Skip to content

Commit d08f623

Browse files
authored
Merge pull request #400 from JustinBonus/master
Allow Celeris to use more flexible input files
2 parents ff2d32c + 43ee21f commit d08f623

File tree

6 files changed

+159
-35
lines changed

6 files changed

+159
-35
lines changed

modules/createEVENT/Celeris/Celeris.py

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,63 @@
4848
import taichi as ti
4949
except ImportError:
5050
print('Taichi is not installed. Please install it using "pip install taichi".') # noqa: T201
51+
print('Attempting to install taichi automatically for you...') # noqa: T201
5152
print() # noqa: T201
52-
subprocess.run([sys.executable, '-m', 'pip', 'install', 'taichi'], check=False) # noqa: S603
53+
# SYSEXECUTABLE = sys.executable # noqa: N806
54+
# PYTHONPATH = os.environ.get('PYTHONPATH', '') # noqa: N806
55+
# PYTHONHOME = os.environ.get('PYTHONHOME', '') # noqa: N806
56+
# PYTHONSTARTUP = os.environ.get('PYTHONSTARTUP', '') # noqa: N806
57+
# VIRTUAL_ENV = os.environ.get('VIRTUAL_ENV', '') # noqa: N806
58+
# PIP_REQUIRE_VIRTUALENV = os.environ.get('PIP_REQUIRE_VIRTUALENV', '') # noqa: N806
59+
# print('If you are using a virtual environment, make sure it is activated.') # noqa: T201
60+
# print('Python executable being used to install taichi (i.e., sys.excutable):', SYSEXECUTABLE) # noqa: T201
61+
# print('PYTHONPATH:', PYTHONPATH)
62+
# print('PYTHONHOME:', PYTHONHOME) # noqa: T201
63+
# print('PYTHONSTARTUP:', PYTHONSTARTUP)
64+
65+
# if VIRTUAL_ENV:
66+
# print('VIRTUAL_ENV:', VIRTUAL_ENV)
67+
# else:
68+
# print('No virtual environment detected. If you are using one, please activate it before running this script.')
69+
70+
# if PIP_REQUIRE_VIRTUALENV:
71+
# print('PIP_REQUIRE_VIRTUALENV:', PIP_REQUIRE_VIRTUALENV)
72+
# else:
73+
# print('No PIP_REQUIRE_VIRTUALENV environment variable detected. If you are using a virtual environment, please activate it before running this script.')
74+
75+
print()
76+
5377
try:
54-
import taichi as ti
55-
except ImportError:
56-
print('Taichi installation failed. Please install it manually.') # noqa: T201
57-
sys.exit(1)
58-
print('Taichi is installed successfully.') # noqa: T201
78+
print('Try to install with $ python -m pip install taichi')
79+
subprocess.run([sys.executable, '-m', 'pip', 'install', 'taichi'], check=False) # noqa: S603
80+
try:
81+
import taichi as ti
82+
except ImportError:
83+
print('Taichi installation failed. Please install it manually.') # noqa: T201
84+
# sys.exit(1)
85+
except:
86+
# Might be user permission issue
87+
print('Try to install with $ python -m pip install --user taichi') # noqa: T201
88+
try:
89+
subprocess.run([sys.executable, '-m', 'pip', 'install', '--user', 'taichi'], check=False) # noqa: S603
90+
try:
91+
import taichi as ti
92+
except ImportError:
93+
print('Taichi installation failed. Please install it manually.')
94+
# sys.exit(1)
95+
except:
96+
print('Try to install with $ pip install taichi') # noqa: T201
97+
try:
98+
subprocess.run(['pip', 'install', 'taichi'], check=False) # noqa: S603
99+
try:
100+
import taichi as ti
101+
except ImportError:
102+
print('Taichi installation failed. Please install it manually.')
103+
# sys.exit(1)
104+
except:
105+
print('ERROR: Cannot install taichi. There is likely an issue with you Python environment, OS, GLIBC, or pip installation.') # noqa: T201
106+
print('INFO: Please manually install taichi into the Python environment specified in the desktop applications Files > Preferences tab')
107+
sys.exit(1)
59108
print() # noqa: T201
60109

61110

@@ -350,10 +399,52 @@ def main():
350399
for event in evt['Events']:
351400
# Redesign the input structure in backend CelerisAi later.
352401
# For now assume waveFile, bathymetryFile, configFile, etc. are in the same directory.
353-
caseDirectory = event['configFilePath'] # noqa: N816
402+
# caseDirectory = event['configFilePath'] # noqa: N816
403+
caseDirectory = '.'
404+
configDirectory = event['configFilePath'] # noqa: N816
354405
configFilename = event['configFile'] # noqa: N816
406+
bathymetryDirectory = event['bathymetryFilePath'] # noqa: N816
355407
bathymetryFilename = event['bathymetryFile'] # noqa: N816
408+
waveDirectory = event['waveFilePath'] # noqa: N816
356409
waveFilename = event['waveFile'] # noqa: N816
410+
411+
# configFilename = os.path.join( # noqa: PTH118
412+
# configDirectory, configFilename
413+
# ) # noqa: N816, PTH118
414+
# bathymetryFilename = os.path.join( # noqa: PTH118
415+
# bathymetryDirectory, bathymetryFilename
416+
# ) # noqa: N816, PTH118
417+
# waveFilename = os.path.join( # noqa: PTH118
418+
# waveDirectory, waveFilename
419+
# ) # noqa: N816, PTH118
420+
421+
# Check if the config file exists
422+
if not os.path.exists(configFilename): # noqa: PTH110
423+
print('Config file does not exist:', configFilename)
424+
# Use default config file
425+
configFilename = os.path.join( # noqa: PTH118
426+
caseDirectory, 'config.json'
427+
) # noqa: N816, PTH118
428+
print('Using default config file:', configFilename) # noqa: T201
429+
430+
# Check if the bathymetry file exists
431+
if not os.path.exists(bathymetryFilename):
432+
print('Bathymetry file does not exist:', bathymetryFilename) # noqa: T201
433+
# Use default bathymetry file
434+
bathymetryFilename = os.path.join( # noqa: PTH118
435+
caseDirectory, 'bathy.txt'
436+
) # noqa: N816, PTH118
437+
print('Using default bathymetry file:', bathymetryFilename)
438+
439+
# Check if the wave file exists
440+
if not os.path.exists(waveFilename): # noqa: PTH110
441+
print('Wave file does not exist:', waveFilename) # noqa: T201
442+
# Use default wave file
443+
waveFilename = os.path.join( # noqa: PTH118
444+
caseDirectory, 'waves.txt'
445+
)
446+
print('Using default wave file:', waveFilename) # noqa: T201
447+
357448
# Determine dt for the force time series
358449
# Try to compute using Courant_num (CFL), otherwise look for dt in the config
359450
if 'Courant_num' in event['config']:

modules/createEVENT/Celeris/celeris/runner.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -532,15 +532,20 @@ def Evolve_1D_Display(self):
532532
while window.running:
533533
self.eta_paint()
534534
if use_ggui:
535-
canvas.circles(self.eta1D,radius=0.005,color = (0., 150/255., 255./255))
536-
canvas.lines(self.bottom1D,width=0.01,indices=self.indexbottom1D,color = (128/255., 0.0, 0.))
535+
try:
536+
canvas.circles(self.eta1D,radius=0.005,color = (0., 150/255., 255./255))
537+
canvas.lines(self.bottom1D,width=0.01,indices=self.indexbottom1D,color = (128/255., 0.0, 0.))
538+
except Exception as e:
539+
print(f"Error in GGUI circles / lines rendering: {e}")
537540
else:
538-
for ii in range(self.solver.nx):
539-
window.circle(pos=[self.eta1D[ii][0], self.eta1D[ii][1]], radius=1, color=0x00FFFF)
540-
if ii >= self.solver.nx - 1:
541-
continue
542-
window.line(self.bottom1D[ii], self.bottom1D[ii+1], radius=1, color = 0x39FF14)
543-
541+
try:
542+
for ii in range(self.solver.nx):
543+
window.circle(pos=[self.eta1D[ii][0], self.eta1D[ii][1]], radius=1, color=0x00FFFF)
544+
if ii >= self.solver.nx - 1:
545+
continue
546+
window.line(self.bottom1D[ii], self.bottom1D[ii+1], radius=1, color = 0x39FF14)
547+
except Exception as e:
548+
print(f"Error in legacy GUI circle / line rendering: {e}")
544549
self.Evolve_Steps(i)
545550

546551
if i==1 or (i%100)==0:
@@ -685,10 +690,12 @@ def Evolve_Display( # noqa: C901, N802, D102
685690
) # using the Taichi tensors to render the image
686691
self.Evolve_Steps(i)
687692

688-
window.line(self.solver.force_sensor_begin_scaled, self.solver.force_sensor_end_scaled, radius=1, color=0x39FF14)
689-
for k in range(self.solver.num_wave_gauges):
690-
window.circle(pos=[self.solver.wave_gauge_scaled[int(k),int(0)], self.solver.wave_gauge_scaled[int(k),int(1)]], radius=2, color=0xFF5733)
691-
693+
try:
694+
window.line(self.solver.force_sensor_begin_scaled, self.solver.force_sensor_end_scaled, radius=1, color=0x39FF14)
695+
for k in range(self.solver.num_wave_gauges):
696+
window.circle(pos=[self.solver.wave_gauge_scaled[int(k),int(0)], self.solver.wave_gauge_scaled[int(k),int(1)]], radius=2, color=0xFF5733)
697+
except Exception as e: # noqa: BLE001
698+
print(f'Error in rendering sensors or wave gauges using line / circle: {e}') # noqa:
692699

693700
if i == self.buffer_step:
694701
start_time = (

modules/createEVENT/Celeris/setrun.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@
1313

1414

1515
def main(): # noqa: C901, D103
16-
# 1) Set the topography data
17-
18-
directoryPath = './examples/CrescentCity' # noqa: N806
19-
configFilename = 'config.json' # noqa: N806
20-
bathymetryFilename = 'bathy.txt' # noqa: N806
21-
waveFilename = 'waves.txt' # noqa: N806
22-
2316
parser = argparse.ArgumentParser(
2417
description='Run Celeris simulation with specified inputs.'
2518
)
@@ -56,13 +49,18 @@ def main(): # noqa: C901, D103
5649
# Parse arguments
5750
args = parser.parse_args()
5851

59-
# Print received arguments
52+
# Resolve file paths
53+
config_path = args.config if os.path.isabs(args.config) else os.path.join(args.directory, args.config)
54+
bathymetry_path = args.bathymetry if os.path.isabs(args.bathymetry) else os.path.join(args.directory, args.bathymetry)
55+
wave_path = args.waves if os.path.isabs(args.waves) else os.path.join(args.directory, args.waves)
56+
57+
# Print resolved settings
6058
print('Running Celeris with the following settings:')
6159
print(' Directory:', args.directory)
62-
print(' Config file:', args.config)
63-
print(' Bathymetry file:', args.bathymetry)
64-
print(' Wave file:', args.waves)
65-
60+
print(' Config file:', config_path)
61+
print(' Bathymetry file:', bathymetry_path)
62+
print(' Wave file:', wave_path)
63+
6664
baty = Topodata(
6765
datatype='celeris',
6866
path=args.directory,

modules/createEVENT/TaichiEvent/TaichiEvent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(self, recorderID=-1): # noqa: N803
5858
continue
5959
# Assume there is no header in the file
6060
# Assume recorder IDs are sequential, starting from 1
61-
if (j + 1) == recorderID:
61+
if (j) == recorderID:
6262
# Strip away leading / trailing white-space,
6363
# Delimit by regex to capture " ", \s, " ", tabs, etc.
6464
# Each value should be a number, rep. the force on recorder j at a time-step i

modules/createEVENT/TaichiEvent/pbf2d.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Taichi implementation by Ye Kuang (k-ye)
33

44
import math
5-
5+
import os
66
import numpy as np
77

88
import taichi as ti
@@ -26,6 +26,7 @@ def round_up(f, s):
2626
grid_size = (round_up(boundary[0], 1), round_up(boundary[1], 1))
2727

2828
dim = 2
29+
max_frames = 1800
2930
bg_color = 0x112F41
3031
particle_color = 0x068587
3132
boundary_color = 0xEBACA2
@@ -64,6 +65,7 @@ def round_up(f, s):
6465
position_deltas = ti.Vector.field(dim, float)
6566
# 0: x-pos, 1: timestep in sin()
6667
board_states = ti.Vector.field(2, float)
68+
wall_force = ti.Vector.field(dim, float, shape=())
6769

6870
ti.root.dense(ti.i, num_particles).place(old_positions, positions, velocities)
6971
grid_snode = ti.root.dense(ti.ij, grid_size)
@@ -122,8 +124,10 @@ def confine_position_to_boundary(p):
122124
bmin = particle_radius_in_world
123125
bmax = ti.Vector([board_states[None][0], boundary[1]]) - particle_radius_in_world
124126
for i in ti.static(range(dim)):
125-
# Use randomness to prevent particles from sticking into each other after clamping
126127
if p[i] <= bmin:
128+
diff = bmin - p[i]
129+
if i == 0:
130+
ti.atomic_add(wall_force[None][i], 1000.0 * diff / time_delta)
127131
p[i] = bmin + epsilon * ti.random()
128132
elif bmax[i] <= p[i]:
129133
p[i] = bmax[i] - epsilon * ti.random()
@@ -145,6 +149,7 @@ def move_board():
145149

146150
@ti.kernel
147151
def prologue():
152+
wall_force[None] = ti.Vector([0.0, 0.0]) # ← Clear previous step force
148153
# save old positions
149154
for i in positions:
150155
old_positions[i] = positions[i]
@@ -294,13 +299,36 @@ def main():
294299
init_particles()
295300
print(f"boundary={boundary} grid={grid_size} cell_size={cell_size}")
296301
gui = ti.GUI("PBF2D", screen_res)
297-
while gui.running and not gui.get_event(gui.ESCAPE):
302+
303+
# Prepare force tracking
304+
force_values = []
305+
time_values = []
306+
307+
# Output file
308+
force_filename = "forces.evt"
309+
if os.path.exists(force_filename):
310+
os.remove(force_filename) # clean if it exists
311+
312+
while gui.running and gui.frame < max_frames and not gui.get_event(gui.ESCAPE):
298313
move_board()
299314
run_pbf()
315+
316+
# Record time and force
317+
current_time = gui.frame * time_delta
318+
time_values.append(current_time)
319+
fx = wall_force.to_numpy()[None][0].item(0) # x-component of the wall force
320+
force_values.append(fx)
321+
300322
if gui.frame % 20 == 1:
301323
print_stats()
324+
print("Left wall force:", fx)
325+
302326
render(gui)
303327

328+
# Write to file at end
329+
with open(force_filename, "w") as f:
330+
f.write(" ".join("0.0" for _ in force_values) + "\n")
331+
f.write(" ".join(f"{fval:.5f}" for fval in force_values) + "\n")
304332

305333
if __name__ == "__main__":
306334
main()

modules/performFEM/OpenSees/createOpenSeesDriver.cpp

100755100644
File mode changed.

0 commit comments

Comments
 (0)