Skip to content

Commit 405118b

Browse files
committed
Adding Resetting Array Origin to Mid-Platform:
This will help with TurbSim and FFarm integration as farm needs to have an origin at the center of the farm. The resetArrayCenter can accept centering the array based on all platforms or only those carrying FOWTs. The function will change bathymetries, boundaries, platform locations, and everything associated with the platforms.
1 parent fd4e8e7 commit 405118b

File tree

3 files changed

+76
-24
lines changed

3 files changed

+76
-24
lines changed

famodel/mooring/mooring.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def reposition(self, r_center=None, heading=None, project=None,
198198
r_center : list or nested list
199199
The x, y, z coordinates of the platform(s) (undisplaced) [m]. If shared mooring, must be a list of lists, with the
200200
coordinates for each platform connection. In this case, end A platform connection is the first entry and end B
201-
platform connection is the second entry.
201+
platform connection is the second entry. If not given, r_center will be populated from what self is attached to.
202202
heading : float
203203
The absolute heading compass direction of the mooring line from end B
204204
[deg or rad] depending on degrees parameter (True or False). Must account for the platform heading as well.
@@ -227,11 +227,15 @@ def reposition(self, r_center=None, heading=None, project=None,
227227
# heading 2D unit vector
228228
u = np.array([np.cos(phi), np.sin(phi)])
229229

230-
if self.shared == 1:
231-
r_centerB = np.array(r_center)[1]
232-
r_centerA = np.array(r_center)[0]
230+
if np.any(r_center):
231+
if self.shared == 1:
232+
r_centerA = np.array(r_center)[0]
233+
r_centerB = np.array(r_center)[1]
234+
else:
235+
r_centerB = np.array(r_center)
233236
else:
234-
r_centerB = np.array(r_center)
237+
r_centerA = self.attached_to[0].r
238+
r_centerB = self.attached_to[1].r
235239

236240
# create fairlead radius list for end A and end B if needed
237241
if not rad_fair:

famodel/platform/platform.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ def __init__(self, id, r=[0,0,0], heading=0, mooring_headings=[60,180,300],rFair
6464
def setPosition(self, r, heading=None, degrees=False,project=None):
6565
'''
6666
Set the position/orientation of the platform as well as the associated
67-
anchor points.
67+
anchor points.
6868
69+
"Note: must only be used for a platform that's only attached with anchored lines"
70+
6971
Parameters
7072
----------
7173
r : list

famodel/project.py

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ def __init__(self, lon=0, lat=0, file=None, depth=202,raft=1):
117117
# MoorPy system associated with the project
118118
self.ms = None
119119

120-
120+
# RAFTDict associated with the project
121+
self.RAFTDict = None
121122

122123
# ----- if an input file has been passed, load it -----
123124
if file:
@@ -788,15 +789,17 @@ def loadDesign(self, d, raft=1):
788789
# create a name for the raft model
789790
RAFTDict['name'] = 'Project_Array'
790791
RAFTDict['type'] = 'input file for RAFT'
791-
792+
793+
self.RAFTDict = deepcopy(RAFTDict)
794+
792795
# create RAFT model if necessary components exist
793796
if 'platforms' in RAFTDict or 'platform' in RAFTDict:
794797

795798
self.getRAFT(RAFTDict,pristine=1)
796-
799+
800+
797801

798802

799-
800803

801804

802805
# ----- Site conditions processing functions -----
@@ -4114,20 +4117,21 @@ def extractFarmInfo(self, cmax=5, fmax=10/6, Cmeander=1.9):
41144117
i = 0
41154118
yaw_init = np.zeros((1, len(self.platformList.items())))
41164119
for _, pf in self.platformList.items():
4117-
x, y, z = pf.body.r6[0], pf.body.r6[1], pf.body.r6[2]
4118-
phi_deg = np.degrees(pf.phi) # float((90 - np.degrees(pf.phi)) % 360) # Converting FAD's rotational convention (0deg N, +ve CW) into FF's rotational convention (0deg E, +ve CCW)
4119-
phi_deg = (phi_deg + 180) % 360 - 180 # Shift range to -180 to 180
4120-
for att in pf.attachments.values():
4121-
if isinstance(att['obj'],Turbine):
4122-
D = 240 # att['obj'].D (assuming 15MW)
4123-
zhub = att['obj'].dd['hHub']
4120+
if pf.entity=='FOWT':
4121+
x, y, z = pf.body.r6[0], pf.body.r6[1], pf.body.r6[2]
4122+
phi_deg = np.degrees(pf.phi) # float((90 - np.degrees(pf.phi)) % 360) # Converting FAD's rotational convention (0deg N, +ve CW) into FF's rotational convention (0deg E, +ve CCW)
4123+
phi_deg = (phi_deg + 180) % 360 - 180 # Shift range to -180 to 180
4124+
for att in pf.attachments.values():
4125+
if isinstance(att['obj'],Turbine):
4126+
D = 240 # att['obj'].D (assuming 15MW)
4127+
zhub = att['obj'].dd['hHub']
41244128

4125-
wts[i] = {
4126-
'x': x, 'y': y, 'z': z, 'phi_deg': phi_deg, 'D': D, 'zhub': zhub,
4127-
'cmax': cmax, 'fmax': fmax, 'Cmeander': Cmeander
4128-
}
4129-
yaw_init[0, i] = -phi_deg
4130-
i += 1
4129+
wts[i] = {
4130+
'x': x, 'y': y, 'z': z, 'phi_deg': phi_deg, 'D': D, 'zhub': zhub,
4131+
'cmax': cmax, 'fmax': fmax, 'Cmeander': Cmeander
4132+
}
4133+
yaw_init[0, i] = -phi_deg
4134+
i += 1
41314135

41324136
# store farm-level wind turbine information
41334137
self.wts = wts
@@ -4206,6 +4210,48 @@ def FFarmCompatibleMDOutput(self, filename, unrotateTurbines=True, renameBody=Tr
42064210
with open(filename, 'w') as f:
42074211
f.writelines(newLines)
42084212

4213+
def resetArrayCenter(self, FOWTOnly=True):
4214+
'''
4215+
Function to reset array center such that the farm origin is the mid-point between all FOWT platforms:
4216+
4217+
Parameters
4218+
----------
4219+
FOWTOnly : bool
4220+
find the center between only FOWT-entity platforms if True.
4221+
'''
4222+
xCenter = np.mean([p.r[0] for p in self.platformList.values() if p.entity=='FOWT' or not FOWTOnly])
4223+
yCenter = np.mean([p.r[1] for p in self.platformList.values() if p.entity=='FOWT' or not FOWTOnly])
4224+
delta = np.array([xCenter, yCenter])
4225+
4226+
# Change boundaries
4227+
self.boundary -= delta
4228+
4229+
# Change bathymetry
4230+
self.grid_x -= delta[0]
4231+
self.grid_y -= delta[1]
4232+
4233+
# Change all platform locations and associated anchors/moorings/cables
4234+
for pf in self.platformList.values():
4235+
pf.r[:2]-=delta
4236+
for i, att in enumerate(pf.attachments.values()):
4237+
obj = att['obj']
4238+
if isinstance(obj, Mooring):
4239+
obj.reposition(project=self)
4240+
4241+
if isinstance(obj, Cable):
4242+
obj.reposiiton(project=self)
4243+
4244+
# Change RAFTDict if available.
4245+
if self.RAFTDict:
4246+
x_idx = self.RAFTDict['array']['keys'].index('x_location')
4247+
y_idx = self.RAFTDict['array']['keys'].index('y_location')
4248+
for i in range(len(self.platformList.values())):
4249+
self.RAFTDict['array']['data'][i][x_idx] -= delta[0]
4250+
self.RAFTDict['array']['data'][i][y_idx] -= delta[1]
4251+
4252+
if 'platforms' in self.RAFTDict or 'platform' in self.RAFTDict:
4253+
self.getRAFT(self.RAFTDict,pristine=1)
4254+
42094255

42104256
def updateFailureProbability(self):
42114257
'''
@@ -4219,7 +4265,7 @@ def updateFailureProbability(self):
42194265
None.
42204266
42214267
'''
4222-
4268+
pass
42234269

42244270

42254271

0 commit comments

Comments
 (0)