diff --git a/msgpi/ms/beam.py b/msgpi/ms/beam.py
index bdf24cc..45225a4 100644
--- a/msgpi/ms/beam.py
+++ b/msgpi/ms/beam.py
@@ -213,6 +213,9 @@ def __init__(self):
#: `{sid: BeamProperty object, ...}`
self.sections = {}
+ # {section name: template name, ...}
+ self.section_templates = {}
+
self.frames = {} #: Local frames
self.distrloads = [] #: Distribution loads
self.timefunctions = [] #: Time functions
@@ -258,6 +261,10 @@ def summary(self):
print('\nMember B.C.')
+ print('\nSection templates')
+ for sn, st in self.section_templates.items():
+ print(f'{sn}: {st}')
+
print('\nSectional properties')
for sid, bp in self.sections.items():
print('Section', sid)
@@ -279,28 +286,6 @@ def summary(self):
- def echo(self):
- """Print the beam data.
- """
- print('')
- print('Key Point Coordinates')
- print('='*40)
- for pid, coords in self.points.items():
- print('point {pid:4d}: {xyz[0]:16.6e} {xyz[1]:16.6e} {xyz[2]:16.6e}'.format(pid=pid, xyz=coords))
- print('')
- print('Member Definition')
- print('='*40)
- for mid, bs in self.segments.items():
- print(
- 'member {mid:4d}: {pids[0]:4d} {pids[1]:4d} {cs[0]:4d} {cs[1]:4d} {frm:4d} {ndiv:4d} {curv:4d}'.format(
- mid=mid, pids=bs.points, cs=bs.css, frm=bs.frame_id, ndiv=bs.num_divisions, curv=bs.curv_id
- )
- )
- print('')
-
-
-
-
def printResults(self):
for i, step in enumerate(self.results_steps):
print('step', i+1)
diff --git a/msgpi/ms/beam2.py b/msgpi/ms/beam2.py
deleted file mode 100644
index 0007eaf..0000000
--- a/msgpi/ms/beam2.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import numpy as np
-import msgpi.sg as sg
-
-
-class Beam(object):
- """[summary]
-
- Parameters
- ----------
- object : [type]
- [description]
- """
-
- def __init(self):
- self.name = ''
diff --git a/msgpi/ms/blade.py b/msgpi/ms/blade.py
new file mode 100644
index 0000000..842c9cd
--- /dev/null
+++ b/msgpi/ms/blade.py
@@ -0,0 +1,195 @@
+import numpy as np
+import pprint
+import msgpi.sg as sg
+
+
+class BladeSegment(object):
+ """Class for a blade segment.
+ """
+
+ def __init__(self):
+ #: list of ints: Point labels.
+ #: `[beginning point, ending point]`
+ self.points = []
+ #: list of lists of floats: Coordinates of beginning and ending points.
+ #: `[[x1, x2, x3], [x1, x2, x3]]`
+ self.coords = []
+ #: list of ints: Cross-section labels.
+ #: `[beginning, ending]`
+ self.css = []
+
+ # {local coord: section name, ...}
+ self.sections = {}
+
+ #: float: Rotation around a1.
+ self.rotate_a1 = 0.0
+ #: float: Twist.
+ self.twist = 0.0
+ # self.dihedral = 0.
+ # self.sweep = 0.
+ #: int: Local frame id.
+ self.local_frame_id = 0
+ #: int: Frame id
+ self.frame_id = 0
+ #: int: Curvature id
+ self.curv_id = 0
+
+ #: int: Number of division of the segment.
+ self.num_divisions = 1
+
+ #: dict: Parameter distributions
+ #: `{name: [beginning value, ending value], ...}`
+ self.cs_parameters = {}
+
+ def summary(self):
+ print(' points:', self.points)
+ print(' coords:', self.coords)
+ print(' cs names:', self.css)
+ print(' cs templates:', self.cs_template)
+ print(' cs parameters:', self.cs_parameters)
+
+ def calcLengthSq(self):
+ """Calculate the square of the segment length.
+
+ Returns
+ -------
+ float
+ Squred length of the segment.
+ """
+ return ((np.array(self.coords[0]) - np.array(self.coords[1]))**2).sum()
+
+
+
+
+
+
+
+
+
+class Blade(object):
+ """Class for a rotor blade.
+
+ """
+
+ def __init__(self):
+ #: str: Name of the beam.
+ self.name = ''
+
+ # Design
+
+ #: dict of {int, list of floats}: Key point id and coordinates.
+ #: `{ptid: [x1, x2, x3], ...}`
+ self.points = {}
+
+ #: dict of {int, msgpi.ms.beam.BeamSegment}: Beam segments
+ #: `{bsid: BeamSegment object, ...}`
+ self.segments = {}
+
+ #: dict of {int, msgpi.sg.BeamProperty}: Effective properties of cross-sections.
+ #: `{sid: BeamProperty object, ...}`
+ self.sections = {}
+
+ # {section name: msgpi.sg.CrossSection, ...}
+ self.section_database = {}
+
+ self.frames = {} #: Local frames
+ self.distrloads = [] #: Distribution loads
+ self.timefunctions = [] #: Time functions
+ self.initcurvatures = [] #: Initial curvatures
+
+ self.functions = {} #: Functions
+ self.distributions = {} #: Distributions
+
+
+
+
+ def summary(self):
+ pp = pprint.PrettyPrinter(indent=4, compact=False)
+
+ print('\nAnalysis')
+ print('analysis type:', self.analysis_type)
+ print('max iteration:', self.max_iteration)
+ print('number of steps:', self.num_steps)
+ if self.analysis_type != 0:
+ print('angular velocity:', self.angular_velocity)
+ print('time function:', self.av_tf)
+ print('linear velocity:', self.linear_velocity)
+ print('time function:', self.lv_tf)
+ if self.analysis_type == 3:
+ print('number of eigen results:', self.num_eigens)
+
+ print('\nPoints')
+ # pp.pprint(self.points)
+ for pid, coords in self.points.items():
+ print(f'{pid}: ( {coords[0]} , {coords[1]} , {coords[2]} )')
+
+ print('\nSegments')
+ for k, v in self.segments.items():
+ print('segment', k)
+ v.summary()
+
+ print('\nSection templates')
+ for sn, st in self.section_templates.items():
+ print(f'{sn}: {st}')
+
+ print('\nSectional properties')
+ for sid, bp in self.sections.items():
+ print('Section', sid)
+ print('Compliance')
+ pp.pprint(bp.cmpl_t)
+ if self.analysis_type != 0:
+ print('Mass')
+ pp.pprint(bp.mass)
+ print('')
+
+ print('\nDistributions')
+ pp.pprint(self.distributions)
+
+ print('\nFunctions')
+ # pp.pprint(self.functions)
+ for k, v in self.functions.items():
+ print(k, ':', v)
+
+
+
+
+ def findPtCoordByName(self, name):
+ """Find key point coordinates by point id.
+
+ Parameters
+ ----------
+ name : int
+ Point id.
+
+ Returns
+ -------
+ list of floats
+ Point coordinates.
+ """
+ for i, c in self.points.items():
+ if i == name:
+ return c
+ return None
+
+
+
+
+ def findSectionByName(self, name):
+ """Find sectional properties by section id.
+
+ Parameters
+ ----------
+ name : int
+ Section id.
+
+ Returns
+ -------
+ msgpi.sg.MaterialSection
+ Sectional properties.
+ """
+ for i, s in self.sections.items():
+ if s.name == name:
+ return i
+ return 0
+
+
diff --git a/msgpi/ms/prebeam.py b/msgpi/ms/prebeam.py
index 26a361c..a4a39ef 100644
--- a/msgpi/ms/prebeam.py
+++ b/msgpi/ms/prebeam.py
@@ -582,6 +582,9 @@ def preBeam2(fn_beam):
bs.cs_template.append(fn_cs_template)
bs.css.append(cs_name)
+ if not cs_name in beam.section_templates.keys():
+ beam.section_templates[cs_name] = fn_cs_template
+
# Ending station
xe_stop = xe_sgm.find('end')
pn = xe_stop.find('location').text.strip()
@@ -597,6 +600,10 @@ def preBeam2(fn_beam):
bs.cs_template.append(fn_cs_template)
bs.css.append(cs_name)
+ if not cs_name in beam.section_templates.keys():
+ beam.section_templates[cs_name] = fn_cs_template
+
+
# Cross-section parameters
for xe_param in xe_sgm.findall('parameter'):
name = xe_param.find('name').text.strip()
diff --git a/msgpi/sg.py b/msgpi/sg.py
index 13cf0c2..91a3893 100644
--- a/msgpi/sg.py
+++ b/msgpi/sg.py
@@ -948,61 +948,22 @@ def writeGmshMsh(self, fo, nid_begin=1, eid_begin=1, loc=[0, 0, 0], *args, **kwa
-def calcOffsetBeamProperty(sg, offset_x2, offset_x3):
- sg_off = copy.deepcopy(sg)
- # Offset mass matrix
- mm_o = np.asarray(sg_off.mass_mc)
- if (offset_x2 != sg_off.mass_center[1]) or (offset_x3 != sg_off.mass_center[2]):
- # mm_c = np.asarray(self.mass_mc)
- mu = mm_o[0, 0]
- mi_c = mm_o[3:, 3:]
+class CrossSection(object):
+ """A simple class for cross-sections
- x2 = sg_off.mass_center[1] - offset_x2
- x3 = sg_off.mass_center[2] - offset_x3
- r_tilde = np.array([
- [0, -x3, x2],
- [x3, 0, 0],
- [-x2, 0, 0]
- ])
-
- mm_o[:3, 3:] = mu * r_tilde.T
- mm_o[3:, :3] = mu * r_tilde
-
- # I_o = I_c + m * r_tilde.r_tilde^T
- mm_o[3:, 3:] = mm_o[3:, 3:] + mu * np.dot(r_tilde, r_tilde.T)
- sg_off.mass_origin = mm_o
- sg_off.mass_center[1] -= offset_x2
- sg_off.mass_center[2] -= offset_x3
-
-
- # Offset stiffness and compliance
- trfm_4 = np.eye(4)
- trfm_6 = np.eye(6)
-
- trfm_4[2, 0] = offset_x3
- trfm_4[3, 0] = -offset_x2
-
- trfm_6[4, 0] = offset_x3
- trfm_6[5, 0] = -offset_x2
- trfm_6[3, 1] = -offset_x3
- trfm_6[3, 2] = offset_x2
-
- cmp_4 = np.asarray(sg_off.compliance)
- cmp_6 = np.asarray(sg_off.compliance_refined)
-
- sg_off.compliance = np.dot(trfm_4.T, np.dot(cmp_4, trfm_4))
- sg_off.compliance_refined = np.dot(trfm_6.T, np.dot(cmp_6, trfm_6))
+ """
- sg_off.stiffness = np.linalg.inv(sg_off.compliance)
- sg_off.stiffness_refined = np.linalg.inv(sg_off.compliance_refined)
+ def __init__(self, name):
+ self.name = name
+ self.template = ""
- sg_off.tension_center[1] -= offset_x2
- sg_off.tension_center[2] -= offset_x3
+ self.sg = None
- sg_off.shear_center[1] -= offset_x2
- sg_off.shear_center[2] -= offset_x3
+ self.params = {}
+ self.props = {}
- return sg_off
+ def summary(self):
+ print(f'cross-section: {self.name}')
diff --git a/tests/test_prebeam/test_prebeam_1.py b/tests/test_prebeam/test_prebeam_1.py
new file mode 100644
index 0000000..f797ff1
--- /dev/null
+++ b/tests/test_prebeam/test_prebeam_1.py
@@ -0,0 +1,5 @@
+import msgpi.ms.prebeam as prebeam
+
+beam = prebeam.preBeam2('uh60a_blade.xml')
+
+beam.summary()
diff --git a/tests/test_prebeam/uh60a_blade.xml b/tests/test_prebeam/uh60a_blade.xml
index 8587dfd..9efcc75 100644
--- a/tests/test_prebeam/uh60a_blade.xml
+++ b/tests/test_prebeam/uh60a_blade.xml
@@ -15,8 +15,15 @@
0.9 0 0
+
+
+
p1
@@ -38,6 +45,8 @@
+
+
p2