Skip to content

Commit d50c1c2

Browse files
committed
Anchor.getSize updates to get the design optimization working for SP/DG
- Small fix in project.addMooring related to the "id_part" list - Took all the hard-coded print statements in capacity_suction (of anchors_famodel) out as there were so many when running Anchor.getSize and calling getAnchorCapacity each iteration - Anchor.getSize updates to get COBYLA running well for suction piles and D&G piles - - constraint functions need all the args listed out one by one where the objective function only needs an args parameter...not sure why right now...might be a better way to do this - - made sure getAnchorCapacity was run in each constraint function (in case some constraints get turned off for different applications)...running getAnchorCapacity is very quick for suction piles (but a little slow for D&G piles) - - changed the conval for the unity check constraint to make sure the unity check was less than 1 and not greater than 1 - - added a constraint for designing D&G anchors based on the lateral and rotational displacements - - added a constraint for the design variable bounds, since COBYLA doesn't work well with bounds - - took out the conFunH and conFunV constraint functions as the unity check constraint appeared to take care of those constraints as well (but this may need to be updated in the future) - Changed inputs to getFS to the input loads value, rather than using the self.loads value - Noticed that the return of "getLugForces" wasn't returning what the output was (mudloads)
1 parent 12ce2a3 commit d50c1c2

File tree

3 files changed

+65
-28
lines changed

3 files changed

+65
-28
lines changed

famodel/anchors/anchor.py

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ def makeEqual_TaTm(mudloads):
623623
else:
624624
mudloads['method'] = mudloads['method']
625625

626-
return(self.loads)
626+
return mudloads
627627

628628
def getFS(self, loads=None, acceptance_crit=None):
629629
'''
@@ -840,7 +840,12 @@ def getSize(self, geom, geomKeys, geomBounds=None, loads=None, minfs={'Ha':1.6,'
840840
# - - - - Objective and Constraint Functions
841841

842842
# Define the objective function: Minimize weight of anchor (cost is dependent on weight)
843-
def objective(vars,geomKeys, input_loads, fix_zlug):
843+
def objective(vars, args):
844+
845+
geomKeys = args['geomKeys']
846+
input_loads = args['input_loads']
847+
fix_zlug = args['fix_zlug']
848+
844849
newGeom = dict(zip(geomKeys,vars))
845850
self.dd['design'].update(newGeom)
846851
if 'suction' in self.dd['type'] and not fix_zlug:
@@ -851,8 +856,12 @@ def objective(vars,geomKeys, input_loads, fix_zlug):
851856
return(results['Weight'])
852857

853858
# constraint for suction bucket sizing only. May add more constraints for other anchors in the future...
854-
def conFun_LD(vars,LD_con,geomKeys):
855-
newGeom = dict(zip(geomKeys,vars))
859+
def conFun_LD(vars, geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs):
860+
newGeom = dict(zip(geomKeys, vars))
861+
self.dd['design'].update(newGeom)
862+
863+
results = self.getAnchorCapacity(loads=input_loads, plot=False)
864+
856865
convalA = newGeom['L']/newGeom['D'] - LD_con[0]
857866
convalB = LD_con[1] - newGeom['L']/newGeom['D']
858867
conval = min([convalA,convalB])
@@ -863,13 +872,22 @@ def conFun_LD(vars,LD_con,geomKeys):
863872

864873
return(conval)
865874
# constraint to ensure unity check > 1 for suction buckets
866-
def conFun_Suction(vars,input_loads):
867-
results = self.getAnchorCapacity(loads=input_loads,plot=False)
868-
conval = results['UC'] - 1
875+
def conFun_Suction(vars, geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs):
876+
results = self.getAnchorCapacity(loads=input_loads, plot=False)
877+
#conval = results['UC'] - 1
878+
conval = 1 - results['UC']
869879
# convalB = 1 - results['UC']
870880
return(conval)
881+
882+
def conFun_DandG(vars, geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs):
883+
884+
newGeom = dict(zip(geomKeys, vars))
885+
self.dd['design'].update(newGeom)
886+
results = self.getAnchorCapacity(loads=input_loads, plot=False)
887+
888+
return np.array([0.05*newGeom['D'] - results['Lateral displacement'] , 0.25 - results['Rotational displacement']])
871889

872-
def conFunH(vars,input_loads):
890+
def conFunH(vars, geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs):
873891
# if 'suction' in self.dd['type']:
874892
# results = self.getAnchorCapacity(plot=False)
875893
# conval = results['UC'] - 1
@@ -885,8 +903,8 @@ def conFunH(vars,input_loads):
885903
# conval = -1*(1-val/minfs[key])
886904
return(conval)
887905

888-
def conFunV(vars,minfs,input_loads):
889-
FS = self.getFS(input_loads)
906+
def conFunV(vars, geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs):
907+
FS = self.getFS(loads=input_loads)
890908
# special case for DEAs
891909
if minfs['Va'] == 0:
892910
conval = 1
@@ -896,6 +914,20 @@ def conFunV(vars,minfs,input_loads):
896914
# print('FS_V',FS['Va'])
897915
return(conval)
898916

917+
def conBounds(vars, geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs):
918+
919+
newGeom = dict(zip(geomKeys, vars))
920+
self.dd['design'].update(newGeom)
921+
922+
results = self.getAnchorCapacity(loads=input_loads, plot=False)
923+
924+
bound_L_lower = newGeom['L'] - geomBounds[0][0]
925+
bound_L_upper = geomBounds[0][1] - newGeom['L']
926+
bound_D_lower = newGeom['D'] - geomBounds[1][0]
927+
bound_D_upper = geomBounds[1][1] - newGeom['D']
928+
929+
return np.array([bound_L_lower, bound_L_upper, bound_D_lower, bound_D_upper])
930+
899931
# - - - - - Setup & Optimization
900932
from scipy.optimize import minimize
901933
from copy import deepcopy
@@ -940,14 +972,20 @@ def conFunV(vars,minfs,input_loads):
940972
if 'suction' in anchType:
941973
# bounds = [(1, 7), (5, 50),()] # Bounds for D and L
942974
# constraints
943-
constraints = [{'type':'ineq','fun':conFun_LD,'args':(LD_con,geomKeys)},
944-
{'type':'ineq','fun':conFun_Suction,'args':(input_loads,)},
945-
{'type':'ineq','fun':conFunH,'args':(input_loads,)},
946-
{'type':'ineq','fun':conFunV,'args':(minfs,input_loads)}]
975+
976+
constraints = [{'type':'ineq','fun':conFun_LD,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
977+
{'type':'ineq','fun':conFun_Suction,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
978+
#{'type':'ineq','fun':conFunH,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
979+
#{'type':'ineq','fun':conFunV,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
980+
{'type':'ineq','fun':conBounds,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)}]
981+
947982
else:
948983
# bounds = None
949-
constraints = ({'type':'ineq','fun':conFunH,'args':(input_loads,)},
950-
{'type':'ineq','fun':conFunV,'args':(minfs,input_loads)})
984+
constraints = [{'type':'ineq','fun':conFun_LD,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
985+
{'type':'ineq','fun':conFun_DandG,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
986+
#{'type':'ineq','fun':conFunH,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
987+
#{'type':'ineq','fun':conFunV,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)},
988+
{'type':'ineq','fun':conBounds,'args':(geomKeys, input_loads, fix_zlug, LD_con, geomBounds, minfs)}]
951989

952990
# Run the optimization to find sizing that satisfy UC close to 1
953991
print('optimizing anchor size')
@@ -956,11 +994,11 @@ def conFunV(vars,minfs,input_loads):
956994
solution = minimize(objective, initial_guess, args=(geomKeys, input_loads, fix_zlug), method="COBYLA",
957995
constraints=constraints, options={'rhobeg':0.1, 'catol':0.001})
958996
else:
959-
solution = minimize(objective, initial_guess, args=(geomKeys, input_loads, fix_zlug), method="COBYLA",
960-
constraints=constraints, bounds=geomBounds,
997+
solution = minimize(objective, initial_guess, args=dict(geomKeys=geomKeys, input_loads=input_loads, fix_zlug=fix_zlug, LD_con=LD_con, geomBounds=geomBounds, minfs=minfs), method="COBYLA",
998+
constraints=constraints,
961999
options={'rhobeg':0.1, 'catol':0.001})
9621000

963-
FS, acceptance, FSdiff = self.getFS(acceptance_crit=minfs)
1001+
FS, acceptance, FSdiff = self.getFS(loads=input_loads, acceptance_crit=minfs)
9641002

9651003
# adjust starting value if you're far off from the acceptance criteria (in either direction)
9661004
if FSdiff_max:
@@ -994,7 +1032,7 @@ def conFunV(vars,minfs,input_loads):
9941032
constraints=constraints, bounds=geomBounds,
9951033
options={'rhobeg':0.1, 'catol':0.001,'maxiter':400})
9961034
# re-determine FS and diff from minFS
997-
FS, acceptance, FSdiff = self.getFS(acceptance_crit=minfs)
1035+
FS, acceptance, FSdiff = self.getFS(loads=input_loads, acceptance_crit=minfs)
9981036
count += 1
9991037

10001038
# Extract the optimized values of geometry

famodel/anchors/anchors_famodel/capacity_suction.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def calc_delta(Dr_val):
8383
if soil_type == 'clay':
8484
# Definitions for cohesive soils
8585
Nc = min (6.2*(1 + 0.34*np.arctan(lambdap)),9) # End-bearing capacity factor
86-
ez = (Su0*L**2/2 + k*L**3/3)/(Su0*L + k*L**2/2); print(ez)
86+
ez = (Su0*L**2/2 + k*L**3/3)/(Su0*L + k*L**2/2)#; print(ez)
8787
Np_fixed = 10.25; Np_free = 4 # From Np vs L/D chart from CAISSON_VHM
8888
Su_av_L = Su0 + k*zlug # Undrained shear strength values (average)
8989
Su_tip = Su0 + k*L # Undrained shear strength values (tip)
@@ -126,15 +126,15 @@ def f(Hmax):
126126
# "Leaking"
127127
Vmax3 = (PileWeight(L, D, t, rhows) + PileSurface(L, D)*alphastar*Su_av_L + SoilWeight(L, D, t, gamma))
128128
Vmax = min(Vmax1, Vmax2, Vmax3)
129-
129+
'''
130130
print("\n--- Parameter-Based Version ---")
131131
print(f"Su_av_L = {Su_av_L:.3f} kPa")
132132
print(f"sigma'_v(zlug) = {sigma_v_eff:.3f} kPa")
133133
print(f"psi_val = {psi_val:.3f}")
134134
print(f"alpha (API) = {alpha:.3f}")
135135
print(f"Hmax = {Hmax[0]:.2f} kN")
136136
print(f"Vmax = {Vmax:.2f} kN")
137-
137+
'''
138138

139139
elif soil_type == 'sand':
140140
# Definition for non-cohesive soils
@@ -168,22 +168,22 @@ def f(Hmax):
168168
# return np.e**(-depth) - 1 + depth
169169
# Ze = D/(4*7); Zi = D/(4*5)
170170
# Vmax = 7*gamma*Ze**2*y(L/Ze)*PileSurface(L, D)/L + 5*gamma*Zi**2*y(L/Zi)*PileSurface(L,(D - 2*t))/L
171-
171+
'''
172172
print("\n--- Parameter-Based (Sand) ---")
173173
print(f"phi = {phi:.2f} deg")
174174
print(f"gamma = {gamma:.2f} kN/m3")
175175
print(f"deltastar = {deltastar:.2f} -")
176176
print(f"sigma_av_L = {sigma_av_L:.2f} kN")
177177
print(f"sigma_tip = {sigma_tip:.2f} kN")
178-
178+
'''
179179
# Pile weight (inc. stiffening plus vent) assessed as a factor
180180
Wp = 1.10*PileWeight(L, D, t, (rhows + rhow))
181181
# Submerged weight of the soil plug
182182
Ws = SoilWeight(L, D, t, gamma)
183183

184184
# Capacity envelope
185185
aVH = 0.5 + lambdap; bVH = 4.5 + lambdap/3
186-
print('Env. exp = ' +str(aVH)+' '+str(bVH))
186+
#print('Env. exp = ' +str(aVH)+' '+str(bVH))
187187
UC = (H/Hmax)**aVH + (V/Vmax)**bVH
188188
x = np.cos(np.linspace (0, np.pi/2, 100))
189189
y = (1 - x**bVH)**(1/aVH)

famodel/project.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,8 +1564,7 @@ def addMooring(self, id=None, endA=None, endB=None, heading=0, dd={},
15641564
elif len(id_part)==1:
15651565
# anchored line
15661566
n_existing_moor = len(self.platformList[id_part[0]].getMoorings())
1567-
1568-
id = str(id_part)+alph[n_existing_moor]
1567+
id = str(id_part[0])+alph[n_existing_moor]
15691568
else:
15701569
id = 'moor'+str(len(self.mooringList))
15711570

0 commit comments

Comments
 (0)