Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 98 additions & 7 deletions modules/createEVENT/Celeris/Celeris.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,63 @@
import taichi as ti
except ImportError:
print('Taichi is not installed. Please install it using "pip install taichi".') # noqa: T201
print('Attempting to install taichi automatically for you...') # noqa: T201
print() # noqa: T201
subprocess.run([sys.executable, '-m', 'pip', 'install', 'taichi'], check=False) # noqa: S603
# SYSEXECUTABLE = sys.executable # noqa: N806
# PYTHONPATH = os.environ.get('PYTHONPATH', '') # noqa: N806
# PYTHONHOME = os.environ.get('PYTHONHOME', '') # noqa: N806
# PYTHONSTARTUP = os.environ.get('PYTHONSTARTUP', '') # noqa: N806
# VIRTUAL_ENV = os.environ.get('VIRTUAL_ENV', '') # noqa: N806
# PIP_REQUIRE_VIRTUALENV = os.environ.get('PIP_REQUIRE_VIRTUALENV', '') # noqa: N806
# print('If you are using a virtual environment, make sure it is activated.') # noqa: T201
# print('Python executable being used to install taichi (i.e., sys.excutable):', SYSEXECUTABLE) # noqa: T201

Check failure on line 60 in modules/createEVENT/Celeris/Celeris.py

View workflow job for this annotation

GitHub Actions / spell-check

excutable ==> executable
# print('PYTHONPATH:', PYTHONPATH)
# print('PYTHONHOME:', PYTHONHOME) # noqa: T201
# print('PYTHONSTARTUP:', PYTHONSTARTUP)

# if VIRTUAL_ENV:
# print('VIRTUAL_ENV:', VIRTUAL_ENV)
# else:
# print('No virtual environment detected. If you are using one, please activate it before running this script.')

# if PIP_REQUIRE_VIRTUALENV:
# print('PIP_REQUIRE_VIRTUALENV:', PIP_REQUIRE_VIRTUALENV)
# else:
# print('No PIP_REQUIRE_VIRTUALENV environment variable detected. If you are using a virtual environment, please activate it before running this script.')

print()

try:
import taichi as ti
except ImportError:
print('Taichi installation failed. Please install it manually.') # noqa: T201
sys.exit(1)
print('Taichi is installed successfully.') # noqa: T201
print('Try to install with $ python -m pip install taichi')
subprocess.run([sys.executable, '-m', 'pip', 'install', 'taichi'], check=False) # noqa: S603
try:
import taichi as ti
except ImportError:
print('Taichi installation failed. Please install it manually.') # noqa: T201
# sys.exit(1)
except:
# Might be user permission issue
print('Try to install with $ python -m pip install --user taichi') # noqa: T201
try:
subprocess.run([sys.executable, '-m', 'pip', 'install', '--user', 'taichi'], check=False) # noqa: S603
try:
import taichi as ti
except ImportError:
print('Taichi installation failed. Please install it manually.')
# sys.exit(1)
except:
print('Try to install with $ pip install taichi') # noqa: T201
try:
subprocess.run(['pip', 'install', 'taichi'], check=False) # noqa: S603
try:
import taichi as ti
except ImportError:
print('Taichi installation failed. Please install it manually.')
# sys.exit(1)
except:
print('ERROR: Cannot install taichi. There is likely an issue with you Python environment, OS, GLIBC, or pip installation.') # noqa: T201
print('INFO: Please manually install taichi into the Python environment specified in the desktop applications Files > Preferences tab')
sys.exit(1)
print() # noqa: T201


Expand Down Expand Up @@ -350,10 +399,52 @@
for event in evt['Events']:
# Redesign the input structure in backend CelerisAi later.
# For now assume waveFile, bathymetryFile, configFile, etc. are in the same directory.
caseDirectory = event['configFilePath'] # noqa: N816
# caseDirectory = event['configFilePath'] # noqa: N816
caseDirectory = '.'
configDirectory = event['configFilePath'] # noqa: N816
configFilename = event['configFile'] # noqa: N816
bathymetryDirectory = event['bathymetryFilePath'] # noqa: N816
bathymetryFilename = event['bathymetryFile'] # noqa: N816
waveDirectory = event['waveFilePath'] # noqa: N816
waveFilename = event['waveFile'] # noqa: N816

# configFilename = os.path.join( # noqa: PTH118
# configDirectory, configFilename
# ) # noqa: N816, PTH118
# bathymetryFilename = os.path.join( # noqa: PTH118
# bathymetryDirectory, bathymetryFilename
# ) # noqa: N816, PTH118
# waveFilename = os.path.join( # noqa: PTH118
# waveDirectory, waveFilename
# ) # noqa: N816, PTH118

# Check if the config file exists
if not os.path.exists(configFilename): # noqa: PTH110
print('Config file does not exist:', configFilename)
# Use default config file
configFilename = os.path.join( # noqa: PTH118
caseDirectory, 'config.json'
) # noqa: N816, PTH118
print('Using default config file:', configFilename) # noqa: T201

# Check if the bathymetry file exists
if not os.path.exists(bathymetryFilename):
print('Bathymetry file does not exist:', bathymetryFilename) # noqa: T201
# Use default bathymetry file
bathymetryFilename = os.path.join( # noqa: PTH118
caseDirectory, 'bathy.txt'
) # noqa: N816, PTH118
print('Using default bathymetry file:', bathymetryFilename)

# Check if the wave file exists
if not os.path.exists(waveFilename): # noqa: PTH110
print('Wave file does not exist:', waveFilename) # noqa: T201
# Use default wave file
waveFilename = os.path.join( # noqa: PTH118
caseDirectory, 'waves.txt'
)
print('Using default wave file:', waveFilename) # noqa: T201

# Determine dt for the force time series
# Try to compute using Courant_num (CFL), otherwise look for dt in the config
if 'Courant_num' in event['config']:
Expand Down
31 changes: 19 additions & 12 deletions modules/createEVENT/Celeris/celeris/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,15 +532,20 @@ def Evolve_1D_Display(self):
while window.running:
self.eta_paint()
if use_ggui:
canvas.circles(self.eta1D,radius=0.005,color = (0., 150/255., 255./255))
canvas.lines(self.bottom1D,width=0.01,indices=self.indexbottom1D,color = (128/255., 0.0, 0.))
try:
canvas.circles(self.eta1D,radius=0.005,color = (0., 150/255., 255./255))
canvas.lines(self.bottom1D,width=0.01,indices=self.indexbottom1D,color = (128/255., 0.0, 0.))
except Exception as e:
print(f"Error in GGUI circles / lines rendering: {e}")
else:
for ii in range(self.solver.nx):
window.circle(pos=[self.eta1D[ii][0], self.eta1D[ii][1]], radius=1, color=0x00FFFF)
if ii >= self.solver.nx - 1:
continue
window.line(self.bottom1D[ii], self.bottom1D[ii+1], radius=1, color = 0x39FF14)

try:
for ii in range(self.solver.nx):
window.circle(pos=[self.eta1D[ii][0], self.eta1D[ii][1]], radius=1, color=0x00FFFF)
if ii >= self.solver.nx - 1:
continue
window.line(self.bottom1D[ii], self.bottom1D[ii+1], radius=1, color = 0x39FF14)
except Exception as e:
print(f"Error in legacy GUI circle / line rendering: {e}")
self.Evolve_Steps(i)

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

window.line(self.solver.force_sensor_begin_scaled, self.solver.force_sensor_end_scaled, radius=1, color=0x39FF14)
for k in range(self.solver.num_wave_gauges):
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)

try:
window.line(self.solver.force_sensor_begin_scaled, self.solver.force_sensor_end_scaled, radius=1, color=0x39FF14)
for k in range(self.solver.num_wave_gauges):
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)
except Exception as e: # noqa: BLE001
print(f'Error in rendering sensors or wave gauges using line / circle: {e}') # noqa:

if i == self.buffer_step:
start_time = (
Expand Down
22 changes: 10 additions & 12 deletions modules/createEVENT/Celeris/setrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@


def main(): # noqa: C901, D103
# 1) Set the topography data

directoryPath = './examples/CrescentCity' # noqa: N806
configFilename = 'config.json' # noqa: N806
bathymetryFilename = 'bathy.txt' # noqa: N806
waveFilename = 'waves.txt' # noqa: N806

parser = argparse.ArgumentParser(
description='Run Celeris simulation with specified inputs.'
)
Expand Down Expand Up @@ -56,13 +49,18 @@ def main(): # noqa: C901, D103
# Parse arguments
args = parser.parse_args()

# Print received arguments
# Resolve file paths
config_path = args.config if os.path.isabs(args.config) else os.path.join(args.directory, args.config)
bathymetry_path = args.bathymetry if os.path.isabs(args.bathymetry) else os.path.join(args.directory, args.bathymetry)
wave_path = args.waves if os.path.isabs(args.waves) else os.path.join(args.directory, args.waves)

# Print resolved settings
print('Running Celeris with the following settings:')
print(' Directory:', args.directory)
print(' Config file:', args.config)
print(' Bathymetry file:', args.bathymetry)
print(' Wave file:', args.waves)

print(' Config file:', config_path)
print(' Bathymetry file:', bathymetry_path)
print(' Wave file:', wave_path)
baty = Topodata(
datatype='celeris',
path=args.directory,
Expand Down
2 changes: 1 addition & 1 deletion modules/createEVENT/TaichiEvent/TaichiEvent.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(self, recorderID=-1): # noqa: N803
continue
# Assume there is no header in the file
# Assume recorder IDs are sequential, starting from 1
if (j + 1) == recorderID:
if (j) == recorderID:
# Strip away leading / trailing white-space,
# Delimit by regex to capture " ", \s, " ", tabs, etc.
# Each value should be a number, rep. the force on recorder j at a time-step i
Expand Down
34 changes: 31 additions & 3 deletions modules/createEVENT/TaichiEvent/pbf2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Taichi implementation by Ye Kuang (k-ye)

import math

import os
import numpy as np

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

dim = 2
max_frames = 1800
bg_color = 0x112F41
particle_color = 0x068587
boundary_color = 0xEBACA2
Expand Down Expand Up @@ -64,6 +65,7 @@ def round_up(f, s):
position_deltas = ti.Vector.field(dim, float)
# 0: x-pos, 1: timestep in sin()
board_states = ti.Vector.field(2, float)
wall_force = ti.Vector.field(dim, float, shape=())

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

@ti.kernel
def prologue():
wall_force[None] = ti.Vector([0.0, 0.0]) # ← Clear previous step force
# save old positions
for i in positions:
old_positions[i] = positions[i]
Expand Down Expand Up @@ -294,13 +299,36 @@ def main():
init_particles()
print(f"boundary={boundary} grid={grid_size} cell_size={cell_size}")
gui = ti.GUI("PBF2D", screen_res)
while gui.running and not gui.get_event(gui.ESCAPE):

# Prepare force tracking
force_values = []
time_values = []

# Output file
force_filename = "forces.evt"
if os.path.exists(force_filename):
os.remove(force_filename) # clean if it exists

while gui.running and gui.frame < max_frames and not gui.get_event(gui.ESCAPE):
move_board()
run_pbf()

# Record time and force
current_time = gui.frame * time_delta
time_values.append(current_time)
fx = wall_force.to_numpy()[None][0].item(0) # x-component of the wall force
force_values.append(fx)

if gui.frame % 20 == 1:
print_stats()
print("Left wall force:", fx)

render(gui)

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

if __name__ == "__main__":
main()
Empty file modified modules/performFEM/OpenSees/createOpenSeesDriver.cpp
100755 → 100644
Empty file.
Loading