@@ -199,11 +199,14 @@ def __init__(self, X, Xu, Xdb =[], wind_rose = [], ss = None, mooringAdjuster =
199199 #with open(os.path.join(dir,"CableProps_default.yaml")) as file:
200200 # source = yaml.load(file, Loader=yaml.FullLoader)
201201 #As = source['conductor_size']['size_A_df']
202- self .iac_typical_conductor = getFromDict (kwargs , 'iac_typical_conductor' ,shape = - 1 , default = [0 ])
202+ self .iac_typical_conductor = getFromDict (kwargs , 'iac_typical_conductor' ,shape = - 1 , default = [300 , 630 , 1000 ])
203203 if len (self .iac_typical_conductor )== 1 and self .iac_typical_conductor [0 ] == 0 :
204204 self .iac_typical_conductor = np .array ([ 70 , 95 , 120 , 150 , 185 , 240 , 300 , 400 , 500 , 630 ,
205205 800 , 1000 , 1200 ,1400 ,1600 ,200 ,2500 ,3000 ,4000 ])
206206
207+ #moorings and mooring headings
208+ self .n_moor = getFromDict (kwargs , 'n_moor' , default = 3 )
209+ self .mooring_headings = getFromDict (kwargs , 'mooring_headings' , default = [0 , 120 , 240 ])
207210
208211 # ----- Offshore Substation -----
209212 self .noss = int (getFromDict (kwargs ,'noss' , default = 1 ))
@@ -344,29 +347,43 @@ def max_distance(x_values):
344347
345348
346349 # ----- Mooring system variables -----
350+ # depth relevant to new method of subsystem sink
351+ if 'depth' in kwargs :
352+ self .depth = kwargs ['depth' ]
353+ else :
354+ self .depth = np .min (self .grid_depth )
355+ if 'adjuster_settings' in kwargs :
356+ from famodel .helpers import configureAdjuster
357+ method = getFromDict (kwargs ['adjuster_settings' ],'method' , default = 'horizontal' , dtype = str )
358+ iline = getFromDict (kwargs ['adjuster_settings' ],'i_line' , default = 0 , dtype = int )
359+ if 'span' in kwargs ['adjuster_settings' ]:
360+ span = kwargs ['adjuster_settings' ]['span' ]
361+ else :
362+ span = None
363+ if 'target' in kwargs ['adjuster_settings' ]:
364+ target = kwargs ['adjuster_settings' ]['target' ]
365+ else :
366+ target = None
347367 print ("setting up mooringList" )
348- self .mooringList = makeMooringListN (ss , 3 * self .nt ) # make Moorings
368+ self .mooringList = makeMooringListN (ss , self . n_moor * self .nt ) # make Moorings
349369
350370 for mooring in self .mooringList .values (): # hackily set them up
351- mooring .dd ['sections' ] = []
352- mooring .dd ['connectors' ] = []
353- for i ,sec in enumerate (mooring .ss .lineList ):
354- mooring .dd ['connectors' ].append ({'CdA' :0 ,'m' :0 ,'v' :0 })
355- mooring .dd ['sections' ].append ({'type' :mooring .ss .lineList [i ].type ,
356- 'L' :mooring .ss .lineList [i ].L })
357- mooring .dd ['connectors' ].append ({'CdA' :0 ,'m' :0 ,'v' :0 })
358371 mooring .adjuster = mooringAdjuster # set the designer/adjuster function
372+ if 'adjuster_settings' in kwargs :
373+ configureAdjuster (mooring , adjuster = mooring .adjuster , method = method ,
374+ i_line = iline , span = span , project = self , target = target )
359375
360376
361377 # ----- Platforms -----
362378 for i in range (self .nt ):
363379 r = [self .turb_coords [i ][0 ],self .turb_coords [i ][1 ],0 ]
364- self .platformList [i ] = Platform (id = i , r = r , heading = 0 , mooring_headings = [ 0 , 120 , 240 ], rFair = ss .rad_fair ,zFair = ss .z_fair )
380+ self .platformList [i ] = Platform (id = i , r = r , heading = 0 ,rFair = ss .rad_fair ,zFair = ss .z_fair )
365381 self .platformList [i ].entity = 'FOWT'
366382
367- for j in range (3 ):
368- self .platformList [i ].attach (self .mooringList [i * 3 + j ], end = 'b' )
369-
383+ for j in range (self .n_moor ):
384+ self .mooringList [i * self .n_moor + j ].rel_heading = self .mooring_headings [j ]
385+ self .platformList [i ].attach (self .mooringList [i * self .n_moor + j ], end = 'b' )
386+ # self.mooringList[i*3+j].reposition(heading = self.mooring_headings[j],degrees=True)
370387
371388 # ---- Anchors ----
372389 self .anchorList = {}
@@ -399,7 +416,7 @@ def max_distance(x_values):
399416 elif anchor_settings and 'mass' in kwargs ['anchor_settings' ]:
400417 anch .mass = kwargs ['anchor_settings' ]['mass' ]
401418
402-
419+
403420 # --- develop anchor types ---
404421 self .anchorTypes = {}
405422 self .anchorMasses = {}
@@ -409,6 +426,7 @@ def max_distance(x_values):
409426 pf = self .platformList [0 ]
410427 # artificially set platform at 0,0
411428 pf .setPosition ([0 ,0 ],project = self ) # put in a random place and reposition moorings
429+
412430 # create ms for this platform
413431 msPF = pf .mooringSystem ()
414432 # set depth artificially to mean depth
@@ -464,16 +482,20 @@ def max_distance(x_values):
464482 self .anchorCosts [name ] = deepcopy (anch .getCost ())
465483 except :
466484 self .anchorCosts [name ] = 0
467-
468-
485+
469486
470- self .ms_na = 3 # Number of anchors per turbine. For now ONLY 3 point mooring system.
487+ self .ms_na = self . n_moor # Number of anchors per turbine. For now equals number of mooring lines (no shared anchors/lines)
471488 #self.ms_anchor_depth = np.zeros((self.nt*self.ms_na)) # depths of anchors
472489 self .anchor_coords = np .zeros ((self .nt * self .ms_na ,2 )) # anchor x-y coordinate list [m]
473490 self .ms_bufferzones_pos = np .zeros ((self .nt ,), dtype = object ) # Buffer zones for moorign system
474491 self .ms_bufferzones_rout = np .zeros ((self .nt ,), dtype = object )
475492 self .ms_bufferzones_rout_points = np .zeros ((self .nt ,), dtype = object )
476-
493+ self .getMoorPyArray ()
494+
495+ self .aep_evol = []
496+ self .moor_evol = []
497+ self .cab_evol = []
498+ self .lcoe_evol = []
477499
478500 # ----- Initialize the FLORIS interface fi -----
479501 self .use_FLORIS = getFromDict (kwargs ,'use_FLORIS' , default = False )
@@ -584,22 +606,41 @@ def generateGridPoints(self, Xu, trans_mode, boundary_index=-1):
584606
585607 # Lease area shape: Get min and max xy coordinates and calculate width
586608 min_x , min_y , max_x , max_y = boundary .bounds # self.boundary_sh.bounds
587- xwidth = abs (max_x - min_x )
588- ywidth = abs (max_y - min_y )
589-
590-
609+ # xwidth_old = abs(max_x-min_x)
610+ # ywidth_old = abs(max_y-min_y)
611+ xwidth = abs (max_x - min_x )+ bound_centroid_x
612+ xwidth -= xwidth % grid_spacing_x
613+ ywidth = abs (max_y - min_y )+ bound_centroid_y
614+ ywidth -= ywidth % grid_spacing_y
615+
616+ # ####################
617+ # x=bound_centroid_x-xwidth#-xwidth_old-bound_centroid_x
618+ # y=bound_centroid_y-ywidth#-ywidth_old-bound_centroid_y
619+ # local_x_old, local_y_old = np.dot(transformation_matrix, [x, y])
620+ # # Add grid translation offsets to local coordinates
621+ # local_x_old += grid_trans_x
622+ # local_y_old += grid_trans_y
623+ # old = np.array([local_x_old,local_y_old])
624+ # x=-xwidth
625+ # y=-ywidth
626+ # local_x, local_y = np.dot(transformation_matrix, [x, y])
627+ # new = np.array([local_x,local_y])
628+ # new_trans = old-new
629+ # ##############################
630+
591631 # LOCAL COORDINATE SYSTEM WITH (0,0) LEASE AREA CENTROID
592632 # Therefore, +/- self.boundary_centroid_y/x cover the entire area
593633 # Loop through y values within the boundary_centroid_y range with grid_spacing_y increments
594634 column_count = 0
595635 rotations = []
596636 grid_position = []
597- for y in np .arange (- bound_centroid_y - ywidth , bound_centroid_y + ywidth , grid_spacing_y ):
637+ for y in np .arange (- ywidth , ywidth , grid_spacing_y ):
638+ # for y in np.arange(-bound_centroid_y-ywidth, bound_centroid_y+ywidth, grid_spacing_y):
598639 column_count += 1
599640 row_count = 0
600641 # Loop through x values within the boundary_centroid_x range with grid_spacing_x increments
601- for x in np .arange (- bound_centroid_x - xwidth , bound_centroid_x + xwidth , grid_spacing_x ):
602-
642+ for x in np .arange (- xwidth , xwidth , grid_spacing_x ):
643+ # for x in np.arange(-bound_centroid_x-xwidth, bound_centroid_x+xwidth, grid_spacing_x):
603644 row_count += 1
604645 # Apply transformation matrix to x, y coordinates
605646 local_x , local_y = np .dot (transformation_matrix , [x , y ])
@@ -616,7 +657,6 @@ def generateGridPoints(self, Xu, trans_mode, boundary_index=-1):
616657 #store column, row for each turbine
617658 grid_position .append ([column_count , row_count ])
618659
619-
620660 # remove points that are not in boundaries
621661 bound_lines = boundary .boundary # get boundary lines for shapely analysis
622662 out_lines = [bound_lines ]
@@ -869,7 +909,7 @@ def updateLayout(self, X, level=0, refresh=False):
869909 buffer_group_rout = []
870910
871911 for j in range (self .ms_na ):
872- im = 3 * i + j # global index of mooring/anchor
912+ im = self . n_moor * i + j # global index of mooring/anchor
873913
874914 moor_bf_start = get_point_along_line (self .turb_coords [i ,:], self .mooringList [im ].rA [:2 ], self .turb_minrad )
875915 # Buffer zone mooring line
@@ -1470,6 +1510,12 @@ def getLCOE2(self):
14701510 self .getAEP ()
14711511 self .getCost ()
14721512 self .lcoe = ((self .cost_total + capex )* fcr + opex )/ self .aep * 1e6 # [$ / MWh]
1513+
1514+ self .aep_evol .append (self .aep )
1515+ costs = self .getArrayCost ()
1516+ self .moor_evol .append (costs ['moor cost' ])
1517+ self .cab_evol .append (costs ['cable cost' ])
1518+ self .lcoe_evol .append (self .lcoe )
14731519
14741520 #return self.cost
14751521
@@ -1534,7 +1580,7 @@ def calcDerivatives(self):
15341580 >>> PLACEHOLDER <<<
15351581 '''
15361582
1537- nDOF = 3 * self .nt
1583+ nDOF = self . n_moor * self .nt
15381584 '''
15391585 # Perturb each DOF in turn and compute AEP results
15401586 J_AEP = np.zeros([nt,nt])
@@ -1666,9 +1712,9 @@ def plotLayout(self, ax=None, bare=False, save=False):
16661712
16671713 # ----- mooring lines
16681714 for i in range (self .nt ):
1669- for j in range (3 ):
1670- plt .plot ([self .turb_coords [i ,0 ], self .mooringList [3 * i + j ].rA [0 ]],
1671- [self .turb_coords [i ,1 ], self .mooringList [3 * i + j ].rA [1 ]], 'k' , lw = 0.5 )
1715+ for j in range (self . n_moor ):
1716+ plt .plot ([self .turb_coords [i ,0 ], self .mooringList [self . n_moor * i + j ].rA [0 ]],
1717+ [self .turb_coords [i ,1 ], self .mooringList [self . n_moor * i + j ].rA [1 ]], 'k' , lw = 0.5 )
16721718
16731719 # plt.plot([self.turb_coords[i,0], self.anchor_coords[3*i+j,0]],
16741720 # [self.turb_coords[i,1], self.anchor_coords[3*i+j,1]], 'k', lw=0.5)
@@ -1719,48 +1765,49 @@ def plotLayout(self, ax=None, bare=False, save=False):
17191765 # ----- Cables
17201766 # Create a colormap and a legend entry for each unique cable section
17211767 # Find unique values
1722- unique_cables = np .unique ([x ['conductor_area' ] for x in self .iac_dic ]) #(self.iac_dic['minimum_con'].values)
1723- colors = plt .cm .viridis (np .linspace (0 , 1 , len (unique_cables ))) # Create a colormap based on the number of unique sections
1724- section_to_color = {sec : col for sec , col in zip (unique_cables , colors )}
1725-
1726-
1727- # ----- Cables in Cluster
1728- # Cable array
1729- iac_array = self .iac_dic
1730- count = 0
1731- # Loop over each cluster
1732- for ic in range (self .n_cluster * self .noss ):
1733- # Plot vertices
1734- #plt.scatter(self.cluster_arrays[ic][:, 0], self.cluster_arrays[ic][:, 1], color='red', label='Turbines')
1735-
1736- # Annotate each point with its index
1737- #for i, point in enumerate(self.cluster_arrays[ic]):
1738- #plt.annotate(str(i), (point[0], point[1]), textcoords="offset points", xytext=(0, 10), ha='center')
1739-
1740- # Get index of cluster
1741- #ind_cluster = np.where(iac_array[:, 0] == 0)[0]
1742- # Loop over edges / cable ids
1743- len_cluster = len (np .where (np .array ([x ['cluster_id' ]== ic for x in iac_array ]))[0 ])
1744- for i in range (len_cluster ):
1745- ix = np .where ((np .array ([x ['cluster_id' ]== ic for x in iac_array ])) & (np .array ([y ['cable_id' ]== count for y in iac_array ]) ))[0 ]
1746- if len (ix )< 1 :
1747- breakpoint ()
1748- ind = ix [0 ]
1749- #ind = np.where((iac_array[:, 0] == ic) & (iac_array[:, 2] == i))[0][0]
1750- # Plot edge
1751- #edge = self.iac_edges[ic][i]
1752- start = iac_array [ind ]['coordinates' ][0 ]#self.cluster_arrays[ic][edge[0]]
1753- end = iac_array [ind ]['coordinates' ][1 ]
1754- # Cable selection
1755- color = section_to_color [iac_array [ind ]['conductor_area' ]]
1756- ax .plot ([start [0 ], end [0 ]], [start [1 ], end [1 ]], color = color , label = f'Section { int (iac_array [ind ]["conductor_area" ])} mm²' if int (iac_array [ind ]["conductor_area" ]) not in plt .gca ().get_legend_handles_labels ()[1 ] else "" )
1757- #plt.text((start[0] + end[0]) / 2, (start[1] + end[1]) / 2, str(i), fontsize=9, color='black')
1758- # for sid in oss_ids:
1759- # if iac_array[ix]['turbineA_glob_id'] == sid or iac_array[ix]['turbineB_glob_id'] == sid:
1760- # iac_array_oss.append(iac_array[ix])
1761- # iac_oss_id.append(sid)
1768+ if hasattr (self ,'iac_dic' ):
1769+ unique_cables = np .unique ([x ['conductor_area' ] for x in self .iac_dic ]) #(self.iac_dic['minimum_con'].values)
1770+ colors = plt .cm .viridis (np .linspace (0 , 1 , len (unique_cables ))) # Create a colormap based on the number of unique sections
1771+ section_to_color = {sec : col for sec , col in zip (unique_cables , colors )}
1772+
1773+
1774+ # ----- Cables in Cluster
1775+ # Cable array
1776+ iac_array = self .iac_dic
1777+ count = 0
1778+ # Loop over each cluster
1779+ for ic in range (self .n_cluster * self .noss ):
1780+ # Plot vertices
1781+ #plt.scatter(self.cluster_arrays[ic][:, 0], self.cluster_arrays[ic][:, 1], color='red', label='Turbines')
1782+
1783+ # Annotate each point with its index
1784+ #for i, point in enumerate(self.cluster_arrays[ic]):
1785+ #plt.annotate(str(i), (point[0], point[1]), textcoords="offset points", xytext=(0, 10), ha='center')
17621786
1763- count += 1
1787+ # Get index of cluster
1788+ #ind_cluster = np.where(iac_array[:, 0] == 0)[0]
1789+ # Loop over edges / cable ids
1790+ len_cluster = len (np .where (np .array ([x ['cluster_id' ]== ic for x in iac_array ]))[0 ])
1791+ for i in range (len_cluster ):
1792+ ix = np .where ((np .array ([x ['cluster_id' ]== ic for x in iac_array ])) & (np .array ([y ['cable_id' ]== count for y in iac_array ]) ))[0 ]
1793+ if len (ix )< 1 :
1794+ breakpoint ()
1795+ ind = ix [0 ]
1796+ #ind = np.where((iac_array[:, 0] == ic) & (iac_array[:, 2] == i))[0][0]
1797+ # Plot edge
1798+ #edge = self.iac_edges[ic][i]
1799+ start = iac_array [ind ]['coordinates' ][0 ]#self.cluster_arrays[ic][edge[0]]
1800+ end = iac_array [ind ]['coordinates' ][1 ]
1801+ # Cable selection
1802+ color = section_to_color [iac_array [ind ]['conductor_area' ]]
1803+ ax .plot ([start [0 ], end [0 ]], [start [1 ], end [1 ]], color = color , label = f'Section { int (iac_array [ind ]["conductor_area" ])} mm²' if int (iac_array [ind ]["conductor_area" ]) not in plt .gca ().get_legend_handles_labels ()[1 ] else "" )
1804+ #plt.text((start[0] + end[0]) / 2, (start[1] + end[1]) / 2, str(i), fontsize=9, color='black')
1805+ # for sid in oss_ids:
1806+ # if iac_array[ix]['turbineA_glob_id'] == sid or iac_array[ix]['turbineB_glob_id'] == sid:
1807+ # iac_array_oss.append(iac_array[ix])
1808+ # iac_oss_id.append(sid)
1809+
1810+ count += 1
17641811
17651812 # Plot gate as a diamond marker
17661813 #plt.scatter(self.gate_coords[ic][0], self.gate_coords[ic][1], marker='D', color='green', label='Gate')
@@ -2245,8 +2292,10 @@ def get_point_along_line(start, end, diste):
22452292
22462293 # Wind rose
22472294 from floris import WindRose
2295+ import os
2296+ direct = '../scripts'
22482297 wind_rose = WindRose .read_csv_long (
2249- 'humboldt_rose.csv' , wd_col = "wd" , ws_col = "ws" , freq_col = "freq_val" , ti_col_or_value = 0.06 )
2298+ os . path . join ( direct , 'humboldt_rose.csv' ) , wd_col = "wd" , ws_col = "ws" , freq_col = "freq_val" , ti_col_or_value = 0.06 )
22502299
22512300
22522301 # ----- LEASE AREA BOUNDARIES -----
@@ -2263,10 +2312,15 @@ def get_point_along_line(start, end, diste):
22632312
22642313 # Make a sample Subsystem to hold the mooring design (used for initialization)
22652314 print ("Making subsystem" )
2266- newFile = '..\scripts\input_files\GoMxOntology.yaml'
2267- project = Project (file = newFile ,raft = 0 )
2268- project .getMoorPyArray ()
2269- ss = deepcopy (project .ms .lineList [0 ])
2315+ newFile = os .path .join (direct ,'input_files' ,'maine_moordyn.dat' )
2316+ #project = Project(file=newFile,raft=0)
2317+ #project.getMoorPyArray()
2318+ ms = mp .System (file = newFile ,depth = 200 )
2319+ ms .initialize ()
2320+ ms .solveEquilibrium ()
2321+ from moorpy .helpers import lines2ss
2322+ ms = lines2ss (ms )
2323+ ss = deepcopy (ms .lineList [0 ])
22702324
22712325 # ----- Set optimization mode
22722326 opt_mode = 'CAPEX'
@@ -2390,7 +2444,7 @@ def get_point_along_line(start, end, diste):
23902444 anchor_settings = {}
23912445 anchor_settings ['anchor_design' ] = {'L' :20 ,'D' :4.5 ,'zlug' :13.3 } # geometry of anchor
23922446 anchor_settings ['anchor_type' ] = 'suction' # anchor type
2393- anchor_settings ['anchor_resize' ] = True # bool to resize the anchor or not
2447+ anchor_settings ['anchor_resize' ] = False # bool to resize the anchor or not
23942448 anchor_settings ['fix_zlug' ] = False # bool to keep zlug the same when resizing anchor
23952449 anchor_settings ['FSdiff_max' ] = {'Ha' :.2 ,'Va' :.2 } # max allowed difference between FS and minimum FS
23962450 anchor_settings ['FS_min' ] = {'Ha' :2 ,'Va' :2 } # horizontal and vertical minimum safety factors
0 commit comments