Skip to content

Commit 8a25a28

Browse files
committed
Mooring.positionSubcomponents and Project.getMoorPyArray progress
Mooring.positionSubcomponents now works, it seems, except for parallel portions still to do. Project.getMoorPyArray now gets through creating the mooring system, but getting error related to lineType entries being strings not numeric.
1 parent 83e4686 commit 8a25a28

File tree

3 files changed

+144
-61
lines changed

3 files changed

+144
-61
lines changed

famodel/famodel_base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,8 @@ def setPosition(self, r, theta=0, force=False):
438438
'''
439439

440440
# Don't allow this if this is part of another object
441-
if self.part_of and not force:
442-
raise Exception("Can't setPosition of an object that's part of a higher object unless force=True.")
441+
if self.attached_to and not force:
442+
raise Exception("Can't setPosition of an object that's attached to a higher object unless force=True.")
443443

444444
# Store updated position and orientation
445445
if len(r) > len(self.r): # default r is 2D, but can be adjusted to 3D
@@ -570,8 +570,8 @@ def __init__(self, id):
570570
self.attached_to = [None, None] # object end [A, B] of this edge is attached to
571571

572572
# End A and B locations
573-
self.rA = [0,0]
574-
self.rB = [0,0]
573+
self.rA = np.zeros(2)
574+
self.rB = np.zeros(2)
575575

576576
# Some attributes related to super-edges used to group things
577577
self.part_of = None # whether this object is part of an Edge group

famodel/mooring/mooring.py

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from moorpy.subsystem import Subsystem
66
from moorpy import helpers
77
from famodel.mooring.connector import Connector, Section
8-
from famodel.famodel_base import Edge
8+
from famodel.famodel_base import Edge, Node
99
from famodel.helpers import calc_midpoint
1010

1111
class Mooring(Edge):
@@ -497,7 +497,7 @@ def createSubsystem(self, case=0, pristine=True, dd=None, ms=None):
497497
# Make Lines
498498
for i in self.i_sec:
499499
sec = self.getSubcomponent(i)
500-
sec.makeMoorPyLine(ms)
500+
sec.makeMoorPyLine(ms) # this also will connect the Lines to Points
501501

502502
"""
503503
n = len(self.subcomponents) # number of serial subcomponent items
@@ -672,42 +672,72 @@ def createSubsystem(self, case=0, pristine=True, dd=None, ms=None):
672672
self.ss_mod = ss
673673
return(self.ss_mod)
674674

675-
"""
675+
676676
def positionSubcomponents(self):
677677
'''Puts any subcomponent connectors/nodes along the mooring in
678678
approximate positions relative to the endpoints based on the
679679
section lengths.'''
680680

681+
print('positionSubcomponents!!!')
682+
681683
# Tabulate the section lengths
682684
L = []
683685

684-
n = len(items)
685-
686-
for i in range(n):
687-
688-
if isinstance(items[i], list):
689-
subL = []
690-
for subitem in items[i]: # go through each parallel subitem
686+
n_serial_nodes = 0 # number of serial nodes, including first and last
691687

692-
if isinstance(subitem, list): # if it's a concatenation of multiple things
693-
688+
# First pass, going through each section in series to figure out lengths
689+
for item in self.subcomponents:
690+
691+
if isinstance(item, list): # indicates there are parallel sections here
692+
pLtot = [] # total length of each parallel string
693+
for j, parallel in enumerate(item): # go through each parallel string
694+
if isinstance(parallel, list): # if it's a concatenation of multiple things
695+
pLtot.append(0)
696+
# go through each item along the parallel path
697+
for subitem in parallel:
698+
if isinstance(subitem, Edge):
699+
pLtot[j] += subitem['L'] # add the L of each edge
694700
else:
695701
raise Exception("Unsupported situation ... parallel subitems must be lists")
696-
697-
elif isinstance(items[i], Node):
698-
pass
699702

700-
elif isinstance(items[i], Edge):
701-
L.append(items[i]['L'])
703+
L.append(min(pLtot)) # save minimum parallel string length
704+
705+
elif isinstance(item, Node):
706+
n_serial_nodes += 1
707+
708+
elif isinstance(item, Edge):
709+
L.append(item['L']) # save length of section
702710

711+
print(f'There are {n_serial_nodes} serial nodes')
712+
713+
# Position nodes along main serial string between rA and rB
714+
Lsum = np.cumsum(np.array(L))
715+
i = 0 # index of node along serial string (at A is 0)
716+
717+
for item in self.subcomponents:
718+
if isinstance(item, list) or isinstance(item, Edge):
719+
i = i+1 # note that we're moving a certain length along the string
720+
print(i)
721+
722+
# if it's a node, but no the first or last one
723+
elif isinstance(item, Node) and i > 0 and i < n_serial_nodes-1:
724+
r = self.rA + (self.rB-self.rA)*Lsum[i]/Lsum[-1]
725+
item.setPosition(r)
726+
print(f'Set position of Node {i} to {r[0]:5.0f}, {r[1]:5.0f}, {r[2]:5.0f}')
703727

704-
Lcsum = np.cumsum(np.array(lengths))
705728

706-
# add the point, initializing linearly between anchor and fairlead/midpoint
707-
self.addPoint(0, rA + (rB-rA)*Lcsum[i]/Lcsum[-1], m=m, v=v, DOFs=[0,2])
708729

709-
# Calculate and set approximate node positions
710-
"""
730+
# Second pass, to position any nodes that are along parallel sections
731+
'''
732+
for i in range(n):
733+
TODO
734+
if isinstance(items[i], list): # indicates there are parallel sections here
735+
subL = []
736+
for subitem in items[i]: # go through each parallel subitem
737+
'''
738+
739+
740+
711741

712742
def mirror(self,create_subsystem=True):
713743
''' Mirrors a half design dictionary. Useful for symmetrical shared mooring lines where

famodel/project.py

Lines changed: 88 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,10 @@ def loadDesign(self, d, raft=True):
554554
else:
555555
moor.attachTo(platform, r_rel=[platform.rFair,0,platform.zFair], end='b')
556556

557-
557+
558+
# Position the subcomponents along the Mooring
559+
moor.positionSubcomponents()
560+
558561
# update counter
559562
mct += 1
560563

@@ -576,10 +579,12 @@ def loadDesign(self, d, raft=True):
576579
raise Exception("Input for end B must match an ID from the array table.")
577580
if any(ids['ID'] == arrayMooring[j]['endB'] for ids in arrayAnchor):
578581
raise Exception(f"input for end B of line_data table row '{j}' in array_mooring must be an ID for a FOWT from the array table. Any anchors should be listed as end A.")
582+
579583
# Make sure no anchor IDs in arrayAnchor table are the same as IDs in array table
580584
for k in range(0,len(arrayInfo)):
581585
if any(ids['ID'] == arrayInfo[k] for ids in arrayAnchor):
582586
raise Exception(f"ID for array table row {k} must be different from any ID in anchor_data table in array_mooring section")
587+
583588
# determine if end A is an anchor or a platform
584589
if any(ids['ID'] == arrayMooring[j]['endA'] for ids in arrayInfo): # shared mooring line (no anchor)
585590
# get ID of platforms connected to line
@@ -624,6 +629,9 @@ def loadDesign(self, d, raft=True):
624629
moor.reposition(r_center=[PF[1].r,
625630
PF[0].r],
626631
heading=headingB, project=self)
632+
633+
# Position the subcomponents along the Mooring
634+
moor.positionSubcomponents()
627635

628636
elif any(ids['ID'] == arrayMooring[j]['endA'] for ids in arrayAnchor): # end A is an anchor
629637
# get ID of platform connected to line
@@ -677,7 +685,10 @@ def loadDesign(self, d, raft=True):
677685
zAnew, nAngle = self.getDepthAtLocation(aloc[0],aloc[1], return_n=True)
678686
moor.dd['zAnchor'] = -zAnew
679687
moor.z_anch = -zAnew
680-
moor.rA = [aloc[0],aloc[1],-zAnew]
688+
moor.setEndPosition([aloc[0],aloc[1],-zAnew], 0)
689+
690+
# Position the subcomponents along the Mooring
691+
moor.positionSubcomponents()
681692

682693
# # update anchor depth and soils
683694
# self.updateAnchor(anchor, update_loc=False)
@@ -2680,7 +2691,7 @@ def getMoorPyArray(self, plt=0, pristineLines=True, cables=True):
26802691
break
26812692

26822693
# attach rB point to platform
2683-
if mooring.parallels:
2694+
if mooring.parallels: # case with paralles/bridles
26842695

26852696
# Look at end B object(s)
26862697
subcom = mooring.subcomponents[-1]
@@ -2693,26 +2704,28 @@ def getMoorPyArray(self, plt=0, pristineLines=True, cables=True):
26932704
if isinstance(subcom2, Edge):
26942705
r = subcom2.attached_to[1].r # approximate end point...?
26952706
point = self.ms.addPoint(1, r)
2696-
PF.body.attachPoint(len(self.ms.pointList), [r[0]-PF.r[0], r[1]-PF.r[1], r[2]-PF.r[2]])
2707+
PF.body.attachPoint(point.number, r-PF.r)
26972708
point.attachLine(subcom2.mpLine.number, 1) # attach the subcomponent's line object end B
26982709

26992710
elif isinstance(subcom2, Node):
27002711
r = subcom2.r # approximate end point...?
27012712
pnum = subcom2.mpConn.number
2702-
PF.body.attachPoint(pnum, [r[0]-PF.r[0], r[1]-PF.r[1], r[2]-PF.r[2]])
2713+
PF.body.attachPoint(pnum, r-PF.r)
27032714

27042715
elif isinstance(subcom, Edge):
27052716
r = subcom.attached_to[1].r # approximate end point...?
27062717
point = self.ms.addPoint(1, r)
2707-
PF.body.attachPoint(len(self.ms.pointList), [r[0]-PF.r[0], r[1]-PF.r[1], r[2]-PF.r[2]])
2718+
PF.body.attachPoint(point.number, r-PF.r)
27082719
point.attachLine(subcom.mpLine.number, 1) # attach the subcomponent's line object end B
27092720

27102721
elif isinstance(subcom, Node):
27112722
r = subcom.r # approximate end point...?
27122723
pnum = subcom.mpConn.number
2713-
PF.body.attachPoint(pnum, [r[0]-PF.r[0], r[1]-PF.r[1], r[2]-PF.r[2]])
2724+
PF.body.attachPoint(pnum, r-PF.r)
27142725
# (the section line object(s) should already be attached to this point)
2715-
else:
2726+
2727+
2728+
else: # normal serial/subsystem case
27162729
# add fairlead point
27172730
point = self.ms.addPoint(1,ssloc.rB)
27182731
# add connector info for fairlead point
@@ -2722,52 +2735,92 @@ def getMoorPyArray(self, plt=0, pristineLines=True, cables=True):
27222735
point.CdA = self.ms.lineList[-1].pointList[-1].CdA
27232736
# attach the line to point
27242737
point.attachLine(ssloc.number,1)
2725-
PF.body.attachPoint(len(self.ms.pointList),[ssloc.rB[0]-PF.r[0],ssloc.rB[1]-PF.r[1],ssloc.rB[2]-PF.r[2]]) # attach to fairlead (need to subtract out location of platform from point for subsystem integration to work correctly)
2726-
2738+
PF.body.attachPoint(point.number, ssloc.rB-PF.r) # attach to fairlead (need to subtract out location of platform from point for subsystem integration to work correctly)
27272739

2728-
check = np.ones((len(self.mooringList),1))
27292740

27302741
# Create and attach any shared lines or hybrid lines attached to buoys
2731-
for ii,i in enumerate(self.mooringList): # loop through all lines - ii is index of mooring object in dictionary, i is key (name) of mooring object
2742+
for mkey, mooring in self.mooringList.items(): # loop through all lines
2743+
check = 1 # temporary approach to identify shared lines <<<
27322744
for j in self.anchorList: # j is key (name) of anchor object
2733-
if i in self.anchorList[j].attachments: # check if line has already been put in ms
2734-
check[ii] = 0
2735-
if check[ii] == 1: # mooring object not in any anchor lists
2745+
if mkey in self.anchorList[j].attachments: # check if line has already been put in ms
2746+
check = 0
2747+
if check == 1: # mooring object not in any anchor lists
27362748
# new shared line
27372749
# create subsystem for shared line
2738-
if hasattr(self.mooringList[i],'shared'):
2739-
self.mooringList[i].createSubsystem(case=self.mooringList[i].shared,
2750+
if hasattr(mooring, 'shared'): # <<<
2751+
mooring.createSubsystem(case=mooring.shared,
27402752
pristine=pristineLines, ms=self.ms)
27412753
else:
2742-
self.mooringList[i].createSubsystem(case=1,pristine=pristineLines,
2754+
mooring.createSubsystem(case=1,pristine=pristineLines,
27432755
ms=self.ms) # we doubled all symmetric lines so any shared lines should be case 1
27442756
# set location of subsystem for simpler coding
27452757
if pristineLines:
2746-
ssloc = self.mooringList[i].ss
2758+
ssloc = mooring.ss
27472759
else:
2748-
ssloc = self.mooringList[i].ss_mod
2749-
'''
2750-
# add subsystem as a line in moorpy system
2751-
self.ms.lineList.append(ssloc)
2752-
ssloc.number = len(self.ms.lineList)
2753-
'''
2760+
ssloc = mooring.ss_mod
2761+
2762+
# (ms.lineList.append is now done in Mooring.createSubsystem)
2763+
27542764
# find associated platforms/ buoys
2755-
att = self.mooringList[i].attached_to
2765+
att = mooring.attached_to
27562766

27572767
# connect line ends to the body/buoy
2758-
ends = [ssloc.rA,ssloc.rB]
2759-
for ki in range(0,2):
2760-
if isinstance(att[ki],Platform):
2761-
# add fairlead point A and attach the line to it
2762-
self.ms.addPoint(1,ends[ki])
2763-
self.ms.pointList[-1].attachLine(ssloc.number,ki)
2764-
att[ki].body.attachPoint(len(self.ms.pointList),[ends[ki][0]-att[ki].r[0],ends[ki][1]-att[ki].r[1],ends[ki][2]-att[ki].r[2]])
2768+
for ki in range(0,2): # for each end of the mooring
2769+
if isinstance(att[ki],Platform): # if it's attached to a platform
2770+
2771+
platform = att[ki]
2772+
2773+
if mooring.parallels: # case with paralles/bridles
2774+
2775+
# Look at end object(s)
2776+
subcom = mooring.subcomponents[-ki]
2777+
2778+
if isinstance(subcom, list): # bridle case
2779+
for parallel in subcom:
2780+
subcom2 = parallel[-ki] # end subcomponent of the parallel path
2781+
2782+
# Code repetition for the moment:
2783+
if isinstance(subcom2, Edge):
2784+
r = subcom2.attached_to[ki].r # approximate end point...?
2785+
point = self.ms.addPoint(1, r)
2786+
platform.body.attachPoint(point.number, r-platform.r)
2787+
point.attachLine(subcom2.mpLine.number, ki) # attach the subcomponent's line object end
2788+
2789+
elif isinstance(subcom2, Node):
2790+
r = subcom2.r # approximate end point...?
2791+
pnum = subcom2.mpConn.number
2792+
platform.body.attachPoint(pnum, r-platform.r)
2793+
2794+
elif isinstance(subcom, Edge):
2795+
r = subcom.attached_to[ki].r # approximate end point...?
2796+
point = self.ms.addPoint(1, r)
2797+
platform.body.attachPoint(point.number, r-platform.r)
2798+
point.attachLine(subcom.mpLine.number, ki) # attach the subcomponent's line object end
2799+
2800+
elif isinstance(subcom, Node):
2801+
r = subcom.r # approximate end point...?
2802+
pnum = subcom.mpConn.number
2803+
platform.body.attachPoint(pnum, r-platform.r)
2804+
# (the section line object(s) should already be attached to this point)
2805+
2806+
2807+
else: # normal serial/subsystem case
2808+
2809+
if ki==0:
2810+
rEnd = self.rA
2811+
else:
2812+
rEnd = self.rB
2813+
2814+
# add fairlead point A and attach the line to it
2815+
point = self.ms.addPoint(1, rEnd)
2816+
point.attachLine(ssloc.number, ki)
2817+
platform.body.attachPoint(point.number, rEnd-platform.r)
27652818

27662819
else:
27672820
# this end is unattached
27682821
pass
2769-
2770-
2822+
2823+
27712824
# add in cables if desired
27722825
if cables:
27732826

0 commit comments

Comments
 (0)