Skip to content

Commit cb2bb35

Browse files
committed
Adding RAFT Mapping Features and info Sheet Generation:
1) FAModel can map RAFT results into the different objects in the project class for better and faster analysis. 2) safety factors of mooring lines are updated based on RAFT analysis and the fid. level is reported along with it. 3) FAModel can now geeerate excel sheets that describe the various components of the array along with certain results reported with it.
1 parent 652f8d3 commit cb2bb35

File tree

3 files changed

+124
-3
lines changed

3 files changed

+124
-3
lines changed

famodel/famodel_base.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ def __init__(self, id):
6262
# installation dictionary [checks for installation status]
6363
self.inst = {'mobilized': False,
6464
'installed': False}
65-
65+
66+
# raft results dictionary
67+
self.raftResults = {}
68+
6669
def isAttached(self, object, end=None):
6770
'''Check if something is attached to this node, even if it's part of
6871
a higher-level edge.

famodel/platform/platform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, id, r=[0,0,0], heading=0, mooring_headings=[60,180,300],rFair
5959
self.reliability = {}
6060
self.cost = {}
6161
self.failure_probability = {}
62-
62+
self.raftResults = {}
6363

6464
def setPosition(self, r, heading=None, degrees=False,project=None):
6565
'''

famodel/project.py

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3549,6 +3549,7 @@ def arrayWatchCircle(self,plot=False, ang_spacing=45, RNAheight=150,
35493549
moor.loads['TBmax'] = moor.ss.TB*DAF
35503550
moor.loads['info'] = f'determined from arrayWatchCircle() with DAF of {DAF}'
35513551
moor.safety_factors['tension'] = minTenSF[j]
3552+
moor.safety_factors['analysisType'] = 'quasi-static (MoorPy)'
35523553

35533554
# store max. laid length of the mooring lines
35543555
if moor_seabed_disturbance:
@@ -4405,9 +4406,126 @@ def updateFailureProbability(self):
44054406
'''
44064407
pass
44074408

4408-
4409+
def mapRAFTResults(self, results=None, SFs=True):
4410+
'''
4411+
Function to map RAFT results to the project class. This
4412+
maps the results from RAFT to the project class.
4413+
4414+
Parameters
4415+
----------
4416+
results : dict, optional
4417+
Dictionary of results from RAFT. The default is None.
4418+
If `analyzeCases` is ran in raft, then the self.array
4419+
results will be used. if results dictionary is empty,
4420+
we try to call analyze cases
4421+
4422+
4423+
Returns
4424+
-------
4425+
None.
4426+
4427+
'''
4428+
if results: # if results are given, overwrite self.array.results
4429+
self.array.results = results
4430+
4431+
if not self.array.results:
4432+
if not self.array.design['cases']:
4433+
raise ValueError("RAFT cases dictionary is empty. Please populate raft cases to generate RAFT results.")
4434+
4435+
# If there is cases dictionary but has not been run, make sure to run RAFT to get it
4436+
self.array.analyzeCases(display=1)
4437+
4438+
else:
4439+
# Get results from RAFT
4440+
# Map platform-related results:
4441+
nCases = len(self.array.design['cases']['data'])
4442+
for iCase in range(nCases):
4443+
for i, pf in enumerate(self.platformList.values()):
4444+
pf.raftResults[iCase] = self.array.results['case_metrics'][iCase][i]
4445+
4446+
# Map mooring-related results:
4447+
if SFs:
4448+
for moor in self.mooringList.values():
4449+
moor.safety_factors['tension'] = 1e10
4450+
4451+
for iCase in range(nCases):
4452+
i = 0
4453+
for moor in self.mooringList.values():
4454+
for line in moor.ss.lineList:
4455+
line.raftResults = {
4456+
'Tmoor_avg': self.array.results['case_metrics'][iCase]['array_mooring']['Tmoor_avg'][[i, i+len(self.ms.lineList)]],
4457+
'Tmoor_std': self.array.results['case_metrics'][iCase]['array_mooring']['Tmoor_std'][[i, i+len(self.ms.lineList)]],
4458+
'Tmoor_min': self.array.results['case_metrics'][iCase]['array_mooring']['Tmoor_min'][[i, i+len(self.ms.lineList)]],
4459+
'Tmoor_max': self.array.results['case_metrics'][iCase]['array_mooring']['Tmoor_max'][[i, i+len(self.ms.lineList)]],
4460+
'Tmoor_PSD': self.array.results['case_metrics'][iCase]['array_mooring']['Tmoor_PSD'][[i, i+len(self.ms.lineList)], :]
4461+
}
4462+
if SFs:
4463+
moor.safety_factors['tension'] = min(moor.safety_factors['tension'], min(line.type['MBL']/line.raftResults['Tmoor_max']))
4464+
moor.safety_factors['analysisType'] = f'(RAFT) MoorMod={self.array.moorMod}'
4465+
4466+
i += 1
4467+
4468+
def generateSheets(self, filename):
4469+
"""
4470+
Generates sheets in an Excel workbook with platform and mooring line information.
4471+
4472+
Parameters
4473+
----------
4474+
filename (str): The name of the Excel file to save the generated sheets.
4475+
4476+
4477+
Returns
4478+
-------
4479+
None
44094480
4481+
"""
4482+
4483+
import openpyxl
4484+
4485+
if not self.array.results:
4486+
if not self.array.design['cases']:
4487+
raise ValueError("RAFT cases dictionary is empty. Please populate raft cases to generate RAFT results.")
4488+
4489+
self.array.analyzeCases(display=1)
4490+
else:
4491+
nCases = len(self.array.design['cases']['data'])
4492+
4493+
# Create a new workbook
4494+
workbook = openpyxl.Workbook()
4495+
# Delete the default sheet
4496+
default_sheet = workbook.active
4497+
workbook.remove(default_sheet)
4498+
4499+
# Create a sheet for platforms
4500+
platform_sheet = workbook.create_sheet(title="Platforms")
4501+
platform_sheet.append(["ID", "X", "Y", "Depth", "Case", "Results (Avg)"])
4502+
platform_sheet.merge_cells(start_row=1, start_column=6, end_row=1, end_column=13)
4503+
platform_sheet.append([" ", " ", " ", " ", " ", "Surge (m)", "Sway (m)", "Heave (m)", "Roll (deg)", "Pitch (deg)", "Yaw (deg)", "NacAcc (m/s^2)", "TwrBend (Nm)"]) #, "RtrSpd (RPM)", "RtrTrq (Nm)", "Power (MW)"
4504+
for pf in self.platformList.values():
4505+
depth_at_pf = self.getDepthAtLocation(pf.r[0], pf.r[1])
4506+
if hasattr(pf, 'raftResults'):
4507+
for iCase in range(nCases):
4508+
if iCase==0:
4509+
platform_sheet.append([pf.id, round(pf.r[0], 2), round(pf.r[1], 2), round(depth_at_pf, 2), iCase,
4510+
round(pf.raftResults[iCase]['surge_avg'], 2), round(pf.raftResults[iCase]['sway_avg'], 2), round(pf.raftResults[iCase]['heave_avg'], 2),
4511+
round(pf.raftResults[iCase]['roll_avg'], 2), round(pf.raftResults[iCase]['pitch_avg'], 2), round(pf.raftResults[iCase]['yaw_avg'], 2),
4512+
round(pf.raftResults[iCase]['AxRNA_avg'][0], 2), round(pf.raftResults[iCase]['Mbase_avg'][0], 2)]) #, round(pf.raftResults[iCase]['omega_avg'][0], 2), round(pf.raftResults[iCase]['torque_avg'][0], 2), round(pf.raftResults[iCase]['power_avg'][0]*1e-6, 2)])
4513+
else:
4514+
platform_sheet.append([" ", " ", " ", " ", iCase,
4515+
round(pf.raftResults[iCase]['surge_avg'], 2), round(pf.raftResults[iCase]['sway_avg'], 2), round(pf.raftResults[iCase]['heave_avg'], 2),
4516+
round(pf.raftResults[iCase]['roll_avg'], 2), round(pf.raftResults[iCase]['pitch_avg'], 2), round(pf.raftResults[iCase]['yaw_avg'], 2),
4517+
round(pf.raftResults[iCase]['AxRNA_avg'][0], 2), round(pf.raftResults[iCase]['Mbase_avg'][0], 2)]) #, round(pf.raftResults[iCase]['omega_avg'][0], 2), round(pf.raftResults[iCase]['torque_avg'][0], 2), round(pf.raftResults[iCase]['power_avg'][0]*1e-6, 2)])
4518+
else:
4519+
platform_sheet.append([pf.id, round(pf.r[0], 2), round(pf.r[1], 2), round(depth_at_pf, 2)])
4520+
4521+
# Create a sheet for mooring lines
4522+
mooring_sheet = workbook.create_sheet(title="Mooring Lines")
4523+
mooring_sheet.append(["ID", "endA", "endB", "Shrd", "Safety Factors", "Fid Level"])
4524+
for moor in self.mooringList.values():
4525+
mooring_sheet.append([moor.id, moor.attached_to[0].id, moor.attached_to[1].id, moor.shared, round(moor.safety_factors['tension'], 2), moor.safety_factors['analysisType']])
44104526

4527+
# Save the workbook
4528+
workbook.save(filename)
44114529
'''
44124530
Other future items:
44134531
Cost calc functions

0 commit comments

Comments
 (0)