Add one line installer and pulsatile case - #6
Open
Eleven7825 wants to merge 53 commits into
Open
Conversation
Eleven7825
commented
Feb 19, 2026
Contributor
- Add a one line installer for the svFSGe
- Add a pulsatile case using mean wss
- Add converted pulsatile Q waveform (pulsatile_flow.dat) from VMR source .flow files, converted from cm/s to mm/s to match kg/mm/s unit system - Update steady_full.xml inlet BC to use Unsteady time dependence with the pulsatile temporal values file - Add static BC file copy step in svfsi.py setup_files so pulsatile_flow.dat is staged into the run directory automatically - Include source .flow files from Vascular Model Repository Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Increase Number_of_time_steps from 10 to 960 (10 cardiac cycles at dt=0.01s) - Add run_fluid_only.py script for standalone fluid simulation without FSG coupling, handles mesh/BC file staging and runs svFSI directly Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Container named 'fsg-dev' now persists after exit - Rerunning the script reconnects to existing container - Uses 'sleep infinity' + 'docker exec' pattern for persistence - Updated pip install to use requirements.txt (includes meshio) - Shows container management commands on completion Users can now: - Exit and reconnect without losing setup - Stop/start the container as needed - See the container in 'docker ps -a' Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Instead of requiring requirements.txt, the script now has the package list hardcoded. This makes it work even if requirements.txt is missing or the repo state is inconsistent. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Creates a bootstrap script that can be downloaded and run via curl. Handles repo cloning and Docker setup in one command. Usage: curl -fsSL https://raw.githubusercontent.com/Eleven7825/svFSGe/master/scripts/install.sh | bash Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Prominently featured at the top of Quickstart section - Explains prerequisites and what the command does - Updated Quick Setup Script section to mention persistent container Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add setup_singularity.sh for automated Singularity environment setup - Add install_singularity.sh for one-command installation on HPC - Add run_simulation.sh helper script for easy simulation execution - Update README.md with HPC installation instructions - Support for read-only containers with user-space Python package installation - Include verification step to ensure all dependencies are properly installed
…ive VTU copying - Copies folder structure and all files except VTU/BIN from pulsatile/steady/gr_restart - Copies only last 400 pulsatile VTU files to minimize transfer size - Copies only last 10 steady VTU files - Excludes all gr_restart VTU files completely - Uses SSH ControlMaster for single authentication - Strips carriage returns from remote SSH output for proper path handling
…from the json file
…be read from the json file" This reverts commit 7c671a3.
…_full_coarse.json
Informational prints in extract_pulsatile_time_average and extract_pulsatile_amplitude are now gated behind verbose=False by default. Enable with "debug": true in the JSON config. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fsg.py/svfsi.py: add iqn_ils_debug option (off by default) to save V, W, Q, R, column counts before/after QR filtering, and cc coefficients each IQN-ILS call; saved to debug_qr.npy on archive - post.py: add plot_cc() to plot cc norm and heatmap with load-step transition lines; called automatically from main_arg when debug_qr.npy exists - in_sim/partitioned_full_steep.json: new steep profile case (nmax=5, profile_beta with beta_min=2/beta_max=10, iqn_ils_debug enabled) - in_svfsi_plus/gr_full_restart_steep.xml: solid XML with n_t_end=4 for steeper GR ramp (full load reached at t=3 out of 5 steps) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…verbose output - fsg.py/svfsi.py: save load step t and sub-iter n alongside each IQN-ILS debug entry, removing need for fragile formula to reconstruct transitions - post.py: derive transition lines directly from saved t array; fix path resolution for plot_cc in main_arg (two levels up from partitioned/converged) - svfsi.py: suppress "extracted from N geometries" print unless debug=true - in_sim/partitioned_full_debug.json: normal progressive profile case with iqn_ils_debug enabled for comparison against steep profile Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Draw a step line at ncols_after - 0.5 on the heatmap to clearly show the boundary between active coefficients and NaN, making filtering events (drops in the line) immediately visible. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When iqn_ils_reset=true, mat_V and mat_W are cleared at n=0 of each new load step so IQN-ILS starts from scratch without reusing vectors from previous time steps. Default is false (existing behavior). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fsg.py: add iqn_ils_debug saving (cc, t, n per call), iqn_ils_reset flag to clear history vectors at each new load step, fallback to relaxation when mat_V is empty after reset - post.py: add plot_cc() with 3-panel GridSpec figure (|c| heatmap log scale, ||c|| norm, coupling residual before/after IQN update); called from main_arg; use pcolormesh + dedicated colorbar column to fix x-axis alignment - in_sim/partitioned_full_steep.json: set q=5, reset=true, profile_beta=true
…ot_cc - Dummy invisible subplots in colorbar column for all rows so column widths match - MaxNLocator(integer=True) for integer x-axis ticks - Fix sharex() call (replace deprecated get_shared_x_axes().join()) - Remove legend from heatmap and norm subplots; residual shows only before/after/tol - Sparser y-ticks on heatmap (every 2)
Saves and restores all state needed to resume from a converged load step: - IQN-ILS history (mat_W, mat_V, dk, res, dtk) - Coupling error and relaxation history (err, omega) - Current and all previous converged solutions - svFSI binary restart files (stFile_last.bin) snapshotted at checkpoint time to avoid corruption from subsequent failed load steps Usage: set "save_restart": true in JSON to enable checkpointing. Restart via "restart": "path/to/restart.npz" in JSON or -restart CLI flag. Tested on steady case (nmax=2 + restart to nmax=3): sub-iteration counts, IQN-ILS residuals, and displacement fields match to floating-point precision.
The load profile (how the G&R insult is ramped over the load steps) was
hard-coded inside svMultiPhysics' gr_equilibrated.cpp and could not be
changed from here. Expose it through the GR_equilibrated material params
and inject it from the simulation JSON:
- svfsi.py set_gr_load(): reads an optional "gr_load" section and patches
the solid solver XML (<load_profile>/<load_steep>/<load_file>) per run,
using the same regex-on-XML approach as the pulsatile step-count patch.
profile: linear | tanh (default) | power | file
steep: tanh steepness / power exponent
curve: for "file", the load factor per step ([step, factor] pairs or
a plain list); step 0 = pre-stress, 1..nloads = G&R loads.
Omitting "gr_load" leaves the XML untouched -> svFSI defaults (tanh, 2.0),
reproducing the historical behavior.
- Rename the top-level G&R load-step count nmax -> nloads (it clashed with
coup["nmax"], the coupling-iteration cap). The old "nmax" is still
accepted for backward compatibility. coup["nmax"] is unchanged.
Verified: fsg.py in_sim/partitioned_test.json matches test_reference/nmax_2
with both the tanh default and an equivalent file curve.
Requires the matching gr_equilibrated.cpp parser changes in svMultiPhysics
(FSGe branch); without them an older binary rejects the injected XML tags.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the per-sub-iteration MESH+FLUID svFSI solves with a DeepONet WSS + pressure surrogate. neural_operator.py: - New "direct" backend (lddmm_backend: "direct"): the svFSGe solid interface nodes coincide with the cylinder template, so the displacement is projected straight onto the SVD basis (cached exact-NN reorder) and the solid reference positions are used as the trunk — no MATLAB/fshapesTk, no per-call LDDMM, and consistent with FSG-direct-trained models. - Refactor: geometry encoding extracted into _encode_geometry dispatch with two interchangeable strategies, _encode_direct and _encode_registration (wrapping the existing matlab/matlab_engine/python LDDMM backends); predict_wss_and_pressure is now backend-agnostic with a single shared NN forward-pass tail. fsg.py: - Wire in NeuralOperator (import, init, _neural_operator_step); skip the fluid step when the surrogate is active. - _wss_relax_beta: optional WSS growth under-relaxation (constant or residual/sub-iteration ramp), defaulting to 1.0 = no-op. predictor_relax knob, also defaulting to original behaviour. - _save_failure_case: dump geometry to failed_cases/ on a failed solve. svfsi_docker.sh: - Purge leaked /dev/shm OpenMPI sm_segment.* before each solver call (these accumulate over a long run and exhaust the container's 64M /dev/shm). Verified: drives a 3-step FSG loop on the rebuilt svFSI with the archived FSG-direct models, reproducing the prior growth trajectory bit-for-bit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The FSG coupling consumes only |WSS| (svfsi.py reduces the vector via np.linalg.norm before the solid G&R solve), so a single-output magnitude model is both the correct target and more accurate than predicting the 3-vector and norming it (0.37% vs 0.64% |WSS| val error on the n833 set). If cfg["wss_magnitude_pt_file"] is set, load a 1-output magnitude model and deliver the scalar as a vector with the magnitude in the axial component, so the downstream norm recovers |WSS| exactly. Falls back to the 3-vector model (cfg["pt_file"]) otherwise — backward compatible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Companion to the load-profile work: the aneurysm insult (the spatial
elastin/stimulus knock-down that localizes the lesion) was a super-Gaussian
hard-coded in svMultiPhysics' gr_equilibrated.cpp. Expose it and inject it
from the simulation JSON.
- svfsi.py set_gr_insult(): reads an optional "gr_insult" section and patches
the solid XML with the GR_equilibrated insult params, writing
gr_insult_curve.dat for profile=file. Refactor the XML-patch and curve-write
logic out of set_gr_load() into shared _patch_solid_xml()/_write_curve()
helpers used by both.
profile: gaussian (default) | file (axial shape; azimuth stays gaussian)
mag: peak elastin loss fraction
z_loc/z_wid/z_exp: axial center/width (frac of length)/exponent
asym, theta_wid/theta_exp: azimuthal localization
curve: for "file", axial factor f_axi vs normalized position z/lo
([z/lo, factor] pairs or a plain list)
Knock-down at a point = mag * f_axi(z) * f_cir(azimuth). Omitting "gr_insult"
leaves the XML untouched -> svFSI defaults reproduce the historical insult.
- partitioned_test.json: add an explicit gaussian gr_insult so the CI test
also exercises the injection path (behavior unchanged).
Verified: fsg.py in_sim/partitioned_test.json matches test_reference/nmax_2
with the injected gaussian insult.
Requires the matching gr_equilibrated.cpp parser changes in svMultiPhysics
(FSGe branch); an older binary would reject the injected insult_* XML tags.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gen_insult_configs.py: Latin-Hypercube sample the configurable gr_insult shape params (mag, z_loc/wid/exp, theta_wid/exp) around the vanilla default, centered at (theta,z)=(0,0), one real-CFD FSG trajectory config per sample. fsg_insult_array.sbatch: run the N trajectories as a Singularity array job, each in its own working dir to avoid mesh-scratch collisions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M6MmCkf7dn8MKZarvtyZYw
Mirror the existing nmax=2 standard-FSI CI test for the neural-operator
direct backend so the NN branch is gated before merge.
- in_sim/partitioned_test_n660.json: nloads=2 test config, neural_operator
direct backend pointing at vendored assets.
- test_assets/n660/: self-contained NN deps (wss/pressure .pt, SVD basis,
cylinder.vtk template, shearStressNN_coeff model module) so CI needs
nothing outside the repo (torch is already in simvascular/solver:latest).
- test_reference/n660_nmax_2/: reference baseline (reference_results.json +
tube_002.vtu); iterations [2, 18, 36], reproducible bit-for-bit.
- test-fsg.yml: run both configs in one Docker build, copy to fixed
test_output/{standard,n660} dirs, compare each via compare_results.py.
- .gitignore: allow test_assets/**/*.vtk past the *.vt* rule.
- post.py: force headless Agg backend; close figures to avoid leaks.
- svfsi.py: optional set_gr_growth (tau_ratio_floor) G&R stabilization.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The base simvascular/solver:latest image has no torch, so CI failed at `from neural_operator import NeuralOperator` (fsg.py top-level) for BOTH the standard and n660 tests. - fsg.py: import NeuralOperator lazily inside __init__, only when a neural_operator surrogate is enabled. The standard FSI path now runs with no torch installed. - test-fsg.yml: install the CPU torch wheel before the n660 test only. Verified in a pristine simvascular/solver:latest container: `import fsg` succeeds without torch, and NeuralOperator loads the vendored test_assets after the CPU torch install. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a partitioned continuation driver that traverses growth limit points by solving for the growth-load factor lambda instead of prescribing it, on top of the new svFSI explicit-restart capability. - fsg.py: _run_arclength() — single-loop Crisfield spherical arc-length in (interface displacement d, growth-load factor lambda), solving the partitioned NN-FSG equilibrium R(d,lambda)=solid(NN(d),lambda)-d=0 with a spherical constraint so a step can be re-evaluated at a different lambda without compounding G&R history. Opt-in via JSON "arc_length". - svfsi.py: pass --restart-in/--restart-out to the solid solver so each arc-length trial re-solves a load step from an exact checkpoint (no compounding); read the most-recently-written gr_restart output when the arc-length resets decouple solver cTS from the coupling counter. - neural_operator.py, post.py: supporting changes (WSS handling; headless plotting / arc-length convergence output). Requires the matching svFSI --restart-in/--restart-out support (svMultiPhysics FSGe branch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The n660 comparison uses a very tight tolerance (Displacement rtol 1e-8, Velocity 1e-6), but the neural-operator (torch CPU) prediction is not bit-reproducible across machines: the committed reference was generated on a workstation, so it passes there but fails on the GitHub runner (the standard FSI test, which has no NN, passes on the runner — confirming the solid solver is consistent and this is NN cross-machine drift). Add a workflow_dispatch input `regenerate_n660` that re-generates the reference from the runner's own n660 output and commits it back (curated convergence.error + tube_002.vtu, matching the documented reference format), then skips the strict comparison for that run. Normal push/PR runs still compare strictly against the committed reference. Trigger it once from the Actions tab to bless a runner-generated baseline; subsequent CI runs on the same runner class then compare against a matching reference. Adds `permissions: contents: write` (used only by the regenerate path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ntinuation, explicit restart # Conflicts: # svfsi.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.