Skip to content

Commit 876b336

Browse files
committed
LineDesign Update:
- Reorganizing the plotOptimization function to separate design variables from constraints and cost function. It also gives units to different variables and constraints. It is also color-referenced. - Adding units dictionary for constraints. - Adding two additional constraints related to the inclination angle of the line.
1 parent 166fa76 commit 876b336

File tree

1 file changed

+88
-22
lines changed

1 file changed

+88
-22
lines changed

famodel/design/LineDesign.py

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,22 @@ def __init__(self, depth, lineProps=None, **kwargs):
156156
Clump weights and buoyancy floats are not specified directly. They are both 'weights' and can have either a postitive or negative value
157157
'''
158158

159-
# first set the weight, length, and diameter lists based on the allVars inputs. Don't worry about design variables yet
159+
# first set the weight, length, and diameter lists based on the allVars inputs. Don't worry about design variables yet. Create the units list too.
160+
160161
if self.shared==1:
161162
if self.span == 0: raise Exception("For shared arrangements, a span must be provided to the Mooring object.")
162163
Ws = self.allVars[0::3].tolist()
163164
else:
164165
self.span = self.allVars[0]*10 - self.rBFair[0] # in tens of meters
165166
Ws = self.allVars[3::3].tolist()
167+
166168
Ls = self.allVars[1::3].tolist()
167169
Ds = self.allVars[2::3].tolist()
168-
170+
171+
unitPattern = ['t', 'm', 'mm']
172+
self.allVarsUnits = [unitPattern[i % 3] for i in range(len(self.allVars))]
173+
if self.shared==0:
174+
self.allVarsUnits[0] = 'm'
169175
# if any of the input lengths are in ratio form, convert them to real value form
170176
# (this can currently only handle 1 ration variable per Mooring)
171177
if len(self.rInds) > 0:
@@ -318,7 +324,7 @@ def __init__(self, depth, lineProps=None, **kwargs):
318324

319325
# fill in the X0 value (initial design variable values) based on provided allVars and Xindices (uses first value if a DV has multiple in allVars)
320326
self.X0 = np.array([self.allVars[self.Xindices.index(i)] for i in range(self.nX)])
321-
327+
self.X0Units = np.array(self.allVarsUnits)[[self.Xindices.index(i) for i in range(self.nX)]] # corresponding units
322328
self.X_denorm = np.ones(self.nX) # normalization factor for design variables
323329
self.obj_denorm = 1.0 # normalization factor for objective function
324330

@@ -340,10 +346,34 @@ def __init__(self, depth, lineProps=None, **kwargs):
340346
"max_sag" : self.con_max_sag, # a maximum for the lowest point's depth at x=x_extr_neg
341347
"max_total_length" : self.con_total_length, # a maximum line length
342348
"min_yaw_stiff" : self.con_yaw_stiffness, # a minimum yaw stiffness for the whole system about the extreme negative position
343-
"max_damage" : self.con_damage, # a maximum fatigue damage for a specified mooring line (scales from provided damage from previous iteration)
344-
"min_tension" : self.con_min_tension # a minimum line tension
349+
"max_damage" : self.con_damage, # a maximum fatigue damage for a specified mooring line (scales from provided damage from previous iteration)
350+
"min_tension" : self.con_min_tension, # a minimum line tension
351+
"min_angle" : self.con_min_angle, # a minimum inclination angle for the line
352+
"max_angle" : self.con_max_angle # a maximum inclination angle for the line
345353
}
346354

355+
# a hard-coded dictionary of the units associated with the constraints
356+
conUnitsDict = {"min_Kx" : "N/m",
357+
"max_offset" : "m",
358+
"min_lay_length" : "m",
359+
"rope_contact" : "m",
360+
"tension_safety_factor" : "-",
361+
"min_sag" : "m",
362+
"max_sag" : "m",
363+
"max_total_length" : "m",
364+
"min_yaw_stiff" : "Nm/deg",
365+
"max_damage" : "-",
366+
"min_tension" : "N",
367+
"min_angle" : "deg",
368+
"max_angle" : "deg"
369+
}
370+
371+
# add units to the constraints dictionary
372+
for con in self.constraints:
373+
if con['name'] in conUnitsDict:
374+
con['unit'] = conUnitsDict[con['name']]
375+
else:
376+
raise Exception(f"The constraint name '{con['name']}' is not recognized.")
347377
# set up list of active constraint functions
348378
self.conList = []
349379
self.convals = np.zeros(len(self.constraints)) # array to hold constraint values
@@ -1288,30 +1318,59 @@ def plotOptimization(self):
12881318
if len(self.log['x']) == 0:
12891319
print("No optimization trajectory saved (log is empty). Nothing to plot.")
12901320
return
1291-
1292-
fig, ax = plt.subplots(len(self.X0)+1+len(self.constraints),1, sharex=True, figsize=[6,8])
1293-
fig.subplots_adjust(left=0.4)
1321+
12941322
Xs = np.array(self.log['x'])
12951323
Fs = np.array(self.log['f'])
12961324
Gs = np.array(self.log['g'])
12971325

1298-
for i in range(len(self.X0)):
1299-
ax[i].plot(Xs[:,i])
1300-
#ax[i].axhline(self.Xmin[i], color=[0.5,0.5,0.5], dashes=[1,1])
1301-
#ax[i].axhline(self.Xmax[i], color=[0.5,0.5,0.5], dashes=[1,1])
1326+
n_dv = len(self.X0)
1327+
n_con = len(self.constraints)
1328+
n_rows = max(n_dv, n_con, 1)
13021329

1303-
ax[len(self.X0)].plot(Fs)
1304-
ax[len(self.X0)].set_ylabel("cost", rotation='horizontal')
1330+
fig, axes = plt.subplots(n_rows, 3, sharex=True, figsize=[12, 3*n_rows])
1331+
fig.subplots_adjust(left=0.1, right=0.95, hspace=0.5, wspace=0.4)
1332+
1333+
if n_rows == 1:
1334+
axes = axes[np.newaxis, :]
13051335

1306-
for i, con in enumerate(self.constraints):
1307-
j = i+1+len(self.X0)
1308-
ax[j].axhline(0, color=[0.5,0.5,0.5])
1309-
ax[j].plot(Gs[:,i])
1310-
ax[j].set_ylabel(f"{con['name']}({con['threshold']})",
1311-
rotation='horizontal', labelpad=80)
1336+
# --- Column 1: Design variables ---
1337+
for i in range(n_dv):
1338+
ax = axes[i, 0]
1339+
ax.plot(Xs[:, i], color='blue')
1340+
ax.set_title(f"d.v.{i+1} [{self.X0Units[i]}]")
1341+
1342+
# turn off unused subplots
1343+
for i in range(n_dv, n_rows):
1344+
axes[i, 0].axis("off")
13121345

1313-
ax[j].set_xlabel("function evaluations")
1314-
1346+
# --- Column 2: Constraints ---
1347+
for i, con in enumerate(self.constraints):
1348+
tol = 0.005 * (max(Gs[:, 0])-min(Gs[:, 0]))
1349+
ax = axes[i, 1]
1350+
ax.axhline(0, color=[0.5,0.5,0.5])
1351+
color = 'green' if Gs[-1, i] >= -tol else 'red'
1352+
ax.plot(Gs[:, i], color=color)
1353+
ax.set_title(f"{con['name']} ({con['threshold']}) [{con['unit']}]")
1354+
1355+
for i in range(n_con, n_rows):
1356+
axes[i, 1].axis("off")
1357+
1358+
# --- Column 3: Cost ---
1359+
ax_cost = axes[0, 2]
1360+
ax_cost.plot(Fs/1e6, color='black')
1361+
ax_cost.set_title('cost [$M]')
1362+
1363+
for i in range(1, n_rows):
1364+
axes[i, 2].axis("off")
1365+
1366+
# x-label
1367+
for i in range(n_rows):
1368+
for j in range(3):
1369+
if axes[i, j].has_data():
1370+
axes[i, j].set_xlabel("function evaluations")
1371+
1372+
plt.tight_layout()
1373+
plt.savefig("/Users/ralkarem/Documents/projects/FADesign/scripts/concepts2/LineDesign_optimization_ex.pdf", dpi=200)
13151374
def plotGA(self):
13161375
'''A function dedicated to plotting relevant GA outputs'''
13171376

@@ -1802,7 +1861,14 @@ def con_max_sag(self, X, index, threshold, display=0):
18021861
a certain maximum depth.'''
18031862
return self.ss.getSag(index) - threshold
18041863

1864+
# ----- angle constraints -----
1865+
def con_min_angle(self, X, index, threshold, display=0):
1866+
'''Ensure the angle of a line section is above a minimum value.'''
1867+
return self.ss.getAng(index) - threshold
18051868

1869+
def con_max_angle(self, X, index, threshold, display=0):
1870+
'''Ensure the angle of a line section is below a maximum value.'''
1871+
return threshold - self.ss.getAng(index)
18061872

18071873
# ----- utility functions -----
18081874

0 commit comments

Comments
 (0)