Skip to content

Commit 16de612

Browse files
committed
Merge remote-tracking branch 'origin/dev' into irma
2 parents 1f0feb7 + acf5d4b commit 16de612

26 files changed

+1132
-1733
lines changed

examples/example_driver.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from famodel.project import Project
2222
import os
2323
import matplotlib.pyplot as plt
24+
from copy import deepcopy
2425

2526
# set yaml file location and name
2627
dir = os.path.dirname(os.path.realpath(__file__))
@@ -32,7 +33,7 @@
3233
# create project object
3334
project = Project(file=ontology_file, raft=False)
3435
# create moorpy system of the array, include cables in the system
35-
project.getMoorPyArray(cables=True)
36+
project.getMoorPyArray()
3637
# plot in 3d, using moorpy system for the mooring and cable plots
3738
project.plot2d()
3839
project.plot3d()
@@ -102,11 +103,12 @@
102103
#### add marine growth to the mooring lines and cables ####
103104
print('\nAdding marine growth\n')
104105
# marine growth dictionary is read in from YAML, see Ontology ReadMe for description
106+
reg_line_d = deepcopy(project.mooringList['FOWT1a'].ss.lineList[1].type['d_nom'])
105107
project.getMarineGrowth(display=False)
106108
# moorpy system lines with marine growth are stored in the respective objects under ss_mod (pristine lines are stored under ss)
107109
# check the difference in nominal diameter for a given line:
108-
reg_line_d = project.mooringList['FOWT1a'].ss.lineList[1].type['d_nom']
109-
mg_line_d = project.mooringList['FOWT1a'].ss_mod.lineList[-1].type['d_nom']
110+
mg_line_d = project.mooringList['FOWT1a'].ss.lineList[-1].type['d_nom']
111+
110112
print('\nPristine line polyester nominal diameter just below surface: ',reg_line_d)
111113
print('Marine growth line polyester nominal diameter just below surface: ',mg_line_d)
112114

famodel-env.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies:
1616
- shapely
1717
- numpy
1818
- pandas
19+
- geopandas
1920
- pyyaml
2021
- pytest
2122
prefix: C:\ProgramData\anaconda3\envs\famodel-env

famodel/cables/dynamic_cable.py

Lines changed: 70 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ def __init__(self, id, dd=None, subsystem=None, rA=[0,0,0], rB=[0,0,0],
113113
# alternate designs to interpolate between when depth changes
114114
self.alternate_designs = None
115115

116+
# dict of states applied to this Cable object subsystem
117+
self.applied_states = {'marine_growth':None}
118+
116119
# Dictionaries for addition information
117120
self.loads = {}
118121
self.safety_factors = {} # calculated safety factor
@@ -121,6 +124,7 @@ def __init__(self, id, dd=None, subsystem=None, rA=[0,0,0], rB=[0,0,0],
121124
self.cost = {}
122125
self.failure_probability = {}
123126

127+
124128

125129
def makeCableType(self,cabDict):
126130
'''
@@ -437,7 +441,7 @@ def updateTensions(self):
437441

438442
return(self.loads['TAmax'],self.loads['TBmax'])
439443

440-
def createSubsystem(self, case=0,pristine=True,dd=None):
444+
def createSubsystem(self, case=0, dd=None):
441445
''' Creates a subsystem for cable and buoyancy section(s) configuration from the design dictionary
442446
443447
Parameters
@@ -472,12 +476,12 @@ def createSubsystem(self, case=0,pristine=True,dd=None):
472476
# If no buoyancy sections, it's just one section of the bare cable
473477
if not 'buoyancy_sections' in dd or not dd['buoyancy_sections']:
474478
#self.dd['sections'].append({'type':self.cableType,'length':self.L})
475-
types.append(cableType)
479+
types.append(deepcopy(cableType))
476480
lengths.append(self.L)
477481

478482
if 'sections' in dd and dd['sections']: # this will be the case for marine growth or possibly other cases
479483
for i, sec in enumerate(dd['sections']):
480-
types.append(sec['type'])
484+
types.append(deepcopy(sec['type']))
481485
lengths.append(sec['length'])
482486
elif 'buoyancy_sections' in dd:
483487
# Parse buoyancy sections to compute their properties and all lengths
@@ -609,35 +613,34 @@ def createSubsystem(self, case=0,pristine=True,dd=None):
609613

610614

611615
# save it in the object
612-
if pristine:
613-
self.ss = ss
614-
return(self.ss)
615-
else:
616-
self.ss_mod = ss
617-
return(self.ss_mod)
616+
self.ss = ss
617+
return(self.ss)
618618

619-
def addMarineGrowth(self, mgDict,updateDepths=False,tol=2):
619+
def addMarineGrowth(self, mgDict, buoy_mg,
620+
updateDepths=False, tol=2,
621+
starting_ss=None, display=False):
620622
'''Creates a new design dictionary (does not overwrite old one) to account for marine
621623
growth on the subystem, then calls createSubsystem() to recreate the cable
622624
623625
Parameters
624626
----------
625-
mgDict : dictionary
627+
mgDict : list, optional
626628
Provides marine growth thicknesses and the associated depth ranges
627-
{
628-
th : list with 3 values in each entry - thickness, range lower z-cutoff, range higher z-cutoff [m]
629-
*In order from sea floor to surface*
630-
example, if depth is 200 m: - [0.00,-200,-100]
631-
- [0.05,-100,-80]
632-
- [0.10,-80,-40]
633-
- [0.20,-40,0]
634-
buoy_th : list of thicknesses associated with buoyancy sections. This is used to simplify the marine growth modeling on buoys.
635-
* In order of sections from end A to end B (also the order of sections listed in buoyancy_sections list in the dd)
636-
example, if 3 buoyancy sections: - 0.1
637-
- 0.05
638-
- 0.1
639-
rho : list of densities for each thickness, or one density for all thicknesses, [kg/m^3] (optional - default is 1325 kg/m^3)
640-
}
629+
Default is None, which triggers the use of the marine growth dictionary saved in the project class
630+
'density' entry is optional. If no 'density' entry is created in the dictionary, addMarineGrowth defaults to 1325 kg/m^3
631+
*In order from sea floor to surface*
632+
example, if depth is 200 m: - {'thickness':0.00,'lowerRange':-200,'upperRange':-100, 'density':1320}
633+
- {'thickness':0.05,'lowerRange':-100,'upperRange':-80, 'density':1325}
634+
- {'thickness':0.1,'lowerRange':-80,'upperRange':0, 'density':1325}
635+
636+
buoy_mg: list, optional
637+
Provides marine growth thicknesses for buoyancy sections of cables, irrespective of depth.
638+
This is used to simplify the marine growth modeling on buoys.
639+
* In order of sections from end A to end B (also the order of sections listed in buoyancy_sections list in the dd)
640+
example, if 3 buoyancy sections: - 0.1
641+
- 0.05
642+
- 0.1
643+
641644
Returns
642645
-------
643646
changePoints : list
@@ -646,12 +649,11 @@ def addMarineGrowth(self, mgDict,updateDepths=False,tol=2):
646649
List of cutoff depths the changePoints should be located at
647650
648651
'''
649-
def getMG(mgDict):
652+
def getMG(mgDict, buoy_mg, oldLine=None):
650653
# create a reference subsystem if it doesn't already exist
651-
if not self.ss:
652-
self.createSubsystem(pristine=1)
653-
# set location of reference subsystem
654-
oldLine = self.ss
654+
if not oldLine:
655+
oldLine = self.createSubsystem(pristine=1)
656+
655657
# set up variables
656658
LTypes = [] # list of line types for new lines (types listed are from reference object)
657659
Lengths = [] # lengths of each section for new line
@@ -699,31 +701,31 @@ def getMG(mgDict):
699701
high = ssLine.rB
700702
flip = 0
701703

702-
th = mgDict['th'] # set location for ease of coding
704+
th = mgDict # set location for ease of coding
703705
# look up what thickness this line section starts at (if lowest point is not on the sea floor, first segment will have a thickness other than the sea floor thickness)
704706
rAth = 0 # exit while loop when we find thickness at low
705707
count1 = 0 # counter
706708
while rAth==0: # and count1 < len(th):
707709
if flip:
708-
if high[2] <= th[count1][2]:
709-
LThick.append(th[count1][0])
710+
if high[2] <= th[count1]['upperRange']:
711+
LThick.append(th[count1]['thickness'])
710712
rAth = 1 # exit while loop
711713
else:
712-
if low[2] <= th[count1][2]:
713-
LThick.append(th[count1][0])
714+
if low[2] <= th[count1]['upperRange']:
715+
LThick.append(th[count1]['thickness'])
714716
rAth = 1 # exit while loop
715717
count1 = count1 + 1 # iterate counter
716718

717719
# determine if this line section will be split
718720
for j in range(0,len(th)): # go through all changeDepths
719721
if flip:
720-
rs = 2
722+
rs = 'upperRange'
721723
else:
722-
rs = 1
724+
rs = 'lowerRange'
723725
if th[j][rs]>low[2] and th[j][rs]<high[2]:
724726
# line section will be split - add line type, mg thickness, and material to list
725727
LTypes.append(ssLine.type['name'])
726-
slthick.append(th[j][0])
728+
slthick.append(th[j]['thickness'])
727729
# Mats.append(ssLine.type['material'])
728730
# add an empty connector object to list for split location
729731
sCount += 1
@@ -771,12 +773,12 @@ def getMG(mgDict):
771773

772774
else:
773775
# this is a buoy section, add the prescribed buoy marine growth thickness
774-
if isinstance(mgDict['buoy_th'],list):
776+
if isinstance(buoy_mg,list):
775777
# add the buoy thickness for this specific buoyancy section
776-
LThick.append(mgDict['buoy_th'][buoyCount])
778+
LThick.append(buoy_mg[buoyCount])
777779
else:
778780
# add the single buoy thickness
779-
LThick.append(mgDict['buoy_th'])
781+
LThick.append(buoy_mg)
780782

781783
if slthick: # add the length of the top line (from last split to upper end of section) if there was a split in the line
782784
slength.append(float(ssLine.L-ln_raw[-1]))
@@ -811,17 +813,13 @@ def getMG(mgDict):
811813
mu_mg = np.zeros((len(LTypes)))
812814
rho_mg = np.ones((len(LTypes)))*1325
813815
# adjust rho value if alternative provided
814-
if 'rho' in mgDict:
815-
if not type(mgDict['rho']) is list:
816-
# just one density given for all marine growth on the line
817-
rho_mg = rho_mg*mgDict['rho']/1325
818-
else: # density given for each thickness of marine growth
819-
for i in range(0,len(rho_mg)):
820-
# look up what thickness number this rho is related to
821-
for j in range(0,len(LThick)):
822-
thind = np.where(th[:][0]==LThick[j])
823-
# assign rho_mg based on the rho_mg of the thickness
824-
rho_mg[i] = mgDict['rho'][thind]
816+
if 'density' in mgDict[0]:
817+
for i in range(0,len(mgDict)):
818+
# look up what thickness number this rho is related to
819+
for j in range(0,len(LThick)):
820+
thind = np.where([th[ii]['thickness']==LThick[j] for ii in range(len(th))])
821+
# assign rho_mg based on the rho_mg of the thickness
822+
rho_mg[i] = mgDict[thind[0][0]]['density']
825823

826824

827825
nd = [] # list of dictionaries for new design dictionary sections part
@@ -943,42 +941,50 @@ def getMG(mgDict):
943941

944942
# call createSubsystem() to make moorpy subsystem with marine growth
945943
if self.shared>0:
946-
self.createSubsystem(case=int(self.shared),dd=nd1,pristine=0)
944+
self.createSubsystem(case=int(self.shared),dd=nd1)
947945
else:
948-
self.createSubsystem(dd=nd1,pristine=0)
946+
self.createSubsystem(dd=nd1)
949947

950948
return(changeDepths,changePoints)
951949

952950
############################################################################################################################
951+
if starting_ss:
952+
ss = deepcopy(starting_ss)
953+
else:
954+
ss = deepcopy(self.ss)
955+
953956
if updateDepths:
954957
mgDict1 = deepcopy(mgDict)
955958
cEq = tol + 1
956959
ct = 0
957960
while(cEq>tol):
958-
changeDepths,changePoints = getMG(mgDict1)
961+
changeDepths,changePoints = getMG(mgDict1, buoy_mg, oldLine=ss)
959962
D = []
960963
for d in range(0,len(changeDepths)):
961-
diff = mgDict['th'][changeDepths[d][0]][changeDepths[d][1]] - self.ss_mod.pointList[changePoints[d]].r[2]
964+
diff = mgDict[changeDepths[d][0]][changeDepths[d][1]] - self.ss.pointList[changePoints[d]].r[2]
962965
D.append(diff)
963966
cEq = np.mean(D)
964967
# adjust depth to change based on difference between actual and desired change depth
965968
if cEq>tol:
966-
mgDict1['th'][0][2] = mgDict1['th'][0][2] + cEq
967-
for j in range(1,len(mgDict['th'])):
968-
for k in range(1,3):
969+
mgDict1[0]['upperRange'] = mgDict1[0]['upperRange'] + cEq
970+
for j in range(1,len(mgDict)):
971+
for k in ['lowerRange','upperRange']:
969972
if ct < 4 and abs(cEq)<12:
970-
mgDict1['th'][j][k] = mgDict1['th'][j][k] + cEq
973+
mgDict1[j][k] = mgDict1[j][k] + cEq
971974
elif (ct >= 4 and ct < 9) or abs(cEq)>=12:
972975
# could be ping-ponging between two different things, try adding half
973-
mgDict1['th'][j][k] = mgDict1['th'][j][k] + 0.5*cEq
974-
print('average difference between expected and actual change depth is: ',cEq)
976+
mgDict1[j][k] = mgDict1[j][k] + 0.5*cEq
977+
if display == True:
978+
print('average difference between expected and actual change depth is: ',cEq)
975979
if ct > 10:
976980
print('Could not meet tolerance in 10 attempts. Exiting loop')
977981
break
978982
ct += 1
979983
else:
980-
changeDepths,changePoints = getMG(mgDict)
981-
return(changeDepths,changePoints)
984+
changeDepths,changePoints = getMG(mgDict, buoy_mg, oldLine=ss)
985+
986+
self.applied_states['marine_growth'] = mgDict
987+
return(changeDepths,changePoints)
982988

983989

984990

famodel/design/LineDesign.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def __init__(self, depth, lineProps=None, **kwargs):
201201

202202
# the sizing function coefficients to use in the design
203203
self.lineProps = loadLineProps(lineProps)
204-
204+
205205
# Build alternating subcomponents list
206206
for i in range(self.nLines):
207207
# Connector at position 2*i (even indices: 0, 2, 4, ...)
@@ -210,7 +210,6 @@ def __init__(self, depth, lineProps=None, **kwargs):
210210

211211
# Initialize connector properties (will be populated below)
212212
dd['subcomponents'][connector_idx] = {'m': 0, 'v': 0, 'CdA': 0}
213-
214213
# Assign section properties
215214
dd['subcomponents'][section_idx]['type'] = getLineProps(Ds[i],
216215
material=lineTypeNames[i], name=i, lineProps=self.lineProps)
@@ -246,7 +245,7 @@ def __init__(self, depth, lineProps=None, **kwargs):
246245
# Call Mooring init function (parent class)
247246

248247

249-
Mooring.__init__(self, dd=dd, rho=rho, g=g, shared=shared)
248+
Mooring.__init__(self, dd=dd, rho=rho, g=g, shared=shared, lineProps=self.lineProps)
250249
# The above will also create Mooring self parameters like self.rad_anch
251250

252251
# Save a copy of the original anchoring radius to use with the
@@ -520,6 +519,9 @@ def updateDesign(self, X, display=0, display2=0, normalized=True):
520519
'''
521520
start_time = time.time()
522521

522+
# reset modifiers to mooring design (corrosion/creep/marine_growth)
523+
self.reset()
524+
523525
# Design vector error checks
524526
if len(X)==0: # if any empty design vector is passed (useful for checking constraints quickly)
525527
return
@@ -606,9 +608,11 @@ def updateDesign(self, X, display=0, display2=0, normalized=True):
606608
name=i, lineProps=self.lineProps)
607609
# use the update method to preserve refs to the original dict - this 'points'/connects to the subsystem object too!
608610
self.dd['subcomponents'][2*i+1]['type'].update(lineType)
609-
611+
# update the ss as well
612+
self.ss.lineList[i].type.update(lineType)
613+
610614
# apply corrosion to the mooring's MBL dictionary (which gets references in the getTenSF constraint in subsystem)
611-
self.addCorrosion(self.lineProps, corrosion_mm=self.corrosion_mm)
615+
self.setCorrosion(corrosion_mm=self.corrosion_mm)
612616

613617
# update the intermediate points if they have any weight or buoyancy
614618
for i in range(self.nLines-1):

famodel/design/layout_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
from famodel.mooring.mooring import Mooring
12-
from famodel.seabed.seabed_tools import getDepthFromBathymetry
12+
from famodel.seabed_tools import getDepthFromBathymetry
1313
from famodel.project import Project
1414
from famodel.design.fadsolvers import dsolve2
1515

0 commit comments

Comments
 (0)