From 05d834839e9ed4f72d6e2605651b3d171e254132 Mon Sep 17 00:00:00 2001 From: napoliion Date: Sun, 14 Dec 2025 23:51:11 -0600 Subject: [PATCH 1/5] Initial commit for adding documentation static page --- .github/workflows/docs.yml | 37 +++++++++++++++++++++++++++++++++++++ USAGE.md => docs/USAGE.md | 0 docs/index.md | 8 ++++++++ mkdocs.yml | 12 ++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 .github/workflows/docs.yml rename USAGE.md => docs/USAGE.md (100%) create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..524d294 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,37 @@ +name: Deploy Documentation + +on: + push: + branches: + - add-documentation # Change this to your branch name for testing + +permissions: + contents: read + pages: write + id-token: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install Zensical + run: pip install zensical + + - name: Build documentation + run: zensical build --clean + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site + + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/USAGE.md b/docs/USAGE.md similarity index 100% rename from USAGE.md rename to docs/USAGE.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..7ef8758 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,8 @@ +# FieldFlow Documentation + +JAX-based continuous normalizing flows for electric field modeling in Time Projection Chambers (TPCs). + +## Quick Links + +- [Usage Guide](USAGE.md) +- [GitHub Repository](https://github.com/RiceAstroparticleLab/fieldflow) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..674dc42 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,12 @@ +site_name: FieldFlow Documentation +site_description: JAX-based continuous normalizing flows for electric field modeling +repo_url: https://github.com/RiceAstroparticleLab/fieldflow + +docs_dir: docs # This tells Zensical to use the 'docs' folder + +nav: + - Home: index.md + - Usage: USAGE.md + +theme: + name: material \ No newline at end of file From 8e60f882cc202fd3bd21dd65018348d66126903f Mon Sep 17 00:00:00 2001 From: napoliion Date: Mon, 15 Dec 2025 22:03:41 -0600 Subject: [PATCH 2/5] Add concurrency check and update github actions/upload-pages-artifact to v4 --- .github/workflows/docs.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 524d294..1eec2ea 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,5 +1,9 @@ name: Deploy Documentation +concurrency: + group: pages + cancel-in-progress: false + on: push: branches: @@ -29,7 +33,7 @@ jobs: run: zensical build --clean - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@v4 with: path: site From 20614570e4b2bf9ce96574923831b252110dea24 Mon Sep 17 00:00:00 2001 From: napoliion Date: Tue, 3 Mar 2026 18:40:54 -0600 Subject: [PATCH 3/5] Update repository readme --- README.md | 55 +++++++++++++++++++++++------ docs/assets/model_architecture.png | Bin 0 -> 41054 bytes 2 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 docs/assets/model_architecture.png diff --git a/README.md b/README.md index 1b33b9b..e6798c9 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,27 @@ # FieldFlow -JAX-based continuous normalizing flows for electric field modeling in Time Projection Chambers (TPCs). FieldFlow uses neural ODEs to learn the mapping between hit patterns and electric field configurations for astrophysical particle detection experiments. +**Physics-informed continuous normalizing flows for modeling electric fields in time projection chambers** + +FieldFlow is a JAX-based library implementing neural ODEs to learn the electric field transformation in time projection chambers directly from calibration data. The model enforces physical constraints (field conservativity) through its architecture to ensure a curl-free electric field. The flow can be used for correcting the field distortions when reconstructing particle interaction positions. Compared to traditional field distortion corrections in xenon TPCs, the flow can achieve comparable accuracy in position reconstruction while requiring fewer calibration events. The library implements continuous normalizing flows with configurable ODE solvers, supporting both exact and approximate log probability computation. Multi-GPU training is supported with automatic data parallelization across devices. +## Paper + +> **Physics-informed continuous normalizing flows to learn the electric field within a time-projection chamber** +> Ivy Li, Peter Gaemers, Juehang Qin, Naija Bruckner, Maris Arthurs, Maria Elena Monzani, Christopher Tunnell (2025) +> [arXiv:2511.01897](https://arxiv.org/abs/2511.01897) *(under review)* + +## Key Features + +- **Continuous normalizing flows** with exact or approximate log probability computation +- **Multi-GPU training** with automatic data sharding across devices +- **Configurable ODE solvers** including adaptive PID controllers +- **Fine-tuning support** for transfer learning from pretrained models +- **Position reconstruction** integration with pretrained flow models +- **JAX-based** implementation for GPU acceleration and automatic differentiation + ## Installation Requires Python ≥3.10. Install from source: @@ -16,7 +33,7 @@ cd fieldflow pip install -e . ``` -## Quick Usage +## Quick Start Train a new model: ```bash @@ -28,16 +45,34 @@ Fine-tune a pretrained model: python -m fieldflow config.toml --pretrained model.eqx ``` -See [USAGE.md](USAGE.md) for detailed usage instructions and [sample_config.toml](sample_config.toml) for configuration options. +See the [documentation](https://riceastroparticlelab.github.io/fieldflow/) (in progress) for example usage details. Configuration options are documented in [`sample_config.toml`](sample_config.toml). -## Key Features +## How It Works -- **Continuous normalizing flows** with exact or approximate log probability computation -- **Multi-GPU training** with automatic data sharding across devices -- **Configurable ODE solvers** including adaptive PID controllers -- **Fine-tuning support** for transfer learning from pretrained models -- **Position reconstruction** integration with pretrained flow models -- **JAX-based** implementation for GPU acceleration and automatic differentiation +In a xenon TPC, ionization electrons drift through the detector under an applied electric field. Imperfections in this field distort the electrons' paths, so the positions measured at the top of the detector don't match where the interaction actually occurred. FieldFlow models the electric field and thereby can be used to correct these distortions. + +**The model:** A continuous normalizing flow takes an interaction's transverse position (x, y) and time as input and outputs the dynamics of that position over drift time — where drift time maps directly to depth z inside the detector (z = drift velocity x time). Solving the neural ODE backward in time traces how a position gets distorted as electrons drift through the field; inverting it recovers the true interaction position. + +**The physics-informed constraint:** Rather than learning the electric field directly, the neural network parameterizes the negative gradient of a scalar potential. This architectural choice guarantees that the learned field is curl-free by construction — this is based under the assumption of electrostatic fields in a TPC which do not vary significantly over time. Thus the physics is baked into the model architecture instead of enforced by a loss penalty as is typical in other physics-informed machine learning methods. + +

+ FieldFlow model architecture +

+ +

+Fig. 1: A position s inside the TPC evolves over drift time t, where depth corresponds to z(t) = vdt. The neural network learns a function gϕ approximating a scaled scalar potential, and outputs −∇gϕ — the transverse gradient that governs how each position transforms as electrons drift. Because the dynamics are derived from a scalar potential, the resulting field is guaranteed to be curl-free. +

+ +## Project Structure + +``` +fieldflow/ +├── src/fieldflow/ # Core library (flows, ODE solvers, training) +├── tests/ # Unit tests +├── sample_config.toml # Example training configuration +├── USAGE.md # Detailed usage guide +└── pyproject.toml # Package metadata +``` ## License diff --git a/docs/assets/model_architecture.png b/docs/assets/model_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..2d460fecea624b3eb80a48e903803875846ca96e GIT binary patch literal 41054 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°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 G`hNg$SQnT8 literal 0 HcmV?d00001 From 7ccb5a9bbbeb05eb686e27de1511bccfb3b404cf Mon Sep 17 00:00:00 2001 From: napoliion Date: Tue, 3 Mar 2026 19:17:07 -0600 Subject: [PATCH 4/5] Edit README --- README.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e6798c9..029e160 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,13 @@ # FieldFlow -**Physics-informed continuous normalizing flows for modeling electric fields in time projection chambers** +**Physics-informed continuous normalizing flows to learn the electric field in time projection chambers** -FieldFlow is a JAX-based library implementing neural ODEs to learn the electric field transformation in time projection chambers directly from calibration data. The model enforces physical constraints (field conservativity) through its architecture to ensure a curl-free electric field. The flow can be used for correcting the field distortions when reconstructing particle interaction positions. Compared to traditional field distortion corrections in xenon TPCs, the flow can achieve comparable accuracy in position reconstruction while requiring fewer calibration events. +FieldFlow is a JAX-based library implementing neural ODEs to learn the electric field transformation in time projection chambers directly from calibration data. + +In a xenon TPC, ionization electrons drift through the detector under an applied electric field. Imperfections in this field distort the electrons' paths, so the positions measured at the top of the detector don't match where the interaction actually occurred. FieldFlow models the electric field and thereby can be used to correct these distortions. + +The model enforces physical constraints (field conservativity) through its architecture to ensure a curl-free electric field. Compared to traditional field distortion corrections in xenon TPCs, the flow can achieve comparable accuracy in position reconstruction while requiring significantly fewer calibration events. The library implements continuous normalizing flows with configurable ODE solvers, supporting both exact and approximate log probability computation. Multi-GPU training is supported with automatic data parallelization across devices. @@ -23,6 +27,20 @@ The library implements continuous normalizing flows with configurable ODE solver - **Position reconstruction** integration with pretrained flow models - **JAX-based** implementation for GPU acceleration and automatic differentiation +## How It Works + +**Solving the neural ODE:** A continuous normalizing flow takes an interaction's transverse position (x, y) and time as input and outputs the dynamics of that position over drift time — where drift time maps directly to depth z inside the detector (z = drift velocity x time). Solving the neural ODE backward in time traces how a position gets distorted as electrons drift through the field. Inverting this transformation recovers the true interaction position. + +**Constraining the electric field:** Rather than learning the electric field directly, the neural network parameterizes the negative gradient of a scalar potential. This architectural choice guarantees that the learned electric field is curl-free, as we make the assumption of electrostatic electric fields which do not significantly vary over time. Thus, unlike other physics-informed models which enforce physics constraints through a loss penalty, the physics here is baked into the model architecture instead. + +

+ FieldFlow model architecture +

+ +

+Fig. 1: A position s inside the TPC evolves over drift time t, where depth corresponds to z(t) = vdt. The neural network learns a function gϕ approximating a scaled scalar potential, and outputs −∇sgϕ — the transverse gradient that governs how each position transforms as electrons drift. Because the dynamics are derived from a scalar potential, the resulting field is guaranteed to be curl-free. +

+ ## Installation Requires Python ≥3.10. Install from source: @@ -47,30 +65,14 @@ python -m fieldflow config.toml --pretrained model.eqx See the [documentation](https://riceastroparticlelab.github.io/fieldflow/) (in progress) for example usage details. Configuration options are documented in [`sample_config.toml`](sample_config.toml). -## How It Works - -In a xenon TPC, ionization electrons drift through the detector under an applied electric field. Imperfections in this field distort the electrons' paths, so the positions measured at the top of the detector don't match where the interaction actually occurred. FieldFlow models the electric field and thereby can be used to correct these distortions. - -**The model:** A continuous normalizing flow takes an interaction's transverse position (x, y) and time as input and outputs the dynamics of that position over drift time — where drift time maps directly to depth z inside the detector (z = drift velocity x time). Solving the neural ODE backward in time traces how a position gets distorted as electrons drift through the field; inverting it recovers the true interaction position. - -**The physics-informed constraint:** Rather than learning the electric field directly, the neural network parameterizes the negative gradient of a scalar potential. This architectural choice guarantees that the learned field is curl-free by construction — this is based under the assumption of electrostatic fields in a TPC which do not vary significantly over time. Thus the physics is baked into the model architecture instead of enforced by a loss penalty as is typical in other physics-informed machine learning methods. - -

- FieldFlow model architecture -

- -

-Fig. 1: A position s inside the TPC evolves over drift time t, where depth corresponds to z(t) = vdt. The neural network learns a function gϕ approximating a scaled scalar potential, and outputs −∇gϕ — the transverse gradient that governs how each position transforms as electrons drift. Because the dynamics are derived from a scalar potential, the resulting field is guaranteed to be curl-free. -

- ## Project Structure ``` fieldflow/ ├── src/fieldflow/ # Core library (flows, ODE solvers, training) ├── tests/ # Unit tests +├── docs/ # Documentation ├── sample_config.toml # Example training configuration -├── USAGE.md # Detailed usage guide └── pyproject.toml # Package metadata ``` From 14ca2cd25bdd90b76441e6c30df71a67bdd22e9c Mon Sep 17 00:00:00 2001 From: napoliion Date: Tue, 3 Mar 2026 19:18:58 -0600 Subject: [PATCH 5/5] Switch documentation github page branch to main --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1eec2ea..e37ebc5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,7 +7,7 @@ concurrency: on: push: branches: - - add-documentation # Change this to your branch name for testing + - main permissions: contents: read