Skip to content

Commit ef1be13

Browse files
committed
minor marine growth bug fix, clean up __init__ methods
-- marine growth getMoorPyArray(pristine=False) bug fix -- marine growth now unloads to yaml -- clean up __init__ methods to remove unneeded inputs -- other various small changes as recommended by Jun Tanemoto's FAModel code review (thanks Jun!!)
1 parent 892a992 commit ef1be13

File tree

5 files changed

+66
-63
lines changed

5 files changed

+66
-63
lines changed

famodel/cables/dynamic_cable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, id, dd=None, subsystem=None, rA=[0,0,0], rB=[0,0,0],
2323
rad_anch=None, rad_fair=5, z_anch=-100, z_fair=-14,
2424
rho=1025, g=9.81,span=2000,length=2200,A=None,
2525
zJTube=-30,voltage=66,powerRating=None,cable_type=None,
26-
headingA=None,headingB=None,buoyancy_sections=None,shared=0,**kwargs):
26+
headingA=None,headingB=None,shared=0,**kwargs):
2727
'''
2828
Parameters
2929
----------

famodel/cables/static_cable.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@ class StaticCable(Edge):
1717
seabed.
1818
'''
1919

20-
def __init__(self, id, dd=None, subsystem=None, anchor=None, rA=[0,0,0], rB=[0,0,0],
21-
rad_anch=500, rad_fair=58, z_anch=-100, z_fair=-14,
22-
rho=1025, g=9.81, L=2000,A=0,conductorSize=None,
23-
type='static',voltage=66,powerRating=None,cable_type=None,routing=[],
24-
burial=None,zAnchor=None,**kwargs):
20+
def __init__(self, id, dd=None, rA=[0,0,0], rB=[0,0,0],
21+
rho=1025, g=9.81, routing=[],
22+
burial=None, **kwargs):
2523
'''
2624
Parameters
2725
----------
@@ -39,7 +37,7 @@ def __init__(self, id, dd=None, subsystem=None, anchor=None, rA=[0,0,0], rB=[0,0
3937
self.cableType = self.makeCableType(self.dd['cable_type']) # Process/check it into a new dict
4038

4139
# cable length
42-
self.getLength
40+
self.getLength()
4341

4442
# end point absolute coordinates, to be set later
4543
self.rA = rA

famodel/helpers.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,14 @@ def adjustCable(cc,project,na=None,nb=None,routeAdjustLength=500,rad_fair=None):
139139
hA = np.radians(90) - np.arctan2((cc.subcomponents[0].rB[0]-cc.subcomponents[0].rA[0]),(cc.subcomponents[0].rB[1]-cc.subcomponents[0].rA[1]))
140140
else:
141141
hA = np.radians(na) #headingA
142-
cx[0] = [cc.attached_to[0].r[0]+500*np.cos(np.radians(na))]
143-
cy[0] = [cc.attached_to[0].r[1]+500*np.sin(np.radians(na))]
142+
cx[0] = [cc.attached_to[0].r[0]+routeAdjustLength*np.cos(np.radians(na))]
143+
cy[0] = [cc.attached_to[0].r[1]+routeAdjustLength*np.sin(np.radians(na))]
144144
if nb==None:
145145
hB = np.radians(90) - np.arctan2((cc.subcomponents[-1].rA[0]-cc.subcomponents[-1].rB[0]),(cc.subcomponents[-1].rA[1]-cc.subcomponents[-1].rB[1]))
146146
else:
147147
hB = np.radians(nb)
148-
cx[-1] = [cc.attached_to[1].r[0]+500*np.cos(np.radians(nb))]
149-
cy[-1] = [cc.attached_to[1].r[1]+500*np.sin(np.radians(nb))]
148+
cx[-1] = [cc.attached_to[1].r[0]+routeAdjustLength*np.cos(np.radians(nb))]
149+
cy[-1] = [cc.attached_to[1].r[1]+routeAdjustLength*np.sin(np.radians(nb))]
150150
cc.reposition(project=project,headings=[hA,hB],rad_fair=rad_fair)
151151

152152
# find cable(s) associated with specific platform(s) xy coordinates
@@ -251,6 +251,8 @@ def head_adjust(att,heading,rad_buff=np.radians(30),endA_dir=1, adj_dir=1):
251251
'''
252252
if heading<0:
253253
headnew = np.pi*2 + heading
254+
elif heading>2*np.pi:
255+
heading - 2*np.pi
254256
else:
255257
headnew = heading
256258
attheadings = [] # complete list of mooring headings to avoid, from all platforms

famodel/mooring/mooring.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ def ddSave(self):
806806
return self.dd
807807
"""
808808

809-
def addMarineGrowth(self, mgDict, project=None, idx=None):
809+
def addMarineGrowth(self, mgDict):
810810
'''Re-creates sections part of design dictionary to account for marine
811811
growth on the subystem, then calls createSubsystem() to recreate the line
812812
@@ -823,17 +823,6 @@ def addMarineGrowth(self, mgDict, project=None, idx=None):
823823
- [0.20,-40,0]
824824
rho : list of densities for each thickness, or one density for all thicknesses, [kg/m^3] (optional - default is 1325 kg/m^3)
825825
}
826-
project : object, optional
827-
A FAModel project object, with the mooringListPristine used as the basis
828-
to build the marine growth model, necessary if the addMarineGrowth method
829-
will be called in a loop (or even just multiple times) to improve accuracy
830-
of change depths, which may decrease significantly after solveEquilibrium()
831-
for the moorpy model. The default is None.
832-
idx : tuple, optional
833-
A key for the pristineMooringList in the project object that is associated
834-
with this mooring object. Since the pristineMooringList is a deepcopy of the
835-
project mooringList, the mooring objects are not the same and therefore if the
836-
project object is provided in the method call, the index must also be provided.
837826
838827
Returns
839828
-------

famodel/project.py

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def __init__(self, lon=0, lat=0, file=None, depth=202,raft=1):
9797
self.rho_water = 1025 # density of water (default to saltwater) [kg/m^3]
9898
self.rho_air = 1.225 # density of air [kg/m^3]
9999
self.mu_air = 1.81e-5 # dynamic viscosity of air [Pa*s]
100+
self.marine_growth = None
100101

101102
# Project boundary (vertical stack of x,y coordinate pairs [m])
102103
self.boundary = np.zeros([0,2])
@@ -110,10 +111,9 @@ def __init__(self, lon=0, lat=0, file=None, depth=202,raft=1):
110111
self.depth = depth
111112
self.grid_depth = np.array([[self.depth]]) # depth at each grid point [iy, ix]
112113

113-
self.seabed_type = 'clay' # switch of which soil property set to use ('clay', 'sand', or 'rock')
114-
115114
# soil parameters at each grid point
116115
self.soilProps = {}
116+
self.soil_names = []
117117
self.soil_mode = 0 # soil/anchor model level to use (0: none; 1: simple categories; 2: quantitative)
118118
self.soil_class = [["none"]] # soil classification name ('clay', 'sand', or 'rock' with optional modifiers)
119119
self.soil_gamma = np.zeros((1,1)) # soil effective unit weight [kPa] (all soils)
@@ -1858,18 +1858,19 @@ def addAnchor(self, id=None, dd=None, design=None, cost=0, atype=None, platform=
18581858
return(anchor)
18591859

18601860
def addTurbine(self,id=None, typeID=None, platform=None, turbine_dd={}):
1861+
18611862
if typeID == None:
18621863
typeID = len(self.turbineTypes)
18631864
if id==None:
18641865
id = 'T'+str(typeID)+'_'+str(len(self.turbineList))
18651866

18661867
if turbine_dd and 'blade' in turbine_dd:
1867-
blade_diameter = turbine_dd['blade']['Rtip']*2
1868+
rotor_diameter = turbine_dd['blade']['Rtip']*2
18681869
self.turbineTypes.append(turbine_dd)
18691870
else:
18701871
blade_diameter = 0
18711872

1872-
self.turbineList[id] = Turbine(turbine_dd,id,D=blade_diameter)
1873+
self.turbineList[id] = Turbine(turbine_dd,id,D=rotor_diameter)
18731874
self.turbineList[id].dd['type'] = typeID
18741875
if platform != None:
18751876
platform.attach(self.turbineList[id])
@@ -2184,7 +2185,7 @@ def plot2d(self, ax=None, plot_seabed=False, plot_soil=False,
21842185
depth_vmin = kwargs.get('depth_vmin', None)
21852186
depth_vmax = kwargs.get('depth_vmax', None)
21862187
bath_levels = kwargs.get('bath_levels', None)
2187-
show_legend = kwargs.get('show_legend', True)
2188+
plot_legend = kwargs.get('plot_legend', True)
21882189
legend_x = kwargs.get('legend_x', 0.5)
21892190
legend_y = kwargs.get('legend_y', -0.1)
21902191

@@ -2302,16 +2303,21 @@ def plot2d(self, ax=None, plot_seabed=False, plot_soil=False,
23022303
line.type['material'][1:]+' Mooring')
23032304

23042305
if mooring.ss:
2305-
mooring.ss.drawLine2d(0, ax, color="self", endpoints=False,
2306-
Xuvec=[1,0,0], Yuvec=[0,1,0], line_depth_settings=line_depth_settings, label=labs)
2306+
mooring.ss.drawLine2d(0, ax, color="self",
2307+
plot_endpoints=False,
2308+
Xuvec=[1,0,0], Yuvec=[0,1,0],
2309+
line_depth_settings=line_depth_settings,
2310+
label=labs)
23072311
elif mooring.parallels:
23082312
for i,line in enumerate(lineList):
23092313
line.drawLine2d(0, ax, color="self",
2310-
Xuvec=[1,0,0], Yuvec=[0,1,0], label=labs[i])
2314+
Xuvec=[1,0,0], Yuvec=[0,1,0],
2315+
label=labs[i])
23112316

23122317
else: # simple line plot
23132318
ax.plot([mooring.rA[0], mooring.rB[0]],
2314-
[mooring.rA[1], mooring.rB[1]], 'k', lw=0.5, label='Mooring Line')
2319+
[mooring.rA[1], mooring.rB[1]], 'k', lw=0.5,
2320+
label='Mooring Line')
23152321

23162322
# ---- Add colorbar for line depth ----
23172323
if line_depth_settings is not None and not bare:
@@ -2351,23 +2357,23 @@ def plot2d(self, ax=None, plot_seabed=False, plot_soil=False,
23512357
# has routing - first plot rA to sub.coordinate[0] connection
23522358
ax.plot([sub.rA[0],sub.x[0]],
23532359
[sub.rA[1],sub.y[0]],':',color = Ccable,
2354-
lw=1.2,label='Static Cable '+str(cableSize)+' mm$^{2}$')
2360+
lw=1.2,label=f'Static Cable {cableSize} mm$^{2}$')
23552361
# now plot route
23562362
if len(sub.x) > 1:
23572363
for i in range(1,len(sub.x)):
23582364
ax.plot([sub.x[i-1],sub.x[i]],
23592365
[sub.y[i-1],sub.y[i]],
23602366
':', color=Ccable, lw=1.2,
2361-
label='Static Cable '+str(cableSize)+' mm$^{2}$')
2367+
label=f'Static Cable {cableSize} mm$^{2}$')
23622368
# finally plot sub.coordinates[-1] to rB connection
23632369
ax.plot([sub.x[-1],sub.rB[0]],
23642370
[sub.y[-1],sub.rB[1]],':',color=Ccable,
2365-
lw=1.2,label='Static Cable '+str(cableSize)+' mm$^{2}$')
2371+
lw=1.2,label=f'Static Cable {cableSize} mm$^{2}$')
23662372
else:
23672373
# if not routing just do simple line plot
23682374
ax.plot([sub.rA[0],sub.rB[0]],
23692375
[sub.rA[1], sub.rB[1]],':',color = Ccable, lw=1.2,
2370-
label='Static Cable '+str(cableSize)+' mm$^{2}$')
2376+
label=f'Static Cable {cableSize} mm$^{2}$')
23712377

23722378
# if cable_labels:
23732379
# x = np.mean([sub.rA[0],sub.rB[0]])
@@ -2380,7 +2386,7 @@ def plot2d(self, ax=None, plot_seabed=False, plot_soil=False,
23802386
elif isinstance(sub,DynamicCable):
23812387
ax.plot([sub.rA[0],sub.rB[0]],
23822388
[sub.rA[1], sub.rB[1]],color = Ccable, lw=1.2,
2383-
label='Dynamic Cable '+str(cableSize)+' mm$^{2}$')
2389+
label=f'Dynamic Cable {cableSize} mm$^{2}$')
23842390

23852391
if cable_labels:
23862392
x = np.mean([sub.rA[0],sub.rB[0]])
@@ -2421,10 +2427,17 @@ def plot2d(self, ax=None, plot_seabed=False, plot_soil=False,
24212427
labels += [h.get_label() for h in soil_handles]
24222428
by_label = dict(zip(labels, handles)) # Removing duplicate labels
24232429

2424-
if show_legend:
2430+
if plot_legend:
24252431
ax.legend(by_label.values(), by_label.keys(),loc='upper center',bbox_to_anchor=(legend_x, legend_y), fancybox=True, ncol=4)
24262432
if save:
2427-
plt.savefig('2dfarm.png', dpi=600, bbox_inches='tight') # Adjust the dpi as needed
2433+
counter = 1
2434+
output_filename = f'2dfarm_{counter}.png'
2435+
while os.path.exists(output_filename):
2436+
counter += 1
2437+
output_filename = f'2dfarm_{counter}.png'
2438+
2439+
# Increase the resolution when saving the plot
2440+
plt.savefig(output_filename, dpi=600, bbox_inches='tight') # Adjust the dpi as needed
24282441

24292442
# TODO - add ability to plot from RAFT FOWT
24302443
if return_contour:
@@ -2483,21 +2496,8 @@ def plot3d(self, ax=None, figsize=(10,8), plot_fowt=False, save=False,
24832496
args_bath = {'cmap': cmap, 'vmin':min([min(x) for x in -self.grid_depth]),
24842497
'vmax': vmax}
24852498

2486-
# >>> below code sections seem to do unnecessary interpolation and regridding... >>>
24872499
if boundary_only: # if you only want to plot the bathymetry that's underneath the boundary, rather than the whole file
2488-
boundary = np.vstack([self.boundary, self.boundary[0,:]])
2489-
xs = np.linspace(min(boundary[:,0]),max(boundary[:,0]),len(boundary[:,0]))
2490-
ys = np.linspace(min(boundary[:,1]),max(boundary[:,1]),len(boundary[:,1]))
2491-
2492-
self.setGrid(xs, ys)
2493-
2494-
# plot the bathymetry in matplotlib using a plot_surface
2495-
X, Y = np.meshgrid(xs, ys) # 2D mesh of seabed grid
2496-
2497-
plot_depths = np.zeros([len(ys), len(xs)])
2498-
for i in range(len(ys)):
2499-
for j in range(len(xs)):
2500-
plot_depths[i,j], nvec = self.getDepthAtLocation(xs[j], ys[i])
2500+
self.trimGrids()
25012501

25022502
else:
25032503
xs = np.linspace(min(self.grid_x),max(self.grid_x),len(self.grid_x))
@@ -2775,9 +2775,12 @@ def getMoorPyArray(self, plt=0, pristineLines=True, cables=True):
27752775
# set location of subsystem for simpler coding
27762776
ssloc = mooring.ss
27772777
else:
2778-
mooring.createSubsystem(pristine=False, ms=self.ms)
2778+
# if modified , assume the ss_mod is already generated
27792779
# set location of subsystem for simpler coding
27802780
ssloc = mooring.ss_mod
2781+
# assign ss_mod in to ms
2782+
self.ms.lineList.append(ssloc)
2783+
ssloc.number = len(self.ms.lineList)
27812784

27822785
# (ms.lineList.append is now done in Mooring.createSubsystem)
27832786

@@ -2889,19 +2892,19 @@ def getMoorPyArray(self, plt=0, pristineLines=True, cables=True):
28892892
if check == 1: # mooring object not in any anchor lists
28902893
# new shared line
28912894
# create subsystem for shared line
2892-
if hasattr(mooring, 'shared'): # <<<
2893-
mooring.createSubsystem(case=mooring.shared,
2894-
pristine=pristineLines, ms=self.ms)
2895-
else:
2896-
mooring.createSubsystem(case=1,pristine=pristineLines,
2897-
ms=self.ms) # we doubled all symmetric lines so any shared lines should be case 1
2895+
28982896
# set location of subsystem for simpler coding
28992897
if pristineLines:
2898+
mooring.createSubsystem(case=mooring.shared,
2899+
pristine=pristineLines, ms=self.ms)
29002900
ssloc = mooring.ss
29012901
else:
2902+
# modified line should already exist - just attach it
29022903
ssloc = mooring.ss_mod
2904+
self.ms.lineList.append(ssloc)
2905+
ssloc.number = len(self.ms.lineList)
29032906

2904-
# (ms.lineList.append is now done in Mooring.createSubsystem)
2907+
# (ms.lineList.append is now done in Mooring.createSubsystem unless not pristine)
29052908

29062909
# find associated platforms/ buoys
29072910
att = mooring.attached_to
@@ -3432,7 +3435,7 @@ def getMarineGrowth(self,mgDict_start=None,lines='all',tol=2,display=False):
34323435
for j in range(0,len(cP)):
34333436
cEq.append(mgDict_start['th'][cD[j][0]][cD[j][1]] - self.cableList[i[0]].subcomponents[i[1]].ss_mod.pointList[cP[j]].r[2])
34343437
else:
3435-
cD,cP = self.mooringList[i].addMarineGrowth(mgDict,project=self,idx=i)
3438+
cD,cP = self.mooringList[i].addMarineGrowth(mgDict)
34363439
for j in range(0,len(cP)):
34373440
cEq.append(mgDict_start['th'][cD[j][0]][cD[j][1]] - self.mooringList[i].ss_mod.pointList[cP[j]].r[2])
34383441
# adjust depth to change based on difference between actual and desired change depth
@@ -4532,6 +4535,14 @@ def unload(self,file='project.yaml'):
45324535
site['bathymetry'] = {'x':[float(x) for x in self.grid_x],'y':[float(y) for y in self.grid_y],'depths':[[float(y) for y in x] for x in self.grid_depth]}
45334536
if len(self.boundary)>0:
45344537
site['boundaries'] = {'x_y':[[float(y) for y in x] for x in self.boundary]}
4538+
4539+
if self.marine_growth:
4540+
site['marine_growth'] = {
4541+
'keys':['thickness', 'lowerRange', 'upperRange', 'density'][:len(self.marine_growth['th'])],
4542+
'data':[v for v in self.marine_growth['th']]
4543+
}
4544+
if 'buoy_th' in self.marine_growth:
4545+
site['marine_growth']['buoys'] = [x for x in self.marine_growth['buoy_th']]
45354546
site['general'] = {'water_depth':float(self.depth),'rho_air':float(self.rho_air),
45364547
'rho_water':float(self.rho_water),'mu_air':float(self.mu_air)}
45374548

@@ -4870,7 +4881,10 @@ def extractFarmInfo(self, cmax=5, fmax=10/6, Cmeander=1.9):
48704881
phi_deg = (phi_deg + 180) % 360 - 180 # Shift range to -180 to 180
48714882
for att in pf.attachments.values():
48724883
if isinstance(att['obj'],Turbine):
4873-
D = 240 # att['obj'].D (assuming 15MW)
4884+
if hasattr(att['obj'], 'D'):
4885+
D = att['obj'].D
4886+
else:
4887+
D = 242
48744888
zhub = att['obj'].dd['hHub']
48754889

48764890
wts[i] = {

0 commit comments

Comments
 (0)