Skip to content

Commit d6f0515

Browse files
committed
misc. updates
-- adjust how cable headings are set - now matches moorings, where cable subcomponent headings are absolute in compass headings -- add loads and safety_factors dictionary to Section objects - mooring loads are now stored in Section object dicts insetead of in mooring objects -- mooring.updateTensions() updated to reflect new location of loads -- updated mooring.addMarineGrowth() to properly work with new dd setup -- in Mooring.sections() allow option to input dictionary of subcomponents instead of using i_sec values, useful for cases like marine growth where new sections are added but the design dicitonary property of mooring needs to be the pristine version -- remove cable heading adjustment when updating platform position -- update platform.getWatchCircle to use & store Section loads/safety_factors -- project.loadDesign update how cable headings are loaded in to match moorings -- project.duplicate update to work with new mooring design dictionaries, fairleads, etc -- project.addPlatformMS update to work with new mooring design dicts, fairleads, etc -- project.arrayWatchCircle update to use & store Section loads/safety_factors -- project.unload update to unload fairleads and jtubes -- allow rJtube to be provided in cable description (this is how it was before, then was removed)
1 parent 2c6c796 commit d6f0515

File tree

9 files changed

+514
-335
lines changed

9 files changed

+514
-335
lines changed

famodel/cables/cable.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def reposition(self,headings=None,project=None,rad_fair=[]):
122122
Parameters
123123
----------
124124
headings : list, optional
125-
List of headings associated with the platform/substation attached
125+
List of absolute compass headings associated with the platform/substation attached
126126
to each end of the cable. The default is None.
127127
project : FAModel project object, optional
128128
FAModel project object associated with this cable, only used if
@@ -139,11 +139,11 @@ def reposition(self,headings=None,project=None,rad_fair=[]):
139139
'''
140140
# reposition cable and set end points for the first and last cable sections (or the dynamic cable for a suspended cable)
141141
if not headings:
142-
headingA = self.subcomponents[0].headingA - self.attached_to[0].phi
143-
headingB = self.subcomponents[-1].headingB - self.attached_to[1].phi
142+
headingA = np.pi/2 - self.subcomponents[0].headingA
143+
headingB = np.pi/2 - self.subcomponents[-1].headingB
144144
else:
145-
headingA = headings[0]
146-
headingB = headings[1]
145+
headingA = np.pi/2 - headings[0]
146+
headingB = np.pi/2 - headings[1]
147147

148148
if not isinstance(self.subcomponents[0].attached_to[0], Jtube):
149149
if not rad_fair:
@@ -154,7 +154,6 @@ def reposition(self,headings=None,project=None,rad_fair=[]):
154154
else:
155155
rf = rad_fair[0]
156156

157-
158157
# calculate fairlead locations
159158
Aloc = [self.attached_to[0].r[0]+np.cos(headingA)*rf,
160159
self.attached_to[0].r[1]+np.sin(headingA)*rf,

famodel/cables/dynamic_cable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def __init__(self, id, dd=None, subsystem=None, rA=[0,0,0], rB=[0,0,0],
8080
elif 'headingB' in self.dd:
8181
self.headingB = self.dd['headingB'] # <<< ??
8282
# if there's no headingA, likely a suspended cable - headingA = headingB+180 degrees
83-
self.headingA = self.headingB + np.pi
83+
self.headingA = 0
8484

8585
else:
8686
self.headingA = 0

famodel/helpers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ def MooringProps(mCon, lineTypes, rho_water, g, checkType=1):
657657
# else:
658658
# d_vol = dd['d']
659659
dd['w'] = (dd['m']-np.pi/4*d_vol**2*rho_water)*g
660+
dd['MBL'] = float(dd['MBL'])
660661
if 'mooringFamily' in mCon:
661662
raise Exception('type and moorFamily listed in yaml - use type to reference a mooring type in the mooring_line_types section of the yaml and mooringFamily to obtain mooring properties from MoorProps_default.yaml')
662663
elif 'mooringFamily' in mCon:
@@ -668,6 +669,7 @@ def MooringProps(mCon, lineTypes, rho_water, g, checkType=1):
668669
dd = mProps
669670
dd['name'] = mCon['mooringFamily']
670671
dd['d_nom'] = mCon['d_nom']
672+
dd['MBL'] = float(dd['MBL'])
671673
elif 'type' in mCon and not mCon['type'] in lineTypes:
672674
raise Exception(f'Type {mCon["type"]} provided in mooring_line_config {mCon} is not found in mooring_line_types section. Check for errors.')
673675

@@ -722,6 +724,7 @@ def getMoorings(lcID, lineConfigs, connectorTypes, pfID, proj):
722724
config[-1]['type']['name'] = str(ct)+'_'+str(lt['name'])
723725
# make EA a float not a string
724726
config[-1]['type']['EA'] = float(lt['EA'])
727+
config[-1]['type']['MBL'] = float(lt['MBL'])
725728
# set line length
726729
config[-1]['L'] = lc['length']
727730

@@ -789,6 +792,7 @@ def getMoorings(lcID, lineConfigs, connectorTypes, pfID, proj):
789792
'L': subsub['length']})
790793
# make EA a float not a string
791794
config[-1][-1][-1]['type']['EA'] = float(lt['EA'])
795+
config[-1][-1][-1]['type']['MBL'] = float(lt['MBL'])
792796
sublineLast[ii] = 1
793797
else:
794798
raise Exception(f"keys in subsection line definitions must either be 'type', 'mooringFamily', or 'connectorType'")

famodel/mooring/README.md

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,23 @@ includes a design dictionary with the following details:
2222
- rad_fair : Fairlead radius
2323
- z_fair : Fairlead depth
2424
- span : 2D distance from fairlead to anchor (or fairlead to fairlead)
25-
- Sections: List of line segment detail dictionaries, becomes list of section objects
26-
- type : Line section type dictionary
27-
- d_nom, d_vol : diameter (nominal and volume-equivalent) [m]
28-
- material
29-
- cost [USD]
30-
- m : linear mass [g/m]
31-
- w : weight [N/m]
32-
- MBL : minimum breaking load [N]
33-
- EA : stiffness coefficient [N]
34-
- L : Line section length [m]
25+
- Subcomponents: List of line sections and connectors in order from end A to end B
26+
The values in each subcomponent type vary depending on if it is a section or connector. For sections:
27+
- type : material property dictionary
28+
- d_nom, d_vol : diameter (nominal and volume-equivalent) [m]
29+
- material
30+
- cost [USD]
31+
- m : linear mass [g/m]
32+
- w : weight [N/m]
33+
- MBL : minimum breaking load [N]
34+
- EA : stiffness coefficient [N]
35+
- L : Line section length [m]
36+
For connectors:
37+
- m : mass [kg]
38+
- v : volume [kg/m^3]
39+
- CdA
3540

36-
The Mooring object contains subcomponent objects that represent each component of the full mooring line. Line segments are Section objects, while connectors between segments and at the ends of the lines are Connector objects. These segments alternate.
41+
The Mooring object contains subcomponent objects that represent each component of the full mooring line. Line segments are Section objects, while connectors between segments and at the ends of the lines are Connector objects. These segments alternate, and are listed in the subcomponents section of the design dictionary in order from end A to end B. If there are parallel sections, such as in the case of a bridle, the parallel sections are described with nested lists.
3742

3843
## Mooring Properties
3944
- dd
@@ -55,13 +60,15 @@ The Mooring object contains subcomponent objects that represent each component o
5560
- rA : end A absolute coordinates
5661
- rB : end B absolute coordinates
5762
- heading : compass heading from B to A
63+
- ss : MoorPy subsystem representation of this Mooring, pristine
64+
- ss_mod : modified MoorPy subsystem of thie Mooring, could have marine growth etc
65+
- span : 2D (x-y) distance from fairlead to anchor or fairlead to fairlead. If bridles, the distance is calculated from the midpoint of all bridle fairlead points
5866
- adjuster : custom function that can adjust mooring
5967
- shared : int for anchored line (0), shared line (1) or half of a shared line (2)
6068
- symmetric : boolean for if the mooring line is symmetric shared line
6169
- rho : water density
6270
- g : acceleration due to gravity
6371
- envelopes : 2D motion envelopes, buffers, etc.
64-
- loads : dictionary of loads on the mooring line
6572
- reliability : dictionary of reliability information on the line
6673
- cost : dictionary of line costs
6774
- failure_probability : dictionary of failure probabilities
@@ -88,7 +95,7 @@ Set the position of an end of the mooring
8895
Finds the cost based on the MoorPy subsystem cost estimates
8996

9097
### updateTensions
91-
Gets tensions from subsystem and updates the max tensions dictionary if it is larger than a previous tension
98+
Gets tensions from subsystem and updates the max tensions dictionaries of each Section object if it is larger than a previous tension
9299

93100
### createSubsystem
94101

@@ -123,7 +130,7 @@ the following details:
123130
- volume
124131
- CdA
125132

126-
The connector class also contains an xyz location of the connector, and a connector object in MoorPy.
133+
The connector class also contains an xyz location of the connector, and a connector object in MoorPy (mpConn).
127134

128135
## Connector methods
129136

@@ -135,7 +142,11 @@ Create a MoorPy connector object in a MoorPy system. Mass, volume, and CdA are a
135142

136143
The Section class provides a data structure for the mooring line section material and length. The Section class inherits from dict and Edge.
137144

138-
The line material properties (linear mass, material, MBL, Cd, etc) are stored in the type dictionary of the Section class.
145+
The line material properties (linear mass, material, MBL, Cd, etc) are stored in the type dictionary of the Section class. If a moorpy system is developed, the the line object representing this section is listed in the mpLine parameter. Loads are stored in the loads dictionary, and safety factors are stored in the safety_factors dictionary property.
146+
147+
### Section methods
148+
- makeMoorPyLine
149+
Create a moorpy line object in a moorpy system
139150

140151
[Back to Top](#moorings-sections-and-connectors)
141152

famodel/mooring/connector.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def __init__(self,id, r=[0,0,0], **kwargs):
4444
# cost dictionary
4545
self.cost = {}
4646

47+
4748
self.getProps()
4849

4950

@@ -149,6 +150,12 @@ def __init__(self,id, **kwargs):
149150

150151
# MoorPy Line object for the section
151152
self.mpLine = None
153+
154+
# dictionary of loads on section
155+
self.loads = {}
156+
157+
# dictionary of safety factors
158+
self.safety_factors = {}
152159

153160

154161
def makeMoorPyLine(self, ms):

famodel/mooring/mooring.py

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def reposition(self, r_center=None, heading=None, project=None,
274274
self.heading = heading
275275
else:
276276
self.heading = np.degrees(heading)
277-
#breakpoint()
277+
278278
phi = np.radians(90-self.heading) # heading in x-y radian convention [rad] (CONVERTS FROM COMPASS HEADINGS!)
279279
# heading 2D unit vector
280280
u = np.array([np.cos(phi), np.sin(phi)])
@@ -450,21 +450,20 @@ def getCost(self,from_ss=True):
450450
# sum up the costs in the dictionary and return
451451
return sum(self.cost.values())
452452

453-
def updateTensions(self):
453+
def updateTensions(self, DAF=1):
454454
''' Gets tensions from subsystem and updates the max tensions dictionary if it is larger than a previous tension
455455
'''
456-
if not 'TAmax' in self.loads:
457-
self.loads['TAmax'] = 0
458-
if not 'TBmax' in self.loads:
459-
self.loads['TBmax'] = 0
460-
# get anchor tensions
461-
if abs(self.ss.TA) > self.loads['TAmax']:
462-
self.loads['TAmax'] = deepcopy(self.ss.TA)
463-
# get TB tensions
464-
if abs(self.ss.TB) > self.loads['TBmax']:
465-
self.loads['TBmax'] = deepcopy(self.ss.TB)
456+
Ts = []
457+
# get tensions for each section
458+
for sec in self.sections():
459+
if not 'Tmax' in sec.loads:
460+
sec.loads['Tmax'] = 0
461+
Tmax = max([abs(sec.mpLine.TA), abs(sec.mpLine.TB)])
462+
if Tmax*DAF > sec.loads['Tmax']:
463+
sec.loads['Tmax'] = deepcopy(Tmax)*DAF
464+
Ts.append(sec.loads['Tmax'])
466465

467-
return(self.loads['TAmax'],self.loads['TBmax'])
466+
return max(Ts)
468467

469468

470469
def createSubsystem(self, case=0, pristine=True, dd=None, ms=None):
@@ -528,6 +527,11 @@ def createSubsystem(self, case=0, pristine=True, dd=None, ms=None):
528527
ss.setEndPosition(self.rA,endB=0)
529528
ss.setEndPosition(self.rB,endB=1)
530529

530+
for i,sec in enumerate(self.sections(dd)):
531+
sec.mpLine = ss.lineList[i]
532+
for i,con in enumerate(self.connectors(dd)):
533+
con.mpConn = ss.pointList[i]
534+
531535
# add in connector info to subsystem points
532536
if case == 0: # has an anchor - need to ignore connection for first point because anchor is a point itself so can't have a point attached to a point
533537
startNum = 1
@@ -609,7 +613,6 @@ def positionSubcomponents(self):
609613
elif isinstance(item, Node) and i > 0 and i < len(self.subcomponents)-1:
610614
r = self.rA + (self.rB-self.rA)*Lsum[j-1]/Lsum[-1]
611615
item.setPosition(r)
612-
print(f'Set position of subcom {i} to {r[0]:5.0f}, {r[1]:5.0f}, {r[2]:5.0f}')
613616

614617

615618

@@ -653,9 +656,6 @@ def positionSubcomponents(self):
653656

654657
# --- Do the positioning ---
655658
Lsum = np.cumsum(np.array(L))
656-
print(f'parallel string ends A and B are at')
657-
print(f'{rA[0]:5.0f}, {rA[1]:5.0f}, {rA[2]:5.0f}')
658-
print(f'{rB[0]:5.0f}, {rB[1]:5.0f}, {rB[2]:5.0f}')
659659

660660
for subitem in parallel:
661661
if isinstance(subitem, Edge):
@@ -666,11 +666,9 @@ def positionSubcomponents(self):
666666
if j > 0 and j < n_serial_nodes-1:
667667
r = rA + (rB-rA)*Lsum[j]/Lsum[-1]
668668
item.setPosition(r)
669-
print(f'Set position of Node {j} to {r[0]:5.0f}, {r[1]:5.0f}, {r[2]:5.0f}')
670669
else:
671670
print('end of parallel')
672671
breakpoint()
673-
print('yep')
674672

675673
def mirror(self,create_subsystem=True):
676674
''' Mirrors a half design dictionary. Useful for symmetrical shared mooring lines where
@@ -1065,9 +1063,9 @@ def addMarineGrowth(self, mgDict, project=None, idx=None):
10651063
nd1 = deepcopy(self.dd)
10661064
nd1['subcomponents'] = [None]*(len(nd)*2+1)
10671065
for i in range(len(nd)):
1068-
nd1['subcomponents'][2*i] = connList[i]
1069-
nd1['subcomponents'][2*i+1] = nd[i]
1070-
nd1['subcomponents'][2*i+2] = connList[i+1]
1066+
nd1['subcomponents'][2*i] = Connector('C'+str(i),**connList[i])
1067+
nd1['subcomponents'][2*i+1] = Section('S'+str(i),**nd[i])
1068+
nd1['subcomponents'][2*i+2] = Connector('C'+str(i),**connList[i+1])
10711069

10721070
# call createSubsystem() to make moorpy subsystem with marine growth
10731071
if self.shared:
@@ -1358,6 +1356,14 @@ def sections(self, dd=None):
13581356
for sub in dd['subcomponents']:
13591357
if 'L' in sub:
13601358
secs.append(sub)
1359+
elif isinstance(sub, list):
1360+
for subsub in sub:
1361+
if isinstance(subsub, list):
1362+
for sss in subsub:
1363+
if 'L' in sss:
1364+
secs.append(sss)
1365+
elif 'L' in sss:
1366+
secs.append(subsub)
13611367
else:
13621368
for i in self.i_sec:
13631369
secs.append(self.getSubcomponent(i))
@@ -1372,8 +1378,16 @@ def connectors(self, dd=None):
13721378
# allow option to input dict of subcomponents and pull sections from that
13731379
if dd:
13741380
for sub in dd['subcomponents']:
1375-
if not 'L' in sub:
1381+
if not 'L' in sub and isinstance(sub, dict):
13761382
conns.append(sub)
1383+
elif isinstance(sub, list):
1384+
for subsub in sub:
1385+
if isinstance(subsub, list):
1386+
for sss in subsub:
1387+
if not 'L' in sss and isinstance(sss, dict):
1388+
conns.append(sss)
1389+
elif not 'L' in sss and isinstance(sss, dict):
1390+
conns.append(subsub)
13771391
else:
13781392
for i in self.i_con:
13791393
conns.append(self.getSubcomponent(i))

0 commit comments

Comments
 (0)