Skip to content

Commit 3b0e1f0

Browse files
committed
Bug fix famodel_base, fairlead ontology adjusted, add comments
-- fixed bug in famodel_base to ensure bridles at end B are connected in assemble function -- add Node.calculate_r_rel method to determine r_rel of node to edge or other node that may be connected via joined subcomponent/subordinate node --> takes into account r_rel of the subs - helpful for determining end point of bridles - attach method now calls this to determine r_rel of each point on an end when there's multiple points, then calls helpers.calculate_midpoint function to determine the r_rel by averaging the r_rels. In moorings, this updates the rB/rA to be the midpoint of the fairlead locations. -- changed fairlead ontology definition to always have a r_rel, and then optionally have headings apply to that r_rel -- small bug fix helpers function adjustMooring
1 parent 1b93d0d commit 3b0e1f0

File tree

7 files changed

+242
-41
lines changed

7 files changed

+242
-41
lines changed

examples/Inputs/OntologySample600m_shared.yaml

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ array:
103103
data : # ID# ID# ID# [m] [m] [deg]
104104
- [FOWT1, 1, 1, ms3, 0, 0, 180 ] # 2 array, shared moorings
105105
- [FOWT2, 1, 1, ms2, 1600, 0, 0 ]
106-
- [FOWT3, 1, 1, ms1, 0, 1656, 180 ]
107-
- [FOWT4, 1, 1, ms4, 1600, 1656, 180]
106+
- [FOWT3, 1, 1, ms1, 0, 1700.4577, 180 ]
107+
- [FOWT4, 1, 1, ms4, 1600, 1700.4577, 180]
108108
# - [4, 1, 2, ms4, -1200, 0, 0 ]
109109
# - [5, 1, 1, ms5, 0, 0, 0 ]
110110
# - [6, 1, 1, ms6, 1200, 0, 0 ]
@@ -118,7 +118,7 @@ array_mooring:
118118
anchor_keys :
119119
[ID, type, x, y, embedment ]
120120
anchor_data :
121-
- [ Anch1, suction_pile1, -828 , 828 , 2 ]
121+
- [ Anch1, suction_pile1, -829 , 850.22887 , 2 ]
122122
# - [ 2, suction1, -1900 , -1200 , 2 ]
123123
# - [ 3, suction1, -850 , -1806 , 2 ]
124124
# - [ 4, suction1, -850 , 600 , 2 ]
@@ -127,7 +127,7 @@ array_mooring:
127127
line_keys :
128128
[MooringConfigID , endA, endB, fairleadA, fairleadB, lengthAdjust]
129129
line_data :
130-
- [ rope_shared , FOWT1, FOWT2, 3, 3, 0]
130+
- [ rope_shared_bridle , FOWT1, FOWT2, [4,5], [4,5], 0]
131131
- [ rope_1 , Anch1, FOWT1, NONE, 2, 0]
132132
- [ rope_1 , Anch1, FOWT3, NONE, 1, 0]
133133
# - [ shared-2-clump , FOWT 2, FOWT 3, 0, 0, 0]
@@ -1206,8 +1206,7 @@ platforms:
12061206
fairleads :
12071207
# list of fairlead coordinates for the platform relative to platform coordinate and 0-degree heading
12081208
- name: fairlead1
1209-
r: 58
1210-
z: -14
1209+
r_rel: [58, 0, -14] # relative coordinates of fairlead to platform center
12111210
headings: [30, 150, 270] # headings in degrees for the fairlead (if multiple headings, the fairlead will be repeated for each heading)
12121211
- name: fairleads2
12131212
r_rel: [-57.779,-5.055, -14]
@@ -1373,8 +1372,46 @@ mooring_line_configs:
13731372
- type: chain_155mm
13741373
length: 20
13751374
- type: rope # ID of a mooring line section type
1376-
length: 1120 # [m] usntretched length of line section
1377-
adjustable: True # flags that this section could be adjusted to accommodate different spacings...
1375+
length: 500 # [m] usntretched length of line section
1376+
- connectorType: triplate
1377+
- subsections: # double chain section
1378+
- - type: chain_155mm
1379+
length: 120
1380+
- - type: chain_155mm
1381+
length: 120
1382+
- connectorType: triplate
1383+
- type: rope # ID of a mooring line section type
1384+
length: 500 # [m] usntretched length of line section
1385+
- subsections: # bridle sections for end B
1386+
- - type: rope
1387+
length: 50
1388+
- connectorType: shackle
1389+
- - type: rope
1390+
length: 50
1391+
- connectorType: shackle
1392+
1393+
rope_shared_bridle:
1394+
name: shared rope with a bridle on each end
1395+
1396+
span: 1484
1397+
1398+
1399+
sections:
1400+
- subsections: # bridle sections for end B
1401+
- - connectorType: shackle
1402+
- type: rope
1403+
length: 50
1404+
- - connectorType: shackle
1405+
- type: rope
1406+
length: 50
1407+
- type: rope
1408+
length: 100
1409+
- connectorType: clump_weight_80
1410+
- type: rope
1411+
length: 1172
1412+
- connectorType: clump_weight_80
1413+
- type: rope
1414+
length: 100
13781415
- subsections: # bridle sections for end B
13791416
- - type: rope
13801417
length: 50
@@ -1514,6 +1551,11 @@ mooring_connector_types:
15141551
shackle:
15151552
m : 200
15161553
v : .2
1554+
1555+
triplate:
1556+
m : 1000
1557+
v : 0.1
1558+
# note: triplate is a connector that connects three mooring lines together, e.g., for a double chain section
15171559

15181560
# Anchor type properties
15191561
anchor_types:

famodel/cables/dynamic_cable.py

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

8485
else:
8586
self.headingA = 0

famodel/famodel_base.py

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import numpy as np
2-
2+
from famodel.helpers import calc_midpoint
33
'''
44
famodel_base contains base classes that can be used for various classes
55
in the floating array model that relate to entities that act like either
@@ -244,9 +244,19 @@ def attach(self, object, r_rel=[0,0], end=None):
244244
'''
245245
# Make sure it's not already attached (note this doesn't distinguish end A/B)
246246
if object.id in self.attachments:
247-
return # for bridles, the mooring will already be attached to platform
247+
# for bridles, the mooring will already be attached to platform
248248
# for second bridle section
249-
# raise Exception(f"Object {object.id} is already attached to {self.id}")
249+
# need to calculate new r_rel that is average of end points
250+
if isinstance(object, Edge):
251+
# pull out relative dist of each point on end to self
252+
r_rel = self.calculate_r_rel(object,end=end)
253+
self.attachments[object.id]['r_rel'] = r_rel
254+
# update end position
255+
Node.setPosition(self, r=self.r,theta=self.theta)
256+
# don't need to attach, already attached- just return
257+
return
258+
else:
259+
raise Exception(f"Object {object.id} is already attached to {self.id}")
250260

251261

252262
# Attach the object
@@ -432,9 +442,9 @@ def setPosition(self, r, theta=0, force=False):
432442
raise Exception("Can't setPosition of an object that's part of a higher object unless force=True.")
433443

434444
# Store updated position and orientation
435-
if len(r) > len(self.r):
445+
if len(r) > len(self.r): # default r is 2D, but can be adjusted to 3D
436446
self.r = np.array(r)
437-
else:
447+
else: # if just a portion of r is being adjusted, only change up to length of initial r
438448
self.r[:len(r)] = r
439449

440450
self.theta = theta
@@ -478,6 +488,63 @@ def setPosition(self, r, theta=0, force=False):
478488
elif isinstance(att['obj'], Edge):
479489
att['obj'].setEndPosition(r_att, att['end'])
480490

491+
def calculate_r_rel(self,object, end=None):
492+
'''Calculate the relative distance between node and object
493+
based on the combined relative distances of the subordinate/
494+
subcomponent nodes connecting them'''
495+
if isinstance(object,Edge):
496+
# pull out subcomponent(s) attached to self at the correct end
497+
end = endToIndex(end) # find end
498+
subs = object.subcons_A if end==0 else object.subcons_B
499+
500+
# go through all end subcomponents of edge at the correct end
501+
rel_locs = [] # relative location list (in case multiple points at end)
502+
for sub in subs:
503+
# first check if subordinate/subcomponent joined
504+
att = [att for att in sub.attachments.values() if att['obj'].attached_to==self]
505+
if len(att)>0:
506+
# find attachment of sub that is subordinately connected to self (Node)
507+
att = att[0] # just need 1st entry
508+
r_rel_att_self = self.attachments[att['id']]['r_rel']
509+
r_rel_att_sub = att['obj'].attachments[sub.id]['r_rel']
510+
# r_rel of sub to self is r_rel of attachment to self + r_rel of sub to attachment
511+
if len(r_rel_att_self) < 3: # pad as needed
512+
r_rel_att_self = np.hstack([r_rel_att_self,[0]])
513+
if len(r_rel_att_sub) < 3: # pad as needed
514+
r_rel_att_sub = np.hstack([r_rel_att_sub,[0]])
515+
rel_locs.append(r_rel_att_self + r_rel_att_sub)
516+
# otherwise, check if directly connected
517+
elif self.isAttached(object):
518+
# if no subordinate/subcomponent connection, should be
519+
# only 1 attachment point at this end
520+
return(self.attachments[object.id]['r_rel'])
521+
else:
522+
raise Exception(f'Cannot determine how {self.id} and {object.id} are connected')
523+
return calc_midpoint(rel_locs)
524+
elif isinstance(object, Node):
525+
# node to node - check if 2 subordinates connected
526+
att = [att for att in object.attachments.values() if self.isAttached(att['obj'])]
527+
if len(att)>0:
528+
att = att[0] # just need 1st entry
529+
# get relative distance of subordinately attached nodes
530+
r_rel_att_self = self.attachments[att['id']]['r_rel']
531+
r_rel_att_obj = object.attachments[att['id']]['r_rel']
532+
# r_rel of obj to self is r_rel of attachment to self + r_rel of obj to attachment
533+
if len(r_rel_att_self) < 3: # pad as needed
534+
r_rel_att_self = np.hstack(r_rel_att_self,[0])
535+
if len(r_rel_att_obj) < 3: # pad as needed
536+
r_rel_att_sub = np.hstack(r_rel_att_sub,[0])
537+
return(r_rel_att_self + r_rel_att_sub)
538+
# otherwise see if they are directly attached and return r_rel
539+
elif self.isattached(object):
540+
return self.attachments[object.id]['r_rel']
541+
else:
542+
raise Exception(f'Cannot determine how {self.id} and {object.id} are connected')
543+
else:
544+
raise Exception(f'{object} is not a Node or Edge')
545+
546+
547+
481548

482549

483550

@@ -1164,13 +1231,11 @@ def assemble(items):
11641231
return
11651232
'''
11661233
n = len(items)
1167-
11681234
for i in range(n-1):
1169-
11701235
if isinstance(items[i], list):
11711236
for subitem in items[i]: # go through each parallel subitem
1172-
11731237
if isinstance(subitem, list): # if it's a concatenation of multiple things
1238+
11741239
assemble(subitem) # make sure that any sublist is assembled
11751240

11761241
# attach the end objects of the subitem to the nodes before and after
@@ -1202,7 +1267,31 @@ def assemble(items):
12021267

12031268
else:
12041269
raise Exception('sequences is not alternating between nodes and edges')
1205-
1270+
# check if last item in items is a list (if length of items>1)
1271+
# if it is a list, it won't have been attached/assembled previously, so
1272+
# attach and assemble now
1273+
if n-1>0:
1274+
if isinstance(items[i+1], list):
1275+
for subitem in items[i+1]: # go through each parallel subitem
1276+
if isinstance(subitem, list): # if it's a concatenation of multiple things
1277+
assemble(subitem) # make sure that any sublist is assembled
1278+
1279+
# attach the end objects of the subitem to the nodes before and after
1280+
if i > 0 and isinstance(items[i], Node): # attach to previous node
1281+
items[i].attach(subitem[0], end='a')
1282+
if i < n-1 and isinstance(items[i+1], Node): # attach to next node
1283+
items[i+1].attach(subitem[-1], end='b')
1284+
# note: this requires the end objects to be edges
1285+
1286+
elif isinstance(subitem, Edge): # if the subitem is just one edge
1287+
print("THIS CASE SHOULDN'T HAPPEN - the list should be nested more")
1288+
breakpoint()
1289+
if i > 0 and isinstance(items[i], Node): # attach to previous node
1290+
items[i].attach(subitem, end='a')
1291+
if i < n-1 and isinstance(items[i+1], Node): # attach to next node
1292+
items[i+1].attach(subitem, end='b')
1293+
else:
1294+
raise Exception("Unsupported situation ... parallel subitems must be edges or concatenations")
12061295

12071296
def rotationMatrix(x3,x2,x1):
12081297
'''Calculates a rotation matrix based on order-z,y,x instrinsic (tait-bryan?) angles, meaning

famodel/helpers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ def getMoorings(lcID, lineConfigs, connectorTypes, pfID, proj):
696696
697697
'''
698698
# set up dictionary of information on the mooring configurations
699-
dd = {'sections':[],'span':{},'zAnchor':{}}#,'EndPositions':{}}
699+
dd = {'span':{},'zAnchor':{}}#,'EndPositions':{}}
700700
# set up connector dictionary
701701
c_config = []
702702
config = [] # mooring and connector combined configuation list
@@ -1171,7 +1171,8 @@ def eval_func(X, args):
11711171
Xmin=[1], Xmax=[1.1*np.linalg.norm(ss.rB-ss.rA)],
11721172
dX_last=[1], tol=[0.01], maxIter=50, stepfac=4)
11731173
ss.lineList[i_line].L = L_final[0]
1174-
mooring.dd['sections'][i_line]['L'] = L_final[0]
1174+
sec = mooring.getSubcomponent(i_line)
1175+
sec['L'] = L_final[0]
11751176
mooring.dd['span'] = span
11761177
mooring.span = span
11771178

0 commit comments

Comments
 (0)