Skip to content

Commit a8db9f8

Browse files
committed
Small bug fix platform.setPosition, loadDesign update, helpers, documentation updates
-- bug fix in platoform.setPosition to remove reliance on mooring_headings property. That way, if a mooring line is removed then added setPosition still works with new order - this required addition of a 'rel_heading' property to the mooring class. -- new helpers functions - removeMooring will remove mooring object's attachments, delete the mooring object from the mooringList, and optionally re-create the MoorPy ms - calcMinimumDists will calculate the minimum distance between 2 lists of objects - calcMaterialMasses (work in progress) will calculate the total material mass of all subcomponents in an object -- update loadDesign so that if fairleads are defined in yaml but fairlead indices are not defined in mooring setup, it will use the rFair and zFair if that is provided. -- various documentation updates
1 parent 6d31e7c commit a8db9f8

File tree

7 files changed

+253
-55
lines changed

7 files changed

+253
-55
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,14 @@ information in an ontology yaml file. FAD has been designed
9999
to work with a specific ontology yaml setup, which is described
100100
in detail in the [Ontology ReadMe](./famodel/ontology/README.md).
101101

102-
The [example driver file](./famodel/example_driver.py) creates a FAD Project
102+
For examples of ontologies and driver files of common use cases,
103+
we recommend starting with the numbered examples in the examples folder.
104+
The [visualization examples](./examples/01_Visualization/) are a good place
105+
to start. Run the .py files and inspect the .yaml files with the same name
106+
to see what information is required for different uses and how they are conveyed
107+
in the ontology.
108+
109+
To see an example with all use cases, the [example driver file](./examples/example_driver.py) creates a FAD Project
103110
object from a pre-set ontology file and shows the syntax and outputs of
104111
various capabilities. For guidance on creating your own ontology yaml file,
105112
it is recommended to read through the [Ontology ReadMe](./famodel/ontology/README.md),

famodel/README.md

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -346,12 +346,32 @@ Interpolate soil properties at specified location from the soil
346346
properties grid and return a dictionary of soil properties that
347347
can be used in anchor capacity calculations.
348348

349-
### calcAnchorCapacity
349+
<!--### calcAnchorCapacity
350350
351351
Compute holding capacity of a given anchor based on the soil
352352
info at its position. The anchor object's anchor properties and
353353
location will be used to determine the holding capacity, which
354-
will be saved to the anchor object.
354+
will be saved to the anchor object.-->
355+
356+
### convertUniformToLayered
357+
358+
Converts self.soilProps (uniform format) into profile_map (layered format)
359+
using a default thickness and assuming uniform clay profile.
360+
Matches the structure of layered CPT-based soil profiles.
361+
362+
### convertLayeredToUniform
363+
364+
Converts self.profile_map (layered format) into soilProps (uniform format)
365+
assuming a single clay layer with linear Su(z) = Su0 + k*z.
366+
Matches the structure expected by uniform soil models.
367+
368+
### updateAnchor
369+
370+
update the location and soil types stored in anchor objects
371+
372+
### setSoilAtLocation
373+
374+
set the soil profile at the location
355375

356376
### getDepthAtLocation
357377

@@ -376,6 +396,18 @@ and returns a matrix of these distances for the array.
376396

377397
Calculates the cable's length based on its routing
378398

399+
### loadBoundary
400+
401+
Load a lease area boundary for the project from an input file.
402+
403+
### setBoundary
404+
405+
Set the boundaries of the project based on x-y polygon vertices
406+
407+
### setExclusionZone
408+
409+
Set exclusion zones of the project based on x-y vertices
410+
379411
### checkCableExclusions
380412

381413
Checks whether a cable crosses over any exclusions or other out of bounds areas
@@ -385,6 +417,43 @@ Checks whether a cable crosses over any exclusions or other out of bounds areas
385417
Trims bathymetry and soil grid information that is outside the project boundaries,
386418
for faster execution and plotting.
387419

420+
### addPlatform
421+
422+
Convenience method to add a platform object. Can specify a variety of information
423+
about the platform such as location, entity, heading, ID, design, etc
424+
425+
### addFairlead
426+
427+
Method to create a fairlead object and attach it to a Platform
428+
429+
### addMooring
430+
431+
Function to create a mooring object and save in mooringList
432+
Optionally does the following:
433+
- create design dictionary if section_types, section_lengths, connectors, and span provided
434+
- create id if none provided
435+
- reposition mooring object and any associated anchor object, update anchor object depth for new location
436+
- attach mooring object to end A and end B object
437+
438+
### addAnchor
439+
440+
Function to create and add an anchor to the project
441+
442+
### addTurbine
443+
444+
Method to create and add a Turbine object to the project
445+
446+
### addSubstation
447+
448+
Method to create and add a Substation object to the project.
449+
Note that Substation objects sit on top of platforms - the platform
450+
portion of the substation is defined in the Platform object and the
451+
topside information is defined in the Substation object
452+
453+
### addJtube
454+
455+
method to create and add a Jtube object, and attach it to a platform object
456+
388457
### addCablesConnections
389458

390459
Creates cable objects from a list and connects them to platforms. If a cable configuration dictionary is provided, full 3d cable designs will be loaded in and cable headings/routing will be adjusted to avoid mooring line clashing. If only list of cable connections is provided, only basic information such as cable cross-sectional properties, conductor size, and connections will be loaded. Designed to work with the output list format from FADesign/CableLayout_functions.getCableLayout(), which will be publicly available in the near future.
@@ -423,9 +492,9 @@ Create a RAFT object and store in the project class
423492
Calls the addMarineGrowth mooring and/or cable class method for the chosen mooring and/or cable objects, and applies the specified marine growth thicknesses at the specified depth ranges for the specified marine growth densities.
424493

425494

426-
### getCorrosion
495+
<!--### getCorrosion
427496
428-
Function to reduce MBL of specified lines based on corrosion thickness
497+
Function to reduce MBL of specified lines based on corrosion thickness-->
429498

430499
### updateUniformArray
431500

@@ -464,10 +533,33 @@ Function to unload information to an ontology yaml file
464533
Function to extract farm-level information required to create FAST.Farm case simulations.
465534
Currently under development.
466535

467-
## FFarmCompatibleMDOutput
536+
### FFarmCompatibleMDOutput
468537

469538
Function to create a FAST.Farm-compatible MoorDyn input file.
470539

540+
### resetArrayCenter
541+
542+
Function to reset array center such that the farm origin is the mid-point
543+
between all FOWT platforms in y and the minimum_x turbine location in x:
544+
545+
### reorientArray
546+
547+
Reorients the array based on a given wind heading. The array will be reoriented such that wind faces East (the zero in FFarm).
548+
Useful to allign the array with the wind direction.
549+
550+
### repositionArray
551+
552+
Method to reposition all platforms in the array at once with input arrays
553+
of positions and headings
554+
555+
### mapRAFTResults
556+
557+
Function to map RAFT results to the project class. This
558+
maps the results from RAFT to the project class.
559+
560+
### generateSheets
561+
562+
Generates sheets in an Excel workbook with RAFT cases, platform, and mooring line information.
471563

472564
### getFromDict
473565

famodel/helpers.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import moorpy as mp
1111
from moorpy.helpers import loadPointProps, getPointProps
1212
import shapely as sh
13+
#from famodel.mooring.mooring import Mooring
14+
#from famodel.platform.platform import Platform
1315

1416

1517
def cart2pol(x, y):
@@ -1136,6 +1138,44 @@ def attachFairleads(moor, end, platform, fair_ID_start=None, fair_ID=None, fair_
11361138
end_subcons[ii].join(fairs[-1])
11371139

11381140
return(fairs)
1141+
1142+
def removeMooring(mooring, project, reset_ms=False):
1143+
'''
1144+
Removes mooring object from project
1145+
1146+
Parameters
1147+
----------
1148+
mooring : TYPE
1149+
DESCRIPTION.
1150+
1151+
Returns
1152+
-------
1153+
None.
1154+
1155+
'''
1156+
if not isinstance(mooring, list):
1157+
mooring = [mooring]
1158+
1159+
for moor in mooring:
1160+
# go through platform attachment list and find which index in mooring_headings list
1161+
# for att in moor.attached_to:
1162+
# if hasattr(att,'rFair'):
1163+
# inds_to_remove = []
1164+
# for ii,attP in enumerate(att.getMoorings.values()):
1165+
# if attP == moor:
1166+
# inds_to_remove.append(ii)
1167+
# for ind in list(inds_to_remove.reverse()):
1168+
# att.mooring_headings.pop(ind)
1169+
# detach mooring from each end
1170+
moor.detach_From('A')
1171+
moor.detach_From('B')
1172+
1173+
# remove from mooringList
1174+
project.mooringList.pop(moor.id)
1175+
1176+
# redo ms if asked
1177+
if reset_ms:
1178+
project.getMoorPyArray()
11391179

11401180
def calc_heading(pointA, pointB):
11411181
'''calculate a compass heading from points, if pointA or pointB is a list of points,
@@ -1480,6 +1520,67 @@ def compareDicts(d1, d2):
14801520
return(False)
14811521
return(True)
14821522

1523+
def calcMinimumDists(obj_list_A,obj_list_B=None, coords_list=None):
1524+
'''
1525+
Calculates and returns the minimum distance between 2 lists of objects.
1526+
1527+
Parameters
1528+
----------
1529+
obj_list_A : list
1530+
List of component objects to calculate distance from second list
1531+
obj_list_B : list, optional
1532+
Second list of component objects to calculate distance from obj_list_A locations
1533+
coords_list : list, optional
1534+
List of coordinates, such as a lease boundary, to compare distance from obj_list_A
1535+
1536+
Returns
1537+
-------
1538+
A2B : float
1539+
Minimum distance between the compared locations
1540+
1541+
'''
1542+
A2B=np.inf
1543+
1544+
if obj_list_B is not None:
1545+
for objA in obj_list_A:
1546+
for objB in obj_list_B:
1547+
if objA != objB:
1548+
dist = np.linalg.norm(np.array(objA.r[:2]) - np.array(objB.r[:2]))
1549+
A2B = min(A2B, dist)
1550+
elif coords_list!=None:
1551+
for objA in obj_list_A:
1552+
dist = np.linalg.norm(objA.r[:2] - coords_list, axis=1)
1553+
A2B = min(A2B, np.min(dist))
1554+
else:
1555+
raise Exception('Either obj_list_B or coords_list must not be None')
1556+
1557+
return(A2B)
1558+
1559+
def calcMaterialMasses(obj_list):
1560+
'''
1561+
Calculates and returns the sum of masses for each material used in the list of objects
1562+
1563+
For example, a list of mooring lines composed of chain and polyester would return
1564+
the total mass of chain across all lines and the total mass of polyester across all lines
1565+
'''
1566+
masses={}
1567+
1568+
for obj in obj_list:
1569+
if hasattr(obj, 'ss'):
1570+
# pull out list of subcomponent masses by material
1571+
for line in obj.ss.lineList:
1572+
mat = line.type['material']
1573+
if not mat in masses:
1574+
masses[mat] = 0
1575+
masses[mat] += line.type['mass']*line.L
1576+
elif hasattr(obj, 'm'):
1577+
# check if there's a type or entity
1578+
if hasattr(obj,'entity'):
1579+
if not obj.entity in masses:
1580+
masses[obj.entity] = 0
1581+
masses[obj.entity] += obj.m
1582+
1583+
14831584
def cleanDataTypes(info, convert_lists=True):
14841585
'''
14851586
cleans data types in a dictionary to be yaml-writeable data types, usually for

famodel/mooring/mooring.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def __init__(self, dd=None, subsystem=None, anchor=None,
184184
# end point absolute coordinates, to be set later
185185
self.rA = np.array([-self.rad_anch, 0, self.z_anch])
186186
self.rB = np.array([-self.rad_fair, 0, self.z_fair])
187+
self.rel_heading = 270 # compass heading relative to platform B heading
187188
self.heading = 270 # compass heading from B to A [deg]
188189

189190
self.adjuster = None # custom function that can adjust the mooring
@@ -890,6 +891,8 @@ def updateState(self, stateDict, ms=None):
890891
- 'creep': Boolean indicating whether to apply creep.
891892
- 'corrosion': Boolean indicating whether to apply corrosion.
892893
- 'marineGrowth': Dictionary for marine growth configuration (same as addMarineGrowth).
894+
ms : MoorPy system, optional
895+
Overall moorpy system that is associated with this
893896
'''
894897

895898
# Extract global number of years

famodel/platform/platform.py

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ def __init__(self, id, r=[0,0,0], heading=0, mooring_headings=[60,180,300],rFair
4646

4747
self.body = None # body object in MoorPy associated with the platform
4848

49-
self.mooring_headings = list(np.radians(mooring_headings)) # headings of mooring lines [rad]
49+
# self.mooring_headings = list(np.radians(mooring_headings)) # headings of mooring lines [rad]
5050

51-
self.n_mooring = len(mooring_headings) # number of mooring lines
51+
# self.n_mooring = len(mooring_headings) # number of mooring lines
5252

5353
self.entity = None # describes what type of platform this is/what its topside carries (for floating wind turbine, entity = 'FOWT', for substation, entity = 'OSS')
5454

@@ -83,7 +83,8 @@ def setPosition(self, r, heading=None, degrees=False,project=None, update_moorin
8383
The heading of the platform [deg or rad] depending on
8484
degrees parameter (True or False) in compass direction
8585
'''
86-
86+
# store old platform heading
87+
old_phi = self.phi
8788

8889
# first call the Node method to take care of the platform and what's directly attached
8990
if heading: # save compass heading in radians
@@ -99,36 +100,26 @@ def setPosition(self, r, heading=None, degrees=False,project=None, update_moorin
99100
# Update the position of any Moorings
100101
count = 0 # mooring counter (there are some attachments that aren't moorings)
101102
if update_moorings:
102-
for i, att in enumerate(self.attachments):
103-
if isinstance(self.attachments[att]['obj'], Mooring):
104-
# Heading of the mooring line
105-
heading_i = self.mooring_headings[count] + self.phi
106-
# Reposition the whole Mooring if it is an anchored line
107-
if not self.attachments[att]['obj'].shared:
108-
self.attachments[att]['obj'].reposition(r_center=self.r, heading=heading_i,project=project)
109-
110-
count += 1
111-
112-
if isinstance(self.attachments[att]['obj'], Cable):
113-
114-
cab = self.attachments[att]['obj']
115-
116-
# update heading stored in subcomponent for attached end
117-
# pf_phis = [cab.attached_to[0].phi, cab.attached_to[1].phi]
118-
# headings = [cab.subcomponents[0].headingA + pf_phis[0], cab.subcomponents[-1].headingB + pf_phis[1]]
103+
for moor in self.getMoorings().values():
104+
# Heading of the mooring line
105+
heading_i = np.radians(moor.rel_heading) + self.phi #self.attachments[att]['obj'].heading - old_phi + self.phi
106+
# Reposition the whole Mooring if it is an anchored line
107+
if not moor.shared:
108+
moor.reposition(r_center=self.r, heading=heading_i,project=project)
109+
119110

120-
# reposition the cable
121-
cab.reposition(project=project)
111+
for cab in self.getCables().values():
112+
113+
# reposition the cable
114+
cab.reposition(project=project)
122115

123116
self.updateMooringPoints()
124117

125118
if not update_moorings:
126119
# update span in case it changed if pf location changes but anchor does not
127-
for i, att in enumerate(self.attachments):
128-
if isinstance(self.attachments[att]['obj'], Mooring):
129-
moor = self.attachments[att]['obj']
130-
moor.dd['span'] = np.linalg.norm(moor.rA[:2]-moor.rB[:2])
131-
moor.span=moor.dd['span']
120+
for moor in self.getMoorings().values():
121+
moor.dd['span'] = np.linalg.norm(moor.rA[:2]-moor.rB[:2])
122+
moor.span=moor.dd['span']
132123

133124
def mooringSystem(self,rotateBool=0,mList=None,bodyInfo=None, project=None):
134125
'''

0 commit comments

Comments
 (0)