Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
57276a8
Push corrections to account for +/- m values. It is likely that in re…
chandrarn Feb 18, 2026
e54a376
Fixed bug when psi is monotonic-negative, this should now be handeled…
chandrarn Mar 3, 2026
5168ead
Slightly modified error handling for ThinCurr Object setup in calc_di…
chandrarn Mar 17, 2026
fa45d34
Refactored files under 'scratch' to be example notebooks instead, upd…
ZanderKeith Apr 6, 2026
7de9296
Added CI to ensure linting and tests pass
ZanderKeith Apr 6, 2026
ebeeec9
Fixed imports in test_thincurr.py
ZanderKeith Apr 6, 2026
c843712
Removed duplicate test and made it more comprehensive
ZanderKeith Apr 6, 2026
4cf1ca5
Added testing and improved comments for angle_domain and wrapped_diff
ZanderKeith Apr 7, 2026
04aabbe
Polished up a few docstrings
ZanderKeith Apr 7, 2026
654af21
Added more tests for thincurr functionality and forced them to run se…
ZanderKeith Apr 7, 2026
a14ddf5
Fleshed out testing for filaments
ZanderKeith Apr 7, 2026
d771592
Added tests for equilibrium field, rewrote core_psi_consistency_check…
ZanderKeith Apr 7, 2026
22ed175
Added disclosure for generative AI
ZanderKeith Apr 7, 2026
cede5cb
Made linting apply to tests
ZanderKeith Apr 7, 2026
77189f5
Fixed pre-commit not running sorting
ZanderKeith Apr 7, 2026
89d2f8e
Added C-Mod vessel and sample eqdsk for testing
ZanderKeith Apr 7, 2026
6793daf
Dropped unused pyvista import due to segfault on CI runner
ZanderKeith Apr 7, 2026
51da8c5
One thread in the testing OFT_env, split up CI actions by test file t…
ZanderKeith Apr 8, 2026
bb8360d
Further split up tests across multiple runners
ZanderKeith Apr 8, 2026
2d27e5d
Implemented caching in calculation of frequency response, improved co…
ZanderKeith Apr 8, 2026
6cdb7ba
Added test to ensure there's no contamination between sequential runs
ZanderKeith Apr 8, 2026
d2d6158
Temporarily relaxed tolerances, will need to return to this
ZanderKeith Apr 9, 2026
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
121 changes: 121 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
lint:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Cache OFT
uses: actions/cache@v4
with:
path: submodules/OpenFUSIONToolkit
key: oft-v1.0.0-beta6-ubuntu-22.04

- name: Install
run: ./install.sh

- name: Ruff format check
run: uv run ruff format --check synthwave/

- name: Ruff lint
run: uv run ruff check synthwave/

- name: Isort
run: uv run isort synthwave/

test:
runs-on: ubuntu-22.04
strategy:
matrix:
test-file:
- test_utils.py
- test_equilibrium_field.py
- test_filaments.py
name: test (${{ matrix.test-file }})
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Cache OFT
uses: actions/cache@v4
with:
path: submodules/OpenFUSIONToolkit
key: oft-v1.0.0-beta6-ubuntu-22.04

- name: Install
run: ./install.sh

- name: Run tests
run: uv run pytest synthwave/tests/${{ matrix.test-file }}

test-thincurr-other:
runs-on: ubuntu-22.04
name: test (test_thincurr.py - other)
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Cache OFT
uses: actions/cache@v4
with:
path: submodules/OpenFUSIONToolkit
key: oft-v1.0.0-beta6-ubuntu-22.04

- name: Install
run: ./install.sh

- name: Run tests
run: uv run pytest synthwave/tests/test_thincurr.py --deselect synthwave/tests/test_thincurr.py::test_toroidal_angles

test-thincurr-toroidal-angles:
runs-on: ubuntu-22.04
strategy:
matrix:
mode: ["m2n1", "m3n2", "m-3n2", "m3n1", "m4n3"]
major_radius: [1, 10]
name: test (test_toroidal_angles[${{ matrix.major_radius }}-${{ matrix.mode }}])
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Cache OFT
uses: actions/cache@v4
with:
path: submodules/OpenFUSIONToolkit
key: oft-v1.0.0-beta6-ubuntu-22.04

- name: Install
run: ./install.sh

- name: Run tests
run: uv run pytest "synthwave/tests/test_thincurr.py::test_toroidal_angles[${{ matrix.major_radius }}-${{ matrix.mode }}]"

notebooks:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- name: Cache OFT
uses: actions/cache@v4
with:
path: submodules/OpenFUSIONToolkit
key: oft-v1.0.0-beta6-ubuntu-22.04

- name: Install
run: ./install.sh

- name: Run notebooks
run: uv run pytest --nbmake examples/
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ __marimo__/

# VSCode
.vscode/
CLAUDE.md

# Install
submodules/OpenFUSIONToolkit
Expand All @@ -216,8 +217,14 @@ setup_env.sh
# Tests
synthwave/tests/figures/*.png
synthwave/tests/figures/**/*.png
synthwave/tests/**/*.h5
synthwave/tests/**/*.save

# Examples
examples/freq_response/
examples/mesh_plot/

# scratch
thincurr_scratch/
synthwave/input_data
scratch/
synthwave/vessel_caches
11 changes: 8 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ repos:
entry: jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace
- id: ruff_format
name: ruff_format
entry: poetry run ruff format
entry: uv run ruff format
language: system
types: [python]
files: "^synthwave/"
- id: ruff_check
name: ruff_check
entry: poetry run ruff check --fix
entry: uv run ruff check --fix
language: system
types: [python]
files: "^synthwave/"
exclude: "^synthwave/tests/"
- id: isort
name: isort
entry: uv run isort
language: system
types: [python]
files: "^synthwave/"
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ Given the provided input files, the magnitude of the output signal across the se

![Basic sensor signal response output](https://github.com/MIT-PSFC/SynthWave/blob/main/synthwave/mirnov/input_data/Sensor_Signals_m04_n02_f1.0e%2B01kHz_CMod.svg)

## Generative AI Disclosure

Github Copilot and Claude Code were used for code completion, snippet generation, and code review.
However, the results of this were carefully vetted. A human has read and understands every line in this repo.
154 changes: 154 additions & 0 deletions examples/freq_response.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "2dc6a9e2",
"metadata": {},
"source": [
"# Frequency Response Example\n",
"\n",
"Quick demonstration of vessel response changing measured probe angle."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0d2855e5",
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2\n",
"\n",
"import os\n",
"import shutil\n",
"import xarray as xr\n",
"import numpy as np\n",
"from OpenFUSIONToolkit._core import OFT_env\n",
"from synthwave import PACKAGE_ROOT\n",
"from synthwave.magnetic_geometry.utils import create_torus_mesh\n",
"from synthwave.magnetic_geometry.filaments import ToroidalFilamentTracer\n",
"from synthwave.mirnov.prep_thincurr_input import (\n",
" gen_OFT_filament_and_eta_file,\n",
" gen_OFT_sensors_file,\n",
")\n",
"from synthwave.mirnov.run_thincurr_model import calc_frequency_response\n",
"\n",
"EXAMPLE_DIR = os.path.join(PACKAGE_ROOT, \"..\", \"examples\", \"freq_response\")\n",
"\n",
"MAJOR_RADIUS = 1\n",
"MINOR_RADIUS = 0.5\n",
"\n",
"os.makedirs(EXAMPLE_DIR, exist_ok=True)\n",
"\n",
"torus_mesh_file = os.path.join(EXAMPLE_DIR, \"thincurr_torus_mesh.h5\")\n",
"if not os.path.exists(torus_mesh_file):\n",
" torus_mesh = create_torus_mesh(MAJOR_RADIUS, MINOR_RADIUS)\n",
" torus_mesh.write_to_file(torus_mesh_file)\n",
"\n",
"# Create 'oft_in.xml' file with icoil definitions\n",
"toroidal_tracer = ToroidalFilamentTracer(2, 1, MAJOR_RADIUS, 0, MINOR_RADIUS - 0.1)\n",
"filament_list, _ = toroidal_tracer.get_filament_list(num_filaments=10)\n",
"\n",
"gen_OFT_filament_and_eta_file(\n",
" working_directory=EXAMPLE_DIR,\n",
" filament_list=filament_list,\n",
" resistivity_list=[1e-6],\n",
")\n",
"\n",
"sensor_details = xr.Dataset(\n",
" data_vars={\n",
" \"position\": (\n",
" (\"sensor\", \"coord\"),\n",
" np.array(\n",
" [\n",
" [MAJOR_RADIUS + MINOR_RADIUS, 0.0, 0.0], # sensor on x axis\n",
" [0, MAJOR_RADIUS + MINOR_RADIUS, 0.0], # sensor on y axis\n",
" [MAJOR_RADIUS, 0, MINOR_RADIUS], # sensor on z axis\n",
" ]\n",
" ),\n",
" ),\n",
" \"normal\": (\n",
" (\"sensor\", \"coord\"),\n",
" np.array(\n",
" [\n",
" [1.0, 0.0, 0.0],\n",
" [0.0, 1.0, 0.0],\n",
" [0.0, 0.0, 1.0],\n",
" ]\n",
" ),\n",
" ),\n",
" \"radius\": (\"sensor\", np.array([0.01, 0.01, 0.01])),\n",
" },\n",
" coords={\n",
" \"sensor\": np.array([\"sensor_x\", \"sensor_y\", \"sensor_z\"]),\n",
" },\n",
" attrs={\n",
" \"sensor_set_name\": \"test_sensors\",\n",
" },\n",
")\n",
"sensor_file_path = gen_OFT_sensors_file(\n",
" sensor_details=sensor_details,\n",
" working_directory=EXAMPLE_DIR,\n",
")\n",
"\n",
"oft_tmpdir = os.path.join(\"tmp\", f\"oft_{os.getpid()}\")\n",
"if os.path.exists(oft_tmpdir):\n",
" shutil.rmtree(oft_tmpdir)\n",
"\n",
"oft_env = OFT_env(nthreads=min(4, os.cpu_count()))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "72474b42",
"metadata": {},
"outputs": [],
"source": [
"total_response, direct_response, vessel_response = calc_frequency_response(\n",
" oft_env=oft_env,\n",
" tracer=toroidal_tracer,\n",
" freq=10e3,\n",
" working_directory=EXAMPLE_DIR,\n",
" mesh_file=torus_mesh_file,\n",
" sensor_file_path=sensor_file_path,\n",
" sensor_details=sensor_details,\n",
")\n",
"\n",
"# Get the angle of each response\n",
"total_response_angle = np.angle(total_response)\n",
"vessel_response_angle = np.angle(vessel_response)\n",
"direct_response_angle = np.angle(direct_response)\n",
"\n",
"# Print the results\n",
"for i, sensor in enumerate(sensor_details.sensor.values):\n",
" print(f\"Sensor: {sensor}\")\n",
" print(f\" Total Response Angle: {total_response_angle[i]:.2f} rad\")\n",
" print(f\" Vessel Response Angle: {vessel_response_angle[i]:.2f} rad\")\n",
" print(f\" Direct Response Angle: {direct_response_angle[i]:.2f} rad\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading
Loading