Skip to content

Commit 91e15b1

Browse files
committed
Update Celeris for hydrostatic force coupling with OpenSees
1 parent 18ff0e5 commit 91e15b1

3 files changed

Lines changed: 121 additions & 15 deletions

File tree

modules/createEVENT/Celeris/Celeris.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@
6060
print() # noqa: T201
6161

6262

63+
# Check if bresenham is installed before importing bresenham
64+
try:
65+
import bresenham
66+
except ImportError:
67+
print('Bresenham is not installed. Please install it using "pip install bresenham".')
68+
# noqa: T201
69+
print()
70+
subprocess.run([sys.executable, '-m', 'pip', 'install', 'bresenham'], check=False) # noqa: S603
71+
try:
72+
import bresenham
73+
except ImportError:
74+
print('Bresenham installation failed. Please install it manually.')
75+
# noqa: T201
76+
sys.exit(1)
77+
print('Bresenham is installed successfully.')
78+
# noqa: T201
79+
print()
80+
6381
class FloorForces: # noqa: D101
6482
def __init__(self, recorderID=-1): # noqa: N803
6583
if recorderID < 0:
@@ -96,7 +114,7 @@ def __init__(self, recorderID=-1): # noqa: N803
96114
continue
97115
# Assume there is no header in the file
98116
# Assume recorder IDs are sequential, starting from 1
99-
if (j + 1) == recorderID:
117+
if (j) == recorderID:
100118
# Strip away leading / trailing white-space,
101119
# Delimit by regex to capture " ", \s, " ", tabs, etc.
102120
# Each value should be a number, rep. the force on recorder j at a time-step i
@@ -173,16 +191,14 @@ def addFloorForceToEvent( # noqa: N802
173191
Add force (one component) time series and pattern in the event file
174192
Use of Wind is just a placeholder for now, since its more developed than Hydro
175193
""" # noqa: D205, D400
176-
seriesName = '1' # noqa: N806
177-
patternName = '1' # noqa: N806
178194
seriesName = 'WindForceSeries_' + str(floor) + direction # noqa: N806
179195
patternName = 'WindForcePattern_' + str(floor) + direction # noqa: N806
180196

181197
pattern = {
182198
'name': patternName,
183199
'timeSeries': seriesName,
184200
'numSteps': len(force.X),
185-
'dT': 0.01,
201+
'dT': dt,
186202
'type': 'WindFloorLoad',
187203
'floor': str(floor),
188204
'story': str(floor),
@@ -196,8 +212,8 @@ def addFloorForceToEvent( # noqa: N802
196212
'dof': directionToDof(direction),
197213
'floor': str(floor),
198214
'story': str(floor),
199-
'dT': 0.01,
200-
'dt': 0.01,
215+
'dT': dt,
216+
'dt': dt,
201217
'numSteps': len(force.X),
202218
'data': force.X,
203219
}
@@ -242,8 +258,8 @@ def writeEVENT(forces, eventFilePath='EVENT.json', floorsCount=1): # noqa: N802
242258
'timeSeries': timeSeriesArray,
243259
'pressure': pressure,
244260
'numSteps': len(forces[0].X),
245-
'dT': 1.0,
246-
'dt': 1.0,
261+
'dT': dt,
262+
'dt': dt,
247263
'units': {'force': 'Newton', 'length': 'Meter', 'time': 'Sec'},
248264
}
249265

@@ -341,13 +357,19 @@ def main():
341357
configFilename = event['configFile'] # noqa: N816
342358
bathymetryFilename = event['bathymetryFile'] # noqa: N816
343359
waveFilename = event['waveFile'] # noqa: N816
360+
# Check for event['config']['dt'] in the event file
361+
# and set dt to the value in the event file
362+
# if not found, set dt to 0.01
363+
dt = event['config']['dt'] if 'dt' in event['config'] else 0.01
344364

345365
print('Running Celeris with script:', scriptName) # noqa: T201
346366
print('Running Celeris with directory:', caseDirectory) # noqa: T201
347367
print('Running Celeris with config file:', configFilename) # noqa: T201
348368
print('Running Celeris with bathymetry:', bathymetryFilename) # noqa: T201
349369
print('Running Celeris with waves:', waveFilename) # noqa: T201
350370

371+
floorsCount = 1 # noqa: N816
372+
351373
if arguments.getRV == True: # noqa: E712
352374
print('RVs requested') # noqa: T201
353375
# Read the number of floors
@@ -413,7 +435,6 @@ def main():
413435
)
414436

415437
forces = []
416-
floorsCount = 1 # noqa: N816
417438
for i in range(floorsCount):
418439
forces.append(FloorForces(recorderID=(i + 1)))
419440

modules/createEVENT/Celeris/celeris/runner.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from celeris.solver import * # noqa: F403
66
from celeris.utils import * # noqa: F403
77
from taichi import tools # For saving images
8-
98
# Done at top of translation unit for now, clean-up later - JB
109
base_frame_dir = './plots/' # ! Assumes we are in CelerisAi/ directory
1110
os.makedirs( # noqa: PTH103
@@ -72,8 +71,8 @@ def Evolve_0(self): # noqa: N802, D102
7271

7372
def Evolve_Steps(self, step=0): # noqa: C901, N802, D102
7473
i = step
75-
76-
self.solver.Pass1()
74+
self.solver.update_step()
75+
self.solver.Pass1(int(i))
7776

7877
if self.solver.useSedTransModel:
7978
self.solver.Pass1_SedTrans()
@@ -125,7 +124,7 @@ def Evolve_Steps(self, step=0): # noqa: C901, N802, D102
125124
src=self.solver.NewState_Sed, dst=self.solver.State_Sed
126125
)
127126

128-
self.solver.Pass1()
127+
self.solver.Pass1(int(i))
129128

130129
if self.solver.useSedTransModel:
131130
self.solver.Pass1_SedTrans()
@@ -545,6 +544,8 @@ def Evolve_Display( # noqa: C901, N802, D102
545544

546545
start_time = time.time()
547546

547+
self.solver.overwrite_force()
548+
548549
while window.running:
549550
# self.paint()
550551
# self.paint_new()
@@ -569,6 +570,8 @@ def Evolve_Display( # noqa: C901, N802, D102
569570
) # using the Taichi tensors to render the image
570571
self.Evolve_Steps(i)
571572

573+
window.line(self.solver.force_sensor_begin_scaled, self.solver.force_sensor_end_scaled, radius=1, color=0x39FF14)
574+
572575
self.buffer_step = 1
573576
self.render_step = 10
574577
self.image_step = 100
@@ -635,7 +638,11 @@ def Evolve_Display( # noqa: C901, N802, D102
635638
# Improve the performance.The visualization is done only every 5 timesteps
636639
window.show()
637640

638-
if i > self.maxsteps:
641+
self.output_forces = True
642+
if (self.output_forces):
643+
self.solver.write_hydrostatic_force()
644+
645+
if i > self.maxsteps:
639646
if self.saveimg:
640647
print('Creating GIF...') # noqa: T201
641648
if frame_paths: # Check if there are frames to create a GIF

modules/createEVENT/Celeris/celeris/solver.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import matplotlib.colors as clr
44
import matplotlib.pyplot as plt
55
import numpy as np
6+
from bresenham import bresenham
7+
import sys
68
import taichi as ti
79
import taichi.math as tm
810
from celeris.utils import (
@@ -233,7 +235,35 @@ def __init__( # noqa: C901, PLR0913, PLR0915
233235
self.dzdt_F_coef = dzdt_F_coef
234236
self.dzdt_I_coef = dzdt_I_coef
235237

238+
self.force_sensor_begin_scaled = [0.0, 0.0]
239+
self.force_sensor_end_scaled = [1.0, 1.0]
240+
self.force_sensor_begin_pixel = [0.0, 0.0]
241+
self.force_sensor_end_pixel = [1.0, 1.0]
242+
self.hydrostatic_forces = ti.field(dtype=ti.f32, shape=(self.maxsteps))
243+
self.hydrostatic_forces_from_numpy = ti.field(dtype=ti.f32, shape=(self.maxsteps))
244+
self.hydrostatic_forces.fill(-1.0)
245+
self.hydrostatic_forces_numpy = np.zeros((self.maxsteps))
246+
self.hydrostatic_forces_list = []
247+
self.hydrostatic_force = ti.field(dtype=ti.f32, shape=(1))
248+
# self.hydrostatic_forces_numpy = np.zeros((1, self.maxsteps))
249+
self.step = 0
236250
if self.bc.celeris == True: # noqa: E712
251+
if checjson('force_sensor_begin', self.bc.configfile) == 1:
252+
self.force_sensor_begin = self.bc.configfile['force_sensor_begin']
253+
self.force_sensor_begin_scaled[0] = self.force_sensor_begin[0] / self.bc.configfile['WIDTH']
254+
self.force_sensor_begin_scaled[1] = self.force_sensor_begin[1] / self.bc.configfile['HEIGHT']
255+
else:
256+
self.force_sensor_begin = [0.0, 0.0]
257+
self.force_sensor_begin_scaled = [0.0, 0.0]
258+
259+
if checjson('force_sensor_end', self.bc.configfile) == 1:
260+
self.force_sensor_end = self.bc.configfile['force_sensor_end']
261+
self.force_sensor_end_scaled[0] = self.force_sensor_end[0] / self.bc.configfile['WIDTH']
262+
self.force_sensor_end_scaled[1] = self.force_sensor_end[1] / self.bc.configfile['HEIGHT']
263+
else:
264+
self.force_sensor_end = [self.bc.configfile['WIDTH'], self.bc.configfile['HEIGHT']]
265+
self.force_sensor_end_scaled = [1.0, 1.0]
266+
237267
if checjson('whiteWaterDecayRate', self.bc.configfile) == 1:
238268
self.whiteWaterDecayRate = float(
239269
self.bc.configfile['whiteWaterDecayRate']
@@ -969,10 +999,23 @@ def tridiag_coeffs_Y(self): # noqa: N802, D102
969999
self.coefMaty[i, j] = ti.Vector([a, b, c, 0.0], self.precision)
9701000

9711001
@ti.kernel
972-
def Pass1(self): # noqa: N802, D102
1002+
def Pass1(self, step: int): # noqa: N802, D102
9731003
# PASS 0 and Pass1 - edge value construction
9741004
# using Generalized minmod limiter
9751005
zro = ti.Vector([0.0, 0.0, 0.0, 0.0], self.precision)
1006+
1007+
# Bresenham's line algorithm
1008+
# bresenham_list = list(
1009+
# bresenham(
1010+
# self.force_sensor_begin[0],
1011+
# self.force_sensor_begin[1],
1012+
# self.force_sensor_end[0],
1013+
# self.force_sensor_end[1],
1014+
# )
1015+
# )
1016+
# print("Bresenham List: ", bresenham_list)
1017+
hydrostatic_force = 0.0
1018+
9761019
for i, j in self.State:
9771020
# Compute the coordinates of the neighbors
9781021
rightIdx = ti.min(i + 1, self.nx - 1) # noqa: N806
@@ -1128,6 +1171,41 @@ def Pass1(self): # noqa: N802, D102
11281171
[maxInundatedDepth, maxVelocityU, maxVelocityV, maxVelocityC],
11291172
self.precision,
11301173
)
1174+
1175+
if (j >= self.force_sensor_begin[1] and j <= self.force_sensor_end[1]) and (i >= self.force_sensor_begin[0] and i <= self.force_sensor_end[0]):
1176+
# print("Calculating hydrostatic force at: ", i, j)
1177+
# Calculate the hydrostatic force
1178+
# Assuming a simple hydrostatic force calculation
1179+
# hydrostatic_force = 1/2 density * g * w * h
1180+
# where density is assumed to be 1 for simplicity
1181+
# and h is the water height at (i, j)
1182+
hsqr = float(self.H[i, j][0]) * float(self.H[i, j][0])
1183+
hydrostatic_force += 1000 * 0.5 * 1000.0 * float(self.g) * float(hsqr) * float(self.dy)
1184+
1185+
self.hydrostatic_forces[int(0)] = float(hydrostatic_force)
1186+
self.hydrostatic_forces[int(step)] = float(hydrostatic_force)
1187+
1188+
1189+
def overwrite_force(self):
1190+
# open forces.evt to overwrite
1191+
print("Overwriting forces.evt")
1192+
with open("forces.evt", "w") as f:
1193+
max_steps = 10000 # self.hydrostatic_forces.shape[0]
1194+
for i in range(max_steps):
1195+
if (i < max_steps - 1):
1196+
f.write(f"{0.0} ")
1197+
else:
1198+
f.write(f"{0.0}\n")
1199+
1200+
1201+
def write_hydrostatic_force(self):
1202+
# open forces.evt to append
1203+
with open("forces.evt", "a") as f:
1204+
f.write(f"{self.hydrostatic_forces[int(0)]} ")
1205+
1206+
def update_step(self):
1207+
self.step += 1
1208+
11311209

11321210
@ti.kernel
11331211
def Pass1_SedTrans(self): # noqa: N802, D102

0 commit comments

Comments
 (0)