pyneutrace 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. pyneutrace-0.1.1/LICENSE +21 -0
  2. pyneutrace-0.1.1/PKG-INFO +147 -0
  3. pyneutrace-0.1.1/README.md +118 -0
  4. pyneutrace-0.1.1/pyproject.toml +57 -0
  5. pyneutrace-0.1.1/setup.cfg +4 -0
  6. pyneutrace-0.1.1/src/pyneutrace/__init__.py +0 -0
  7. pyneutrace-0.1.1/src/pyneutrace/components/__init__.py +56 -0
  8. pyneutrace-0.1.1/src/pyneutrace/components/analyzer.py +161 -0
  9. pyneutrace-0.1.1/src/pyneutrace/components/cascadeanalyzer.py +229 -0
  10. pyneutrace-0.1.1/src/pyneutrace/components/curvedfermichopper.py +441 -0
  11. pyneutrace-0.1.1/src/pyneutrace/components/curvedfermichopper_new.py +252 -0
  12. pyneutrace-0.1.1/src/pyneutrace/components/curvedguide.py +379 -0
  13. pyneutrace-0.1.1/src/pyneutrace/components/curvedguide_v0.py +359 -0
  14. pyneutrace-0.1.1/src/pyneutrace/components/diskchopper.py +379 -0
  15. pyneutrace-0.1.1/src/pyneutrace/components/doubleellipticguide.py +436 -0
  16. pyneutrace-0.1.1/src/pyneutrace/components/doubleparabolicguide.py +589 -0
  17. pyneutrace-0.1.1/src/pyneutrace/components/io_rays.py +151 -0
  18. pyneutrace-0.1.1/src/pyneutrace/components/moderator.py +204 -0
  19. pyneutrace-0.1.1/src/pyneutrace/components/monitor.py +337 -0
  20. pyneutrace-0.1.1/src/pyneutrace/components/monochromator.py +1544 -0
  21. pyneutrace-0.1.1/src/pyneutrace/components/multicascadeanalyzer.py +417 -0
  22. pyneutrace-0.1.1/src/pyneutrace/components/neutronguide.py +556 -0
  23. pyneutrace-0.1.1/src/pyneutrace/components/nsource.py +474 -0
  24. pyneutrace-0.1.1/src/pyneutrace/components/powdersample.py +370 -0
  25. pyneutrace-0.1.1/src/pyneutrace/components/powdersample_v0.py +343 -0
  26. pyneutrace-0.1.1/src/pyneutrace/components/radcollimator.py +839 -0
  27. pyneutrace-0.1.1/src/pyneutrace/components/singlecrystalsample.py +437 -0
  28. pyneutrace-0.1.1/src/pyneutrace/components/singleellipticguide.py +474 -0
  29. pyneutrace-0.1.1/src/pyneutrace/components/soller.py +367 -0
  30. pyneutrace-0.1.1/src/pyneutrace/components/source.py +406 -0
  31. pyneutrace-0.1.1/src/pyneutrace/components/spacer.py +241 -0
  32. pyneutrace-0.1.1/src/pyneutrace/components/straightfermichopper.py +388 -0
  33. pyneutrace-0.1.1/src/pyneutrace/components/vanalyzer.py +1759 -0
  34. pyneutrace-0.1.1/src/pyneutrace/components/velselector.py +377 -0
  35. pyneutrace-0.1.1/src/pyneutrace/components/virtualfilter.py +62 -0
  36. pyneutrace-0.1.1/src/pyneutrace/components/vsample.py +250 -0
  37. pyneutrace-0.1.1/src/pyneutrace/constants.py +46 -0
  38. pyneutrace-0.1.1/src/pyneutrace/instrument/__init__.py +5 -0
  39. pyneutrace-0.1.1/src/pyneutrace/instrument/instrumentassemble.py +657 -0
  40. pyneutrace-0.1.1/src/pyneutrace/simulation/__init__.py +5 -0
  41. pyneutrace-0.1.1/src/pyneutrace/simulation/instrumentoptimizer.py +331 -0
  42. pyneutrace-0.1.1/src/pyneutrace/simulation/instrumentoptimizer_v0.py +156 -0
  43. pyneutrace-0.1.1/src/pyneutrace/utils.py +163 -0
  44. pyneutrace-0.1.1/src/pyneutrace/visualization/__init__.py +5 -0
  45. pyneutrace-0.1.1/src/pyneutrace/visualization/instrumentvis.py +109 -0
  46. pyneutrace-0.1.1/src/pyneutrace.egg-info/PKG-INFO +147 -0
  47. pyneutrace-0.1.1/src/pyneutrace.egg-info/SOURCES.txt +97 -0
  48. pyneutrace-0.1.1/src/pyneutrace.egg-info/dependency_links.txt +1 -0
  49. pyneutrace-0.1.1/src/pyneutrace.egg-info/requires.txt +13 -0
  50. pyneutrace-0.1.1/src/pyneutrace.egg-info/top_level.txt +1 -0
  51. pyneutrace-0.1.1/test/test_3D_assemble.py +74 -0
  52. pyneutrace-0.1.1/test/test_3D_diskchopper.py +180 -0
  53. pyneutrace-0.1.1/test/test_3D_guide_doubleelliptical.py +152 -0
  54. pyneutrace-0.1.1/test/test_3D_guide_doubleparabolic.py +218 -0
  55. pyneutrace-0.1.1/test/test_3D_guide_doubleparabolic_new.py +45 -0
  56. pyneutrace-0.1.1/test/test_3D_guide_doubleparabolic_z-.py +174 -0
  57. pyneutrace-0.1.1/test/test_3D_guide_simple.py +93 -0
  58. pyneutrace-0.1.1/test/test_3D_guide_single_elliptical.py +92 -0
  59. pyneutrace-0.1.1/test/test_3D_mono.py +152 -0
  60. pyneutrace-0.1.1/test/test_3D_radcoll.py +100 -0
  61. pyneutrace-0.1.1/test/test_3D_soller.py +87 -0
  62. pyneutrace-0.1.1/test/test_3D_source.py +113 -0
  63. pyneutrace-0.1.1/test/test_3D_spacer.py +78 -0
  64. pyneutrace-0.1.1/test/test_3D_vanalyzer.py +156 -0
  65. pyneutrace-0.1.1/test/test_3D_velselector.py +120 -0
  66. pyneutrace-0.1.1/test/test_analyzer.py +187 -0
  67. pyneutrace-0.1.1/test/test_cascadeanalyzer.py +70 -0
  68. pyneutrace-0.1.1/test/test_curvedguide.py +110 -0
  69. pyneutrace-0.1.1/test/test_instrumentoptimizer_v0.py +70 -0
  70. pyneutrace-0.1.1/test/test_instrumentvis.py +54 -0
  71. pyneutrace-0.1.1/test/test_io_rays.py +83 -0
  72. pyneutrace-0.1.1/test/test_moderator.py +120 -0
  73. pyneutrace-0.1.1/test/test_moderator_neutronguide_curvedfermichopper.py +287 -0
  74. pyneutrace-0.1.1/test/test_moderator_neutronguide_diskchopper.py +340 -0
  75. pyneutrace-0.1.1/test/test_moderator_neutronguide_straitfermi.py +275 -0
  76. pyneutrace-0.1.1/test/test_moderator_neutronguide_straitfermi_with_instrAssemble.py +210 -0
  77. pyneutrace-0.1.1/test/test_monitor.py +73 -0
  78. pyneutrace-0.1.1/test/test_mono.py +316 -0
  79. pyneutrace-0.1.1/test/test_multicascadeanalyzer.py +148 -0
  80. pyneutrace-0.1.1/test/test_multicascadeanalyzer_3d.py +127 -0
  81. pyneutrace-0.1.1/test/test_nsource.py +74 -0
  82. pyneutrace-0.1.1/test/test_powdersample.py +160 -0
  83. pyneutrace-0.1.1/test/test_powdersample_noinstr.py +212 -0
  84. pyneutrace-0.1.1/test/test_run_beamline_simulation_3D.py +106 -0
  85. pyneutrace-0.1.1/test/test_run_beamline_simulation_v1.py +133 -0
  86. pyneutrace-0.1.1/test/test_run_beamline_simulation_v2.py +189 -0
  87. pyneutrace-0.1.1/test/test_run_beamline_simulation_v2_3D.py +185 -0
  88. pyneutrace-0.1.1/test/test_run_beamline_simulation_v3_ana.py +316 -0
  89. pyneutrace-0.1.1/test/test_run_beamline_simulation_v3_ana_3D.py +257 -0
  90. pyneutrace-0.1.1/test/test_run_beamline_simulation_v4_multicascade.py +305 -0
  91. pyneutrace-0.1.1/test/test_run_beamline_simulation_v4_multicascade_3D.py +359 -0
  92. pyneutrace-0.1.1/test/test_singlecrystalsample.py +220 -0
  93. pyneutrace-0.1.1/test/test_singlecrystalsample_noinstr.py +171 -0
  94. pyneutrace-0.1.1/test/test_singlecrystalsample_v2.py +276 -0
  95. pyneutrace-0.1.1/test/test_source.py +74 -0
  96. pyneutrace-0.1.1/test/test_unknown.py +177 -0
  97. pyneutrace-0.1.1/test/test_vanalyzer.py +358 -0
  98. pyneutrace-0.1.1/test/test_velselector.py +127 -0
  99. pyneutrace-0.1.1/test/test_vrodsample_radcollimator_v2.py +182 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Guochu Deng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyneutrace
3
+ Version: 0.1.1
4
+ Summary: pyneutrace is a neutron ray tracing monte carlo simulation package for neutron instrumentation and component design optimization and resolution calculation.
5
+ Author-email: Guochu Deng <gc.deng.ansto@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/gcdengansto/pyneutrace
8
+ Project-URL: Documentation, https://project.readthedocs.io/gcdengansto/pyneutrace
9
+ Keywords: neutron,ray tracing,Monte Carlo,spectrometer,triple-axis,time-of-flight
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Physics
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy>=1.20.0
18
+ Requires-Dist: scipy>=1.7
19
+ Requires-Dist: pandas>=1.3
20
+ Provides-Extra: gui
21
+ Requires-Dist: matplotlib>=3.1.0; extra == "gui"
22
+ Requires-Dist: pyvista; extra == "gui"
23
+ Requires-Dist: QtPy; extra == "gui"
24
+ Requires-Dist: PySide6; extra == "gui"
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: black>=23.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # pyneutrace: Neutron Ray Tracing Python Package
31
+
32
+ A pure Python-based Monte Carlo neutron ray-tracing package for neutron instrument design, structural optimization, resolution calculation, and virtual experiments.
33
+
34
+ ---
35
+
36
+ ## Features
37
+
38
+ - **High-Performance Tracing** — Monte Carlo neutron ray tracing simulation utilizing fully vectorized operations via `numpy` to trace millions of rays simultaneously without the need for C/C++ compilation.
39
+ - **Modular Pipeline** — Easy-to-use component assembly system to seamlessly chain neutron optics, sample environments, and detectors.
40
+ - **Built-in Crystallography** — Custom CIF parser natively built into the package to handle real-world crystal structures for powder and single-crystal scattering.
41
+ - **Advanced Ray Checkpointing** — Transparently export and merge live neutron states (with metadata validation) to overcome extreme attenuation and accelerate complex downstream simulations.
42
+ - **Optimization Engine** — SciPy-backed `InstrumentOptimizer` to tune beamline parameters (e.g., guide focus, chopper phase) for maximum flux/resolution.
43
+
44
+ ---
45
+
46
+ ## Directory Structure
47
+
48
+ ```text
49
+ pyneutrace/
50
+ ├── src/
51
+ │ └── pyneutrace/
52
+ │ ├── __init__.py
53
+ │ ├── constants.py # Physical constants and standard D-spacings
54
+ │ ├── utils.py # Core utilities, including the custom CIF parser
55
+ │ ├── instrument/ # InstrumentAssemble pipeline manager
56
+ │ ├── components/ # Optics, samples, choppers, and detectors
57
+ │ ├── simulation/ # InstrumentOptimizer
58
+ │ └── visualization/ # InstrumentSimPlot for statistical visualization
59
+ ├── test/ # Comprehensive test suite covering all components
60
+ ├── pyproject.toml # Package build configuration
61
+ └── README.md
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Quick Start
67
+
68
+ 1. **Installation:** Run `pip install .` in the project root path for the core engine, or `pip install ".[gui]"` to include 3D visualization dependencies.
69
+ 2. **Build your instrument:** Instantiate components and chain them using the `InstrumentAssemble` class.
70
+ 3. **Run the simulation:** Execute `pipeline.run(num_rays=1_000_000)` to trace the beam.
71
+ 4. **Visualize 3D Geometry:** Call `pipeline.visualize_3d()` to render the physical instrument layout via PyVista.
72
+ 5. **Analyze Results:** Use the `InstrumentSimPlot` class to visualize transmission drop-off and spatial/energy beam profiles at any stage.
73
+
74
+ ---
75
+
76
+ ## User Interface
77
+
78
+ ### Available Components (`pyneutrace.components`)
79
+
80
+ | Component Class | Description |
81
+ |---|---|
82
+ | **NeutronSource** | Continuous neutron source (reactor) with a dual-temperature Maxwellian flux spectrum. |
83
+ | **Moderator** | Pulsed neutron source (spallation) with wavelength-dependent Ikeda-Carpenter pulse shaping. |
84
+ | **NeutronGuide** | Straight or tapered supermirror guide (supports m-value reflectivity decay). |
85
+ | **CurvedGuide** | Horizontally curved supermirror bender for filtering fast neutrons and gammas. |
86
+ | **Elliptic / Parabolic Guides**| Focusing optic guides (Single Elliptic, Double Elliptic, Double Parabolic). |
87
+ | **DiskChopper** | Standard rotating disk chopper for pulse shaping and order sorting. |
88
+ | **Straight/Curved FermiChopper**| High-speed rotating slit packages for precise energy selection. |
89
+ | **VelSelector** | Mechanical velocity selector (helical turbine) for monochromatic beam selection. |
90
+ | **Monochromator / Analyzer** | Single crystal (e.g., PG, Si, Ge) arrays to select specific neutron energies via Bragg's law. |
91
+ | **PowderSample** | Realistic sample environment supporting CIF loading and Debye-Scherrer cone diffraction. |
92
+ | **VRodSample** | Cylindrical sample demonstrating isotropic elastic scattering. |
93
+ | **Monitor / CylindMonitor** | Flat and curved Position Sensitive Detectors (PSD) for capturing 2D spatial and 1D energy histograms. |
94
+ | **Soller / RadCollimator** | Linear and radial collimation packages to define beam divergence. |
95
+ | **ExportRays / ImportRays** | I/O components to checkpoint live beams to disk and merge multiple runs. |
96
+ | **Spacer** | A virtual component used to advance the beam a specific distance in empty space. |
97
+
98
+ ### Core Pipeline (`pyneutrace.instrument`)
99
+
100
+ | Class | Description |
101
+ |---|---|
102
+ | **InstrumentAssemble** | The central pipeline manager. Handles the addition of components, calculates global 4x4 coordinate transformations, and executes the sequential Monte Carlo propagation (`propagate_TOF`). |
103
+
104
+ ### Visualization (`pyneutrace.visualization`)
105
+
106
+ | Class | Description |
107
+ |---|---|
108
+ | **InstrumentSimPlot** | Generates Matplotlib dashboards summarizing transmission efficiency and "Virtual Monitor" beam profiles without requiring heavy memory storage during runs. |
109
+
110
+ ---
111
+
112
+ ## Physics & Architecture
113
+
114
+ ### Coordinate System
115
+
116
+ ```text
117
+ X → Horizontal (perpendicular to the beam propagating direction)
118
+ Y → Vertical (up)
119
+ Z → Beam propagating direction
120
+ ```
121
+
122
+ **Local vs. Global Frames**
123
+ Each component in the instrument possesses its own local coordinate system. A component clearly defines its **entry window** (usually at $Z = 0$) and its **exit window** (usually at $Z = L$).
124
+
125
+ `InstrumentAssemble` builds the instrument as a **seamless continuous pipeline**. This means all components, from the source to the detector, are connected back-to-back. The exit window of an upstream component becomes the exact mathematical entry window of the subsequent component.
126
+
127
+ To achieve this:
128
+ 1. All surviving neutrons exiting a component are mathematically translated (and rotated, if the component bends the beam like a `CurvedGuide` or `Monochromator`) so that their positions and velocities are expressed perfectly relative to the **center of the exit window**.
129
+ 2. This allows the next component to simply assume the incoming beam is crossing its own $Z=0$ plane.
130
+ 3. If physical empty space is required between two optical elements, a `Spacer` component must be explicitly inserted into the pipeline.
131
+
132
+ **The Sample Exception**
133
+ The only exception to the strict Entry/Exit window rule is the Sample environment. Because neutrons scattered from a sample diverge outward into the entire 3D sphere ($4\pi$ steradians), it is impossible to define a single planar "exit window".
134
+
135
+ Instead, neutron coordinates scattered away from a sample use the **sample center** as their origin ($0,0,0$), with the incident primary beam defining the $+Z$ direction. Downstream components (such as a `RadCollimator` or `CylindMonitor`) are explicitly designed to account for this geometry, often utilizing cylindrical or spherical coordinates to capture the flying neutrons.
136
+
137
+ ### Bragg Scattering
138
+
139
+ For the `Monochromator`, `Analyzer`, and `PowderSample`, the Bragg condition is applied to filter and scatter neutrons at specific wavelengths. The momentum transfer vector $\vec{Q}$ is calculated for reciprocal lattice vectors $\vec{G}$ and the incident wavevector $\vec{k}_{in}$, ensuring that only neutrons satisfying $|\vec{k}_{out}| = |\vec{k}_{in}|$ and $\vec{Q} = \vec{G}$ are scattered with high probability according to their structure factors ($|F|^2$).
140
+
141
+ ---
142
+
143
+ ## Known Limitations
144
+
145
+ - **Gravity:** The impact of gravity ($\vec{g}$) has not yet been taken into account. Neutrons currently travel in perfectly straight lines between component boundaries.
146
+ - **Detector Efficiency:** Monitors currently act as perfect 100% absorbing planes. Wavelength-dependent gas detection efficiency ($1 - \exp(-c\lambda)$) and finite depth tracking are not yet implemented.
147
+ - **Inelastic Scattering:** Sample kernels for inelastic energy transfer ($S(Q, \omega)$) to simulate phonons and magnons are not yet supported.
@@ -0,0 +1,118 @@
1
+ # pyneutrace: Neutron Ray Tracing Python Package
2
+
3
+ A pure Python-based Monte Carlo neutron ray-tracing package for neutron instrument design, structural optimization, resolution calculation, and virtual experiments.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - **High-Performance Tracing** — Monte Carlo neutron ray tracing simulation utilizing fully vectorized operations via `numpy` to trace millions of rays simultaneously without the need for C/C++ compilation.
10
+ - **Modular Pipeline** — Easy-to-use component assembly system to seamlessly chain neutron optics, sample environments, and detectors.
11
+ - **Built-in Crystallography** — Custom CIF parser natively built into the package to handle real-world crystal structures for powder and single-crystal scattering.
12
+ - **Advanced Ray Checkpointing** — Transparently export and merge live neutron states (with metadata validation) to overcome extreme attenuation and accelerate complex downstream simulations.
13
+ - **Optimization Engine** — SciPy-backed `InstrumentOptimizer` to tune beamline parameters (e.g., guide focus, chopper phase) for maximum flux/resolution.
14
+
15
+ ---
16
+
17
+ ## Directory Structure
18
+
19
+ ```text
20
+ pyneutrace/
21
+ ├── src/
22
+ │ └── pyneutrace/
23
+ │ ├── __init__.py
24
+ │ ├── constants.py # Physical constants and standard D-spacings
25
+ │ ├── utils.py # Core utilities, including the custom CIF parser
26
+ │ ├── instrument/ # InstrumentAssemble pipeline manager
27
+ │ ├── components/ # Optics, samples, choppers, and detectors
28
+ │ ├── simulation/ # InstrumentOptimizer
29
+ │ └── visualization/ # InstrumentSimPlot for statistical visualization
30
+ ├── test/ # Comprehensive test suite covering all components
31
+ ├── pyproject.toml # Package build configuration
32
+ └── README.md
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Quick Start
38
+
39
+ 1. **Installation:** Run `pip install .` in the project root path for the core engine, or `pip install ".[gui]"` to include 3D visualization dependencies.
40
+ 2. **Build your instrument:** Instantiate components and chain them using the `InstrumentAssemble` class.
41
+ 3. **Run the simulation:** Execute `pipeline.run(num_rays=1_000_000)` to trace the beam.
42
+ 4. **Visualize 3D Geometry:** Call `pipeline.visualize_3d()` to render the physical instrument layout via PyVista.
43
+ 5. **Analyze Results:** Use the `InstrumentSimPlot` class to visualize transmission drop-off and spatial/energy beam profiles at any stage.
44
+
45
+ ---
46
+
47
+ ## User Interface
48
+
49
+ ### Available Components (`pyneutrace.components`)
50
+
51
+ | Component Class | Description |
52
+ |---|---|
53
+ | **NeutronSource** | Continuous neutron source (reactor) with a dual-temperature Maxwellian flux spectrum. |
54
+ | **Moderator** | Pulsed neutron source (spallation) with wavelength-dependent Ikeda-Carpenter pulse shaping. |
55
+ | **NeutronGuide** | Straight or tapered supermirror guide (supports m-value reflectivity decay). |
56
+ | **CurvedGuide** | Horizontally curved supermirror bender for filtering fast neutrons and gammas. |
57
+ | **Elliptic / Parabolic Guides**| Focusing optic guides (Single Elliptic, Double Elliptic, Double Parabolic). |
58
+ | **DiskChopper** | Standard rotating disk chopper for pulse shaping and order sorting. |
59
+ | **Straight/Curved FermiChopper**| High-speed rotating slit packages for precise energy selection. |
60
+ | **VelSelector** | Mechanical velocity selector (helical turbine) for monochromatic beam selection. |
61
+ | **Monochromator / Analyzer** | Single crystal (e.g., PG, Si, Ge) arrays to select specific neutron energies via Bragg's law. |
62
+ | **PowderSample** | Realistic sample environment supporting CIF loading and Debye-Scherrer cone diffraction. |
63
+ | **VRodSample** | Cylindrical sample demonstrating isotropic elastic scattering. |
64
+ | **Monitor / CylindMonitor** | Flat and curved Position Sensitive Detectors (PSD) for capturing 2D spatial and 1D energy histograms. |
65
+ | **Soller / RadCollimator** | Linear and radial collimation packages to define beam divergence. |
66
+ | **ExportRays / ImportRays** | I/O components to checkpoint live beams to disk and merge multiple runs. |
67
+ | **Spacer** | A virtual component used to advance the beam a specific distance in empty space. |
68
+
69
+ ### Core Pipeline (`pyneutrace.instrument`)
70
+
71
+ | Class | Description |
72
+ |---|---|
73
+ | **InstrumentAssemble** | The central pipeline manager. Handles the addition of components, calculates global 4x4 coordinate transformations, and executes the sequential Monte Carlo propagation (`propagate_TOF`). |
74
+
75
+ ### Visualization (`pyneutrace.visualization`)
76
+
77
+ | Class | Description |
78
+ |---|---|
79
+ | **InstrumentSimPlot** | Generates Matplotlib dashboards summarizing transmission efficiency and "Virtual Monitor" beam profiles without requiring heavy memory storage during runs. |
80
+
81
+ ---
82
+
83
+ ## Physics & Architecture
84
+
85
+ ### Coordinate System
86
+
87
+ ```text
88
+ X → Horizontal (perpendicular to the beam propagating direction)
89
+ Y → Vertical (up)
90
+ Z → Beam propagating direction
91
+ ```
92
+
93
+ **Local vs. Global Frames**
94
+ Each component in the instrument possesses its own local coordinate system. A component clearly defines its **entry window** (usually at $Z = 0$) and its **exit window** (usually at $Z = L$).
95
+
96
+ `InstrumentAssemble` builds the instrument as a **seamless continuous pipeline**. This means all components, from the source to the detector, are connected back-to-back. The exit window of an upstream component becomes the exact mathematical entry window of the subsequent component.
97
+
98
+ To achieve this:
99
+ 1. All surviving neutrons exiting a component are mathematically translated (and rotated, if the component bends the beam like a `CurvedGuide` or `Monochromator`) so that their positions and velocities are expressed perfectly relative to the **center of the exit window**.
100
+ 2. This allows the next component to simply assume the incoming beam is crossing its own $Z=0$ plane.
101
+ 3. If physical empty space is required between two optical elements, a `Spacer` component must be explicitly inserted into the pipeline.
102
+
103
+ **The Sample Exception**
104
+ The only exception to the strict Entry/Exit window rule is the Sample environment. Because neutrons scattered from a sample diverge outward into the entire 3D sphere ($4\pi$ steradians), it is impossible to define a single planar "exit window".
105
+
106
+ Instead, neutron coordinates scattered away from a sample use the **sample center** as their origin ($0,0,0$), with the incident primary beam defining the $+Z$ direction. Downstream components (such as a `RadCollimator` or `CylindMonitor`) are explicitly designed to account for this geometry, often utilizing cylindrical or spherical coordinates to capture the flying neutrons.
107
+
108
+ ### Bragg Scattering
109
+
110
+ For the `Monochromator`, `Analyzer`, and `PowderSample`, the Bragg condition is applied to filter and scatter neutrons at specific wavelengths. The momentum transfer vector $\vec{Q}$ is calculated for reciprocal lattice vectors $\vec{G}$ and the incident wavevector $\vec{k}_{in}$, ensuring that only neutrons satisfying $|\vec{k}_{out}| = |\vec{k}_{in}|$ and $\vec{Q} = \vec{G}$ are scattered with high probability according to their structure factors ($|F|^2$).
111
+
112
+ ---
113
+
114
+ ## Known Limitations
115
+
116
+ - **Gravity:** The impact of gravity ($\vec{g}$) has not yet been taken into account. Neutrons currently travel in perfectly straight lines between component boundaries.
117
+ - **Detector Efficiency:** Monitors currently act as perfect 100% absorbing planes. Wavelength-dependent gas detection efficiency ($1 - \exp(-c\lambda)$) and finite depth tracking are not yet implemented.
118
+ - **Inelastic Scattering:** Sample kernels for inelastic energy transfer ($S(Q, \omega)$) to simulate phonons and magnons are not yet supported.
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ # Minimum requirements for the build system
3
+ requires = ["setuptools>=77.0.0", "wheel"]
4
+ build-backend = "setuptools.build_meta"
5
+
6
+ [project]
7
+ name = "pyneutrace"
8
+ version = "0.1.1"
9
+ description = "pyneutrace is a neutron ray tracing monte carlo simulation package for neutron instrumentation and component design optimization and resolution calculation."
10
+ readme = "README.md"
11
+ requires-python = ">=3.8"
12
+
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+
16
+ authors = [
17
+ {name = "Guochu Deng", email = "gc.deng.ansto@gmail.com"}
18
+ ]
19
+
20
+ # Dependencies required to run the core project
21
+ dependencies = [
22
+ "numpy>=1.20.0",
23
+ "scipy>=1.7",
24
+ "pandas>=1.3"
25
+ ]
26
+
27
+ keywords = ["neutron", "ray tracing", "Monte Carlo", "spectrometer", "triple-axis", "time-of-flight"]
28
+
29
+ classifiers = [
30
+ "Programming Language :: Python :: 3",
31
+ "Intended Audience :: Science/Research",
32
+ "Topic :: Scientific/Engineering :: Physics",
33
+ "Operating System :: OS Independent",
34
+ ]
35
+
36
+ [project.urls]
37
+ # External links for PyPI
38
+ Homepage = "https://github.com/gcdengansto/pyneutrace"
39
+ Documentation = "https://project.readthedocs.io/gcdengansto/pyneutrace"
40
+
41
+ [tool.setuptools.packages.find]
42
+ # Automatically find packages in a 'src' directory
43
+ where = ["src"]
44
+
45
+ [project.optional-dependencies]
46
+ # Optional groups for visualization and UI
47
+ gui = [
48
+ "matplotlib>=3.1.0",
49
+ "pyvista",
50
+ "QtPy",
51
+ "PySide6"
52
+ ]
53
+ # Optional groups for development
54
+ dev = [
55
+ "pytest>=7.0",
56
+ "black>=23.0"
57
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,56 @@
1
+ from .source import NeutronSource
2
+ from .nsource import NSource
3
+ from .moderator import Moderator
4
+ from .spacer import Spacer
5
+ from .soller import Soller
6
+ from .radcollimator import RadCollimator
7
+ from .neutronguide import NeutronGuide
8
+ from .singleellipticguide import SingleEllipticGuide
9
+ from .doubleparabolicguide import DoubleParabolicGuide
10
+ from .doubleellipticguide import DoubleEllipticGuide
11
+ from .diskchopper import DiskChopper
12
+ from .straightfermichopper import StraightFermiChopper
13
+ from .curvedfermichopper import CurvedFermiChopper
14
+ from .vsample import VRodSample
15
+ from .monitor import Monitor, CylindMonitor
16
+ from .monochromator import Monochromator
17
+ from .analyzer import Analyzer
18
+ from .cascadeanalyzer import CascadeAnalyzer
19
+ from .multicascadeanalyzer import MultiCascadeAnalyzer
20
+ from .velselector import VelSelector
21
+ from .powdersample import PowderSample
22
+ from .virtualfilter import VirtualFilterAndMultiplier
23
+
24
+ from .curvedguide import CurvedGuide
25
+ from .io_rays import ExportRays, ImportRays
26
+
27
+ from .singlecrystalsample import SingleCrystalSample
28
+
29
+ __all__ = [
30
+ "PowderSample",
31
+ "SingleCrystalSample",
32
+ "VirtualFilterAndMultiplier",
33
+ "CurvedGuide",
34
+ "ExportRays",
35
+ "ImportRays",
36
+ "VelSelector",
37
+ "NeutronSource",
38
+ "Moderator",
39
+ "Spacer",
40
+ "Soller",
41
+ "RadCollimator",
42
+ "NeutronGuide",
43
+ "SingleEllipticGuide",
44
+ "DoubleParabolicGuide",
45
+ "DoubleEllipticGuide",
46
+ "DiskChopper",
47
+ "StraightFermiChopper",
48
+ "CurvedFermiChopper",
49
+ "VRodSample",
50
+ "Monitor",
51
+ "CylindMonitor",
52
+ "Monochromator",
53
+ "Analyzer",
54
+ "CascadeAnalyzer",
55
+ "MultiCascadeAnalyzer",
56
+ ]
@@ -0,0 +1,161 @@
1
+ import numpy as np
2
+
3
+ from .monochromator import Monochromator
4
+
5
+
6
+ class Analyzer(Monochromator):
7
+ """
8
+ Neutron monochromator simulation.
9
+
10
+ Parameters
11
+ ----------
12
+ entry_w, entry_h : entry window width / height [mm]
13
+ ana_w, ana_h : crystal width / height [mm]
14
+ exit_w, exit_h : exit window width / height [mm]
15
+ length : entry-window → crystal centre distance [mm]
16
+ rotation : Bragg angle (half of 2θ) [degrees]
17
+ crystal : crystal type string, e.g. "PG"
18
+ mosaicity : crystal mosaicity FWHM [degrees]
19
+ focus : "NONE" | "DOUBLE" | "HF_ONLY" | "VF_ONLY"
20
+ ana_vr : vertical focusing radius [mm]
21
+ ana_hr : horizontal focusing radius [mm]
22
+ L1 : sample-to-analyzer distance [mm] (for optimal-R calc only)
23
+ L2 : analyzer-to-detector distance [mm] (for optimal-R calc only)
24
+ second_order : if True, allow λ/2 contamination (only for PG)
25
+ rng_seed : optional int seed for reproducibility
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ entry_w = 60,
31
+ entry_h = 100,
32
+ ana_w = 120,
33
+ ana_h = 100,
34
+ exit_w = 60,
35
+ exit_h = 100,
36
+ length = 400,
37
+ rotation = 45,
38
+ crystal = "PG",
39
+ mosaicity = 0.3,
40
+ focus = "NONE",
41
+ ana_vr = None,
42
+ ana_hr = None,
43
+ L1 = 1500,
44
+ L2 = 500,
45
+ second_order = None,
46
+ rng_seed = None,
47
+ reflectivity = 1.0,
48
+ exit_capture_mode = "position",
49
+ ):
50
+ super().__init__(
51
+ entry_w=entry_w,
52
+ entry_h=entry_h,
53
+ mono_w=ana_w,
54
+ mono_h=ana_h,
55
+ exit_w=exit_w,
56
+ exit_h=exit_h,
57
+ length=length,
58
+ rotation=rotation,
59
+ crystal=crystal,
60
+ mosaicity=mosaicity,
61
+ focus=focus,
62
+ mono_vr=ana_vr,
63
+ mono_hr=ana_hr,
64
+ L1=L1,
65
+ L2=L2,
66
+ second_order=second_order,
67
+ rng_seed=rng_seed,
68
+ reflectivity=reflectivity,
69
+ )
70
+ self.exit_capture_mode = self._validate_exit_capture_mode(exit_capture_mode)
71
+ self.exit_capture = self._empty_exit_capture()
72
+
73
+ @staticmethod
74
+ def _validate_exit_capture_mode(mode):
75
+ if mode not in ("position", "full"):
76
+ raise ValueError(
77
+ f"exit_capture_mode must be 'position' or 'full'. Got '{mode}'."
78
+ )
79
+ return mode
80
+
81
+ def _empty_exit_capture(self):
82
+ capture = {
83
+ "x": np.empty((0,), dtype=float),
84
+ "y": np.empty((0,), dtype=float),
85
+ "z": np.empty((0,), dtype=float),
86
+ "weight": np.empty((0,), dtype=float),
87
+ }
88
+ if self.exit_capture_mode == "full":
89
+ capture.update({
90
+ "vx": np.empty((0,), dtype=float),
91
+ "vy": np.empty((0,), dtype=float),
92
+ "vz": np.empty((0,), dtype=float),
93
+ "time": None,
94
+ })
95
+ return capture
96
+
97
+ def _record_exit_capture(self, final_pos, final_vel, final_time, final_weight):
98
+ self.exit_capture = {
99
+ "x": final_pos[:, 0].copy(),
100
+ "y": final_pos[:, 1].copy(),
101
+ "z": final_pos[:, 2].copy(),
102
+ "weight": final_weight.copy(),
103
+ }
104
+ if self.exit_capture_mode == "full":
105
+ self.exit_capture.update({
106
+ "vx": final_vel[:, 0].copy(),
107
+ "vy": final_vel[:, 1].copy(),
108
+ "vz": final_vel[:, 2].copy(),
109
+ "time": None if final_time is None else final_time.copy(),
110
+ })
111
+
112
+ def propagate_TOF(
113
+ self,
114
+ initPos,
115
+ initVel,
116
+ initTime=None,
117
+ initWeight=None,
118
+ ):
119
+ final_pos, final_vel, final_time, final_weight, survived = super().propagate_TOF(
120
+ initPos,
121
+ initVel,
122
+ initTime=initTime,
123
+ initWeight=initWeight,
124
+ )
125
+ self._record_exit_capture(final_pos, final_vel, final_time, final_weight)
126
+ return final_pos, final_vel, final_time, final_weight, survived
127
+
128
+ @property
129
+ def ana_w(self):
130
+ return self.mono_w
131
+
132
+ @ana_w.setter
133
+ def ana_w(self, value):
134
+ self.mono_w = value
135
+
136
+
137
+ @property
138
+ def ana_h(self):
139
+ return self.mono_h
140
+
141
+ @ana_h.setter
142
+ def ana_h(self, value):
143
+ self.mono_h = value
144
+
145
+
146
+ @property
147
+ def ana_vr(self):
148
+ return self.mono_vr
149
+
150
+ @ana_vr.setter
151
+ def ana_vr(self, value):
152
+ self.mono_vr = value
153
+
154
+
155
+ @property
156
+ def ana_hr(self):
157
+ return self.mono_hr
158
+
159
+ @ana_hr.setter
160
+ def ana_hr(self, value):
161
+ self.mono_hr = value