goad-py 1.2.2__tar.gz → 1.3.0__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 (135) hide show
  1. {goad_py-1.2.2 → goad_py-1.3.0}/Cargo.lock +2 -1
  2. {goad_py-1.2.2 → goad_py-1.3.0}/Cargo.toml +2 -2
  3. {goad_py-1.2.2 → goad_py-1.3.0}/PKG-INFO +1 -1
  4. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/main.rs +8 -3
  5. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/run_ensemble.py +3 -5
  6. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/run_individual.py +3 -5
  7. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/run_roughness_sweep.py +3 -5
  8. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/run_simulation.py +5 -6
  9. {goad_py-1.2.2 → goad_py-1.3.0}/examples/capture_vertices.rs +8 -7
  10. {goad_py-1.2.2 → goad_py-1.3.0}/examples/convergence.rs +5 -3
  11. {goad_py-1.2.2 → goad_py-1.3.0}/examples/distortion.rs +6 -2
  12. goad_py-1.3.0/examples/field_at_initial_beam.rs +84 -0
  13. {goad_py-1.2.2 → goad_py-1.3.0}/examples/lidar_batch_test.rs +10 -4
  14. {goad_py-1.2.2 → goad_py-1.3.0}/examples/lidar_convergence_test.rs +6 -2
  15. {goad_py-1.2.2 → goad_py-1.3.0}/examples/multiproblem.rs +4 -2
  16. {goad_py-1.2.2 → goad_py-1.3.0}/examples/problem-diff.rs +5 -2
  17. {goad_py-1.2.2 → goad_py-1.3.0}/examples/problem1.rs +4 -2
  18. {goad_py-1.2.2 → goad_py-1.3.0}/examples/regen_mueller_refs/main.rs +2 -1
  19. goad_py-1.3.0/examples/schematic_field_dump.rs +426 -0
  20. goad_py-1.3.0/examples/tmp_dump_recording.rs +113 -0
  21. {goad_py-1.2.2 → goad_py-1.3.0}/pyproject.toml +1 -1
  22. {goad_py-1.2.2 → goad_py-1.3.0}/src/beam.rs +57 -50
  23. {goad_py-1.2.2 → goad_py-1.3.0}/src/clip.rs +17 -23
  24. {goad_py-1.2.2 → goad_py-1.3.0}/src/convergence/python.rs +15 -15
  25. {goad_py-1.2.2 → goad_py-1.3.0}/src/convergence.rs +3 -3
  26. {goad_py-1.2.2 → goad_py-1.3.0}/src/field.rs +9 -0
  27. {goad_py-1.2.2 → goad_py-1.3.0}/src/geom.rs +241 -39
  28. {goad_py-1.2.2 → goad_py-1.3.0}/src/lib.rs +1 -0
  29. {goad_py-1.2.2 → goad_py-1.3.0}/src/main.rs +3 -2
  30. {goad_py-1.2.2 → goad_py-1.3.0}/src/multiproblem.rs +38 -41
  31. {goad_py-1.2.2 → goad_py-1.3.0}/src/problem.rs +148 -170
  32. goad_py-1.3.0/src/recording.rs +625 -0
  33. {goad_py-1.2.2 → goad_py-1.3.0}/src/settings/cli.rs +62 -12
  34. {goad_py-1.2.2 → goad_py-1.3.0}/src/settings/constants.rs +10 -3
  35. {goad_py-1.2.2 → goad_py-1.3.0}/src/settings/loading.rs +1 -1
  36. {goad_py-1.2.2 → goad_py-1.3.0}/src/settings.rs +76 -70
  37. {goad_py-1.2.2 → goad_py-1.3.0}/tests/common/cases.rs +2 -2
  38. {goad_py-1.2.2 → goad_py-1.3.0}/tests/compare_solvers.rs +13 -7
  39. {goad_py-1.2.2 → goad_py-1.3.0}/tests/convergence_merge_tests.rs +8 -2
  40. {goad_py-1.2.2 → goad_py-1.3.0}/tests/helpers.rs +48 -11
  41. {goad_py-1.2.2 → goad_py-1.3.0}/tests/optical_theorem_tests.rs +11 -10
  42. {goad_py-1.2.2 → goad_py-1.3.0}/.github/workflows/CI.yml +0 -0
  43. {goad_py-1.2.2 → goad_py-1.3.0}/.gitignore +0 -0
  44. {goad_py-1.2.2 → goad_py-1.3.0}/LICENSE +0 -0
  45. {goad_py-1.2.2 → goad_py-1.3.0}/README.md +0 -0
  46. {goad_py-1.2.2 → goad_py-1.3.0}/config/default.toml +0 -0
  47. {goad_py-1.2.2 → goad_py-1.3.0}/config_editor.sh +0 -0
  48. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/generate_ensemble.py +0 -0
  49. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/generate_plate.py +0 -0
  50. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/generate_roughness_sweep.py +0 -0
  51. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/plate-render.png +0 -0
  52. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/plot_roughness_sweep.py +0 -0
  53. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/results.json +0 -0
  54. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/roughened_edge15.0_sigma0p1_merge1p0_hexagonal_column_l5.0_r25.0_6904c8.obj +0 -0
  55. {goad_py-1.2.2 → goad_py-1.3.0}/examples/backscattering/settings.json +0 -0
  56. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/8col.obj +0 -0
  57. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/clip_test.obj +0 -0
  58. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/concave1.obj +0 -0
  59. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/concave2.obj +0 -0
  60. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cone.obj +0 -0
  61. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cube.obj +0 -0
  62. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cube2.obj +0 -0
  63. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cube_inside_cube.obj +0 -0
  64. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cube_inside_hex.obj +0 -0
  65. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cube_inside_ico.obj +0 -0
  66. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/cubes.obj +0 -0
  67. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex.obj +0 -0
  68. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex2.obj +0 -0
  69. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex3.obj +0 -0
  70. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex4.obj +0 -0
  71. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex5.obj +0 -0
  72. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex6.obj +0 -0
  73. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex7.obj +0 -0
  74. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex_20_30_30.obj +0 -0
  75. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex_distort.obj +0 -0
  76. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex_hollow.obj +0 -0
  77. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/hex_indented.obj +0 -0
  78. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/icosphere1.obj +0 -0
  79. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/multiple.obj +0 -0
  80. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/multiple2.obj +0 -0
  81. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/multiple3.obj +0 -0
  82. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/octo.obj +0 -0
  83. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/octo2.obj +0 -0
  84. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/para.obj +0 -0
  85. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/para_rough1.obj +0 -0
  86. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/plane_xy.obj +0 -0
  87. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/plane_xy_rect.obj +0 -0
  88. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/plane_xy_rect_split.obj +0 -0
  89. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/plane_yz.obj +0 -0
  90. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/plate.obj +0 -0
  91. {goad_py-1.2.2 → goad_py-1.3.0}/examples/data/plate_distort.obj +0 -0
  92. {goad_py-1.2.2 → goad_py-1.3.0}/examples/diffraction_plot.rs +0 -0
  93. {goad_py-1.2.2 → goad_py-1.3.0}/examples/simplify.rs +0 -0
  94. {goad_py-1.2.2 → goad_py-1.3.0}/mkdocs.yml +0 -0
  95. {goad_py-1.2.2 → goad_py-1.3.0}/python/goad/__init__.py +0 -0
  96. {goad_py-1.2.2 → goad_py-1.3.0}/python/goad/_goad.pyi +0 -0
  97. {goad_py-1.2.2 → goad_py-1.3.0}/python/goad/bar.py +0 -0
  98. {goad_py-1.2.2 → goad_py-1.3.0}/python/goad/py.typed +0 -0
  99. {goad_py-1.2.2 → goad_py-1.3.0}/setup.sh +0 -0
  100. {goad_py-1.2.2 → goad_py-1.3.0}/src/_quickstart.rs +0 -0
  101. {goad_py-1.2.2 → goad_py-1.3.0}/src/bin/stub_gen.rs +0 -0
  102. {goad_py-1.2.2 → goad_py-1.3.0}/src/bins.rs +0 -0
  103. {goad_py-1.2.2 → goad_py-1.3.0}/src/cancel.rs +0 -0
  104. {goad_py-1.2.2 → goad_py-1.3.0}/src/containment.rs +0 -0
  105. {goad_py-1.2.2 → goad_py-1.3.0}/src/convergence/convergeable.rs +0 -0
  106. {goad_py-1.2.2 → goad_py-1.3.0}/src/convergence/progress.rs +0 -0
  107. {goad_py-1.2.2 → goad_py-1.3.0}/src/diff.rs +0 -0
  108. {goad_py-1.2.2 → goad_py-1.3.0}/src/diff2.rs +0 -0
  109. {goad_py-1.2.2 → goad_py-1.3.0}/src/distortion.rs +0 -0
  110. {goad_py-1.2.2 → goad_py-1.3.0}/src/filelog.rs +0 -0
  111. {goad_py-1.2.2 → goad_py-1.3.0}/src/fresnel.rs +0 -0
  112. {goad_py-1.2.2 → goad_py-1.3.0}/src/orientation.rs +0 -0
  113. {goad_py-1.2.2 → goad_py-1.3.0}/src/output.rs +0 -0
  114. {goad_py-1.2.2 → goad_py-1.3.0}/src/params.rs +0 -0
  115. {goad_py-1.2.2 → goad_py-1.3.0}/src/powers.rs +0 -0
  116. {goad_py-1.2.2 → goad_py-1.3.0}/src/python.rs +0 -0
  117. {goad_py-1.2.2 → goad_py-1.3.0}/src/result/component.rs +0 -0
  118. {goad_py-1.2.2 → goad_py-1.3.0}/src/result/integrate.rs +0 -0
  119. {goad_py-1.2.2 → goad_py-1.3.0}/src/result/mueller.rs +0 -0
  120. {goad_py-1.2.2 → goad_py-1.3.0}/src/result/python.rs +0 -0
  121. {goad_py-1.2.2 → goad_py-1.3.0}/src/result/results.rs +0 -0
  122. {goad_py-1.2.2 → goad_py-1.3.0}/src/result/scatt_result.rs +0 -0
  123. {goad_py-1.2.2 → goad_py-1.3.0}/src/result.rs +0 -0
  124. {goad_py-1.2.2 → goad_py-1.3.0}/src/settings/validation.rs +0 -0
  125. {goad_py-1.2.2 → goad_py-1.3.0}/src/snell.rs +0 -0
  126. {goad_py-1.2.2 → goad_py-1.3.0}/src/zones.rs +0 -0
  127. {goad_py-1.2.2 → goad_py-1.3.0}/template/custom_bins.toml +0 -0
  128. {goad_py-1.2.2 → goad_py-1.3.0}/template/goad_pbs.sh +0 -0
  129. {goad_py-1.2.2 → goad_py-1.3.0}/tests/diffraction_tests.rs +0 -0
  130. {goad_py-1.2.2 → goad_py-1.3.0}/tests/mueller_regression_tests.rs +0 -0
  131. {goad_py-1.2.2 → goad_py-1.3.0}/tests/orientation_sampling_tests.rs +0 -0
  132. {goad_py-1.2.2 → goad_py-1.3.0}/tests/test_basic.py +0 -0
  133. {goad_py-1.2.2 → goad_py-1.3.0}/tests/test_data/fixed_hex_30_20_20_mueller_scatgrid +0 -0
  134. {goad_py-1.2.2 → goad_py-1.3.0}/tests/test_data/fixed_hex_30_30_30_mueller_scatgrid +0 -0
  135. {goad_py-1.2.2 → goad_py-1.3.0}/tests/test_data/hex.obj +0 -0
@@ -753,7 +753,7 @@ dependencies = [
753
753
 
754
754
  [[package]]
755
755
  name = "goad"
756
- version = "1.2.2"
756
+ version = "1.3.0"
757
757
  dependencies = [
758
758
  "anyhow",
759
759
  "chrono",
@@ -1505,6 +1505,7 @@ dependencies = [
1505
1505
  "indoc",
1506
1506
  "libc",
1507
1507
  "memoffset",
1508
+ "num-complex",
1508
1509
  "once_cell",
1509
1510
  "portable-atomic",
1510
1511
  "pyo3-build-config",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "goad"
3
- version = "1.2.2"
3
+ version = "1.3.0"
4
4
  edition = "2021"
5
5
  license = "GPL-3.0"
6
6
  description = "Compute the single scattering properties of particles much larger than the wavelength of light with geometric optics and aperture diffraction theory."
@@ -25,7 +25,7 @@ readme = "README.md"
25
25
  ndarray = "0.15"
26
26
  num-complex = { version = "0.4.6", features = ["serde"] }
27
27
  numpy = "0.27.0"
28
- pyo3 = { version = "0.27.1"}
28
+ pyo3 = { version = "0.27.1", features = ["num-complex"] }
29
29
  pyo3-stub-gen = { version = "0.17", optional = true }
30
30
  rand = "0.9.0"
31
31
  rand_distr = "0.5.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: goad-py
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Topic :: Scientific/Engineering :: Physics
@@ -3,6 +3,7 @@
3
3
  //! Run with: cargo run --release --example backscattering
4
4
 
5
5
  use goad::convergence::Convergence;
6
+ use goad::geom::Geom;
6
7
  use goad::params::Param;
7
8
  use goad::settings;
8
9
  use std::path::PathBuf;
@@ -16,9 +17,7 @@ fn main() -> anyhow::Result<()> {
16
17
 
17
18
  // Load settings from defaults and override
18
19
  let mut settings = settings::load_default_config()?;
19
- settings.geom_name = geometry_file.to_string_lossy().to_string();
20
20
  settings.wavelength = 0.532;
21
- settings.particle_refr_index = vec![nalgebra::Complex::new(1.31, 0.0)];
22
21
  settings.zones = vec![]; // empty zones for backscatter only
23
22
  settings.max_tir = 20;
24
23
  settings.beam_area_threshold_fac = 0.01;
@@ -27,8 +26,14 @@ fn main() -> anyhow::Result<()> {
27
26
  settings.directory = output_dir.clone();
28
27
  settings.quiet = false;
29
28
 
29
+ // Load geometry with its refractive index
30
+ let geoms = Geom::load(
31
+ geometry_file.to_str().expect("non-utf8 geometry path"),
32
+ vec![nalgebra::Complex::new(1.31, 0.0)],
33
+ )?;
34
+
30
35
  // Create convergence solver
31
- let mut convergence = Convergence::new(None, Some(settings))?;
36
+ let mut convergence = Convergence::new(geoms, Some(settings))?;
32
37
 
33
38
  // Add targets: 5% error on lidar ratio and depolarization ratio
34
39
  convergence.add_target(Param::LidarRatio, 0.05);
@@ -3,7 +3,7 @@
3
3
  import json
4
4
  from pathlib import Path
5
5
 
6
- from goad import Convergence, Param, Settings
6
+ from goad import Convergence, Geom, Param, Settings
7
7
 
8
8
  base_dir = Path(__file__).parent
9
9
  ensemble_dir = base_dir / "ensemble"
@@ -11,11 +11,9 @@ results_dir = base_dir / "ensemble_results"
11
11
  results_dir.mkdir(exist_ok=True)
12
12
 
13
13
  # Pass the directory containing all OBJ files for ensemble averaging
14
+ geoms = Geom.from_file(str(ensemble_dir), [1.31 + 0j])
14
15
  settings = Settings(
15
- geom_path=str(ensemble_dir),
16
16
  wavelength=0.532,
17
- particle_refr_index_re=1.31,
18
- particle_refr_index_im=0.0,
19
17
  zones=[],
20
18
  max_tir=20,
21
19
  directory=str(results_dir),
@@ -24,7 +22,7 @@ settings = Settings(
24
22
  cutoff=0.999,
25
23
  )
26
24
 
27
- convergence = Convergence(settings)
25
+ convergence = Convergence(settings, geoms)
28
26
  convergence.add_target(Param.LidarRatio, 0.1)
29
27
  convergence.add_target(Param.DepolarizationRatio, 0.1)
30
28
  convergence.add_target(Param.BackscatterCross, 0.1)
@@ -3,7 +3,7 @@
3
3
  import json
4
4
  from pathlib import Path
5
5
 
6
- from goad import Convergence, Param, Settings
6
+ from goad import Convergence, Geom, Param, Settings
7
7
 
8
8
  base_dir = Path(__file__).parent
9
9
  ensemble_dir = base_dir / "ensemble"
@@ -24,11 +24,9 @@ for i, geometry_file in enumerate(obj_files):
24
24
  particle_dir = results_dir / f"particle_{i + 1}"
25
25
  particle_dir.mkdir(exist_ok=True)
26
26
 
27
+ geoms = Geom.from_file(str(geometry_file), [1.31 + 0j])
27
28
  settings = Settings(
28
- geom_path=str(geometry_file),
29
29
  wavelength=0.532,
30
- particle_refr_index_re=1.31,
31
- particle_refr_index_im=0.0,
32
30
  zones=[],
33
31
  max_tir=20,
34
32
  directory=str(particle_dir),
@@ -37,7 +35,7 @@ for i, geometry_file in enumerate(obj_files):
37
35
  cutoff=0.999,
38
36
  )
39
37
 
40
- convergence = Convergence(settings)
38
+ convergence = Convergence(settings, geoms)
41
39
  convergence.add_target(Param.LidarRatio, 0.1)
42
40
  convergence.add_target(Param.DepolarizationRatio, 0.1)
43
41
  convergence.add_target(Param.BackscatterCross, 0.1)
@@ -3,7 +3,7 @@
3
3
  import json
4
4
  from pathlib import Path
5
5
 
6
- from goad import Convergence, Param, Settings
6
+ from goad import Convergence, Geom, Param, Settings
7
7
 
8
8
  base_dir = Path(__file__).parent
9
9
 
@@ -20,11 +20,9 @@ for sigma in roughness_levels:
20
20
  print(f"Running ensemble for sigma={sigma}")
21
21
  print(f"{'=' * 60}")
22
22
 
23
+ geoms = Geom.from_file(str(ensemble_dir), [1.31 + 0j])
23
24
  settings = Settings(
24
- geom_path=str(ensemble_dir),
25
25
  wavelength=0.532,
26
- particle_refr_index_re=1.31,
27
- particle_refr_index_im=0.0,
28
26
  zones=[],
29
27
  max_tir=20,
30
28
  directory=str(results_dir),
@@ -33,7 +31,7 @@ for sigma in roughness_levels:
33
31
  cutoff=0.999,
34
32
  )
35
33
 
36
- convergence = Convergence(settings)
34
+ convergence = Convergence(settings, geoms)
37
35
  convergence.add_target(Param.LidarRatio, 0.025)
38
36
  convergence.add_target(Param.DepolarizationRatio, 0.025)
39
37
  convergence.add_target(Param.BackscatterCross, 0.025)
@@ -2,7 +2,7 @@
2
2
 
3
3
  from pathlib import Path
4
4
 
5
- from goad import Convergence, Param, Settings
5
+ from goad import Convergence, Geom, Param, Settings
6
6
 
7
7
  output_dir = Path(__file__).parent
8
8
 
@@ -12,16 +12,15 @@ geometry_file = (
12
12
  / "roughened_edge15.0_sigma0p1_merge1p0_hexagonal_column_l5.0_r25.0_6904c8.obj"
13
13
  )
14
14
 
15
+ # Load geometry with the ice refractive index
16
+ geoms = Geom.from_file(str(geometry_file), [1.31 + 0j])
17
+
15
18
  # Set up simulation settings
16
19
  # - wavelength 0.532 microns (green laser)
17
- # - ice refractive index 1.31
18
20
  # - empty zones for faster computation (just forward and backward scattering)
19
21
  # - high max_tir for backscattering
20
22
  settings = Settings(
21
- geom_path=str(geometry_file),
22
23
  wavelength=0.532,
23
- particle_refr_index_re=1.31,
24
- particle_refr_index_im=0.0,
25
24
  zones=[],
26
25
  max_tir=20,
27
26
  directory=str(output_dir),
@@ -31,7 +30,7 @@ settings = Settings(
31
30
  )
32
31
 
33
32
  # Set up convergence solver
34
- convergence = Convergence(settings)
33
+ convergence = Convergence(settings, geoms)
35
34
 
36
35
  # Converge on lidar ratio and depolarisation ratio within 10% error
37
36
  convergence.add_target(Param.LidarRatio, 0.1)
@@ -1,5 +1,6 @@
1
1
  use goad::clip::Clipping;
2
- use goad::geom::{Geom, Face};
2
+ use goad::geom::{Face, Geom};
3
+ use goad::settings::DEFAULT_PARTICLE_REFR_INDEX;
3
4
  use nalgebra::{Point3, Vector3};
4
5
 
5
6
  fn main() {
@@ -23,7 +24,7 @@ fn main() {
23
24
  }
24
25
 
25
26
  fn test_projection_debug() {
26
- let geoms = Geom::load("./examples/data/hex.obj").unwrap();
27
+ let geoms = Geom::load("./examples/data/hex.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
27
28
  let mut geom = geoms[0].clone();
28
29
  let mut clip = geom.shapes[0].faces.remove(4);
29
30
  let projection = Vector3::new(0.0, 0.0, -1.0);
@@ -35,7 +36,7 @@ fn test_projection_debug() {
35
36
  }
36
37
 
37
38
  fn test_projection1() {
38
- let geoms = Geom::load("./examples/data/concave1.obj").unwrap();
39
+ let geoms = Geom::load("./examples/data/concave1.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
39
40
  let mut geom = geoms[0].clone();
40
41
  let mut clip = geom.shapes[0].faces.remove(4);
41
42
  let projection = Vector3::new(-0.3, 0.0, -1.0);
@@ -47,7 +48,7 @@ fn test_projection1() {
47
48
  }
48
49
 
49
50
  fn test_projection2() {
50
- let geoms = Geom::load("./examples/data/cube_inside_ico.obj").unwrap();
51
+ let geoms = Geom::load("./examples/data/cube_inside_ico.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
51
52
  let mut geom = geoms[0].clone();
52
53
  let mut clip = geom.shapes[0].faces.remove(5);
53
54
  let projection = Vector3::new(-0.2, 0.0, -1.0);
@@ -59,7 +60,7 @@ fn test_projection2() {
59
60
  }
60
61
 
61
62
  fn test_projection_multi() {
62
- let geoms = Geom::load("./examples/data/multiple.obj").unwrap();
63
+ let geoms = Geom::load("./examples/data/multiple.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
63
64
  let mut geom = geoms[0].clone();
64
65
  let mut clip = geom.shapes[0].faces.remove(5);
65
66
  let projection = Vector3::new(-1.0, 0.0, 0.0);
@@ -71,7 +72,7 @@ fn test_projection_multi() {
71
72
  }
72
73
 
73
74
  fn test_clip_test() {
74
- let geoms = Geom::load("./examples/data/clip_test.obj").unwrap();
75
+ let geoms = Geom::load("./examples/data/clip_test.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
75
76
  let mut geom = geoms[0].clone();
76
77
  let mut clip = geom.shapes[1].faces.remove(1);
77
78
  let projection = Vector3::new(1.0, 1.0, 0.0);
@@ -83,7 +84,7 @@ fn test_clip_test() {
83
84
  }
84
85
 
85
86
  fn test_remainder() {
86
- let geoms = Geom::load("./examples/data/multiple.obj").unwrap();
87
+ let geoms = Geom::load("./examples/data/multiple.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
87
88
  let mut geom = geoms[0].clone();
88
89
  let projection = Vector3::new(0.0, 0.0, -1.0);
89
90
 
@@ -1,15 +1,17 @@
1
1
  // --8<-- [start:convergence]
2
2
  fn main() {
3
3
  use goad::convergence::Convergence;
4
+ use goad::geom::Geom;
4
5
  use goad::params::Param;
5
6
  use goad::result::GOComponent;
6
- use goad::settings;
7
+ use goad::settings::{self, DEFAULT_PARTICLE_REFR_INDEX};
7
8
 
8
- // Load default settings
9
+ // Load default settings and geometry
9
10
  let settings = settings::load_default_config().unwrap();
11
+ let geoms = Geom::load("./examples/data/hex.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
10
12
 
11
13
  // Create a convergence solver
12
- let mut convergence = Convergence::new(None, Some(settings)).unwrap();
14
+ let mut convergence = Convergence::new(geoms, Some(settings)).unwrap();
13
15
 
14
16
  // Set convergence target: 1% relative SEM on asymmetry parameter
15
17
  convergence.add_target(Param::Asymmetry, 0.03);
@@ -1,5 +1,7 @@
1
1
  use goad::cancel::CancelToken;
2
+ use goad::geom::Geom;
2
3
  use goad::problem::Problem;
4
+ use goad::settings::DEFAULT_PARTICLE_REFR_INDEX;
3
5
 
4
6
  // --8<-- [start:multiproblem]
5
7
  fn main() {
@@ -9,14 +11,16 @@ fn main() {
9
11
  let mut base_settings = settings::load_default_config().unwrap();
10
12
  base_settings.quiet = true;
11
13
  // base_settings.geom_scale = Some(vec![2.622, 2.622, 3.745]);
12
- base_settings.geom_name = "examples/data/hex.obj".to_string();
13
14
 
14
15
  let distortions = vec![0.1];
15
16
 
16
17
  for distortion in distortions {
17
18
  let mut settings = base_settings.clone();
18
19
  settings.distortion = Some(distortion);
19
- let mut problem = Problem::new(None, Some(settings)).unwrap();
20
+ let geom = Geom::load("examples/data/hex.obj", vec![DEFAULT_PARTICLE_REFR_INDEX])
21
+ .unwrap()
22
+ .remove(0);
23
+ let mut problem = Problem::new(geom, Some(settings)).unwrap();
20
24
  let _ = problem.run(None, &CancelToken::noop());
21
25
  let _ = problem.geom.write_obj(format!("file_{}.obj", distortion));
22
26
  let _ = problem.writeup();
@@ -0,0 +1,84 @@
1
+ //! Sample the near-field at a handful of query points along the initial
2
+ //! incident beam.
3
+ //!
4
+ //! Runs a recorded solve on a hex geometry, filters the recording down to
5
+ //! just the initial illumination event, then asks `BeamView::fields_at`
6
+ //! for the field contribution at each query point.
7
+ //!
8
+ //! `settings.scale = Some(1.0)` opts out of the automatic rescale-to-unit-
9
+ //! cube that `Problem::init` would otherwise apply, so query points and
10
+ //! reported distances are in the same units as the geometry file.
11
+
12
+ use goad::beam::BeamVariant;
13
+ use goad::cancel::CancelToken;
14
+ use goad::geom::Geom;
15
+ use goad::problem::Problem;
16
+ use goad::settings::{load_default_config, DEFAULT_PARTICLE_REFR_INDEX};
17
+ use nalgebra::Point3;
18
+
19
+ fn main() {
20
+ // 1. Load default settings and pin the scale so the geometry isn't
21
+ // rescaled. Coordinates below are then in the hex.obj's native
22
+ // units (vertices at z = ±5, hex radius ≈ 5).
23
+ let mut settings = load_default_config().expect("load default config");
24
+ settings.scale = Some(1.0);
25
+
26
+ let geoms = Geom::load("./examples/data/hex.obj", vec![DEFAULT_PARTICLE_REFR_INDEX])
27
+ .expect("load hex");
28
+ let geom = geoms[0].clone();
29
+ let mut problem = Problem::new(geom, Some(settings)).expect("build problem");
30
+
31
+ // 2. Run the full recorded pipeline (init → orient → illuminate →
32
+ // near-field with recording → far-field → mueller → params).
33
+ // `None` for euler → no rotation; geometry sits as loaded.
34
+ let recording = problem
35
+ .run_with_recording(None, &CancelToken::noop())
36
+ .expect("recorded solve");
37
+
38
+ println!("recorded {} propagation events", recording.len());
39
+
40
+ // 3. Filter the view to just the initial illumination event.
41
+ let view = recording.view().variant(BeamVariant::Initial);
42
+ let initial_events: Vec<_> = view.events().collect();
43
+ println!("initial events in view: {}", initial_events.len());
44
+
45
+ // 4. Pick a few query points. The default illumination travels along
46
+ // -z from a quad above the geometry. With FAC=1.1 in
47
+ // basic_initial_beam and hex top at z = 5, the illumination face
48
+ // sits at z ≈ 5.5, so the initial beam's column spans
49
+ // z ∈ [5.0, 5.5]. We sample inside that slab, plus two negative
50
+ // controls (upstream of the start, off-footprint in xy).
51
+ let query_points = vec![
52
+ Point3::new(0.0, 0.0, 5.4), // inside the initial slab, near start
53
+ Point3::new(0.0, 0.0, 5.2), // inside, mid-slab
54
+ Point3::new(0.0, 0.0, 5.05), // inside, near front cap
55
+ Point3::new(0.0, 0.0, 10.0), // upstream of illumination — outside
56
+ Point3::new(0.0, 0.0, 0.0), // inside the geometry — past front cap
57
+ Point3::new(20.0, 0.0, 5.2), // off the illumination footprint in xy
58
+ ];
59
+
60
+ let results = view.fields_at(&query_points);
61
+
62
+ // 5. Report per-point contributions.
63
+ for (i, contribs) in results.iter().enumerate() {
64
+ let p = &query_points[i];
65
+ println!(
66
+ "\npoint ({:.3}, {:.3}, {:.3}): {} contribution(s)",
67
+ p.x,
68
+ p.y,
69
+ p.z,
70
+ contribs.len()
71
+ );
72
+ for c in contribs {
73
+ println!(
74
+ " event {} output {} kind={:?} distance={:.4} intensity={:.4e} phase={:.4}",
75
+ c.event_id,
76
+ c.output_index,
77
+ c.kind,
78
+ c.distance,
79
+ c.field.intensity(),
80
+ c.field.phase(),
81
+ );
82
+ }
83
+ }
84
+ }
@@ -5,6 +5,7 @@ use std::path::PathBuf;
5
5
  use std::time::Instant;
6
6
 
7
7
  use goad::convergence::Convergence;
8
+ use goad::geom::Geom;
8
9
  use goad::orientation::{EulerConvention, Orientation, Scheme};
9
10
  use goad::params::Param;
10
11
  use goad::result::GOComponent;
@@ -52,8 +53,6 @@ fn run_single_config(
52
53
  let settings = Settings {
53
54
  wavelength: WAVELENGTH_UM,
54
55
  medium_refr_index: Complex::new(1.0, 0.0),
55
- particle_refr_index: vec![Complex::new(REFR_INDEX_RE, REFR_INDEX_IM)],
56
- geom_name: geom_dir.to_string_lossy().to_string(),
57
56
  zones: vec![], // Empty zones = auto Forward/Backward
58
57
  max_tir: MAX_TIR,
59
58
  max_rec: 10,
@@ -66,7 +65,7 @@ fn run_single_config(
66
65
  euler_convention: EulerConvention::ZYZ,
67
66
  },
68
67
  seed: None,
69
- scale: 1.0,
68
+ scale: Some(1.0),
70
69
  distortion: None,
71
70
  geom_scale: None,
72
71
  fov_factor: None,
@@ -86,8 +85,15 @@ fn run_single_config(
86
85
  binning: None,
87
86
  };
88
87
 
88
+ // Load all geometries in the directory with the configured refractive index
89
+ let geoms = Geom::load(
90
+ geom_dir.to_str().ok_or("non-utf8 geom dir")?,
91
+ vec![Complex::new(REFR_INDEX_RE, REFR_INDEX_IM)],
92
+ )
93
+ .map_err(|e| e.to_string())?;
94
+
89
95
  // Create convergence solver
90
- let mut convergence = Convergence::new(None, Some(settings)).map_err(|e| e.to_string())?;
96
+ let mut convergence = Convergence::new(geoms, Some(settings)).map_err(|e| e.to_string())?;
91
97
 
92
98
  // Enable logging
93
99
  let log_file = results_dir.join("convergence_log.csv");
@@ -3,10 +3,11 @@
3
3
 
4
4
  fn main() {
5
5
  use goad::convergence::Convergence;
6
+ use goad::geom::Geom;
6
7
  use goad::orientation::{Orientation, Scheme};
7
8
  use goad::params::Param;
8
9
  use goad::result::GOComponent;
9
- use goad::settings;
10
+ use goad::settings::{self, DEFAULT_PARTICLE_REFR_INDEX};
10
11
 
11
12
  // Initialize logging
12
13
  env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
@@ -23,8 +24,11 @@ fn main() {
23
24
  euler_convention: settings.orientation.euler_convention,
24
25
  };
25
26
 
27
+ // Load default geometry separately (geom no longer lives in Settings)
28
+ let geoms = Geom::load("examples/data/hex.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
29
+
26
30
  // Create a convergence solver
27
- let mut convergence = Convergence::new(None, Some(settings)).unwrap();
31
+ let mut convergence = Convergence::new(geoms, Some(settings)).unwrap();
28
32
 
29
33
  // Enable logging of mean values during convergence
30
34
  convergence.set_log_file("lidar_convergence_running.csv");
@@ -1,10 +1,12 @@
1
1
  // --8<-- [start:multiproblem]
2
2
  fn main() {
3
3
  use goad::multiproblem::MultiProblem;
4
- use goad::settings;
4
+ use goad::settings::{self, cli};
5
5
 
6
6
  // Setup and run a multi-orientation problem with default settings
7
- let mut multiproblem = MultiProblem::new(None, settings::load_config().ok()).unwrap();
7
+ let settings = settings::load_config().ok();
8
+ let geoms = cli::load_geoms().expect("load geoms");
9
+ let mut multiproblem = MultiProblem::new(geoms, settings).unwrap();
8
10
  multiproblem.solve();
9
11
  }
10
12
  // --8<-- [end:multiproblem]
@@ -1,15 +1,18 @@
1
1
  use goad::cancel::CancelToken;
2
2
  use goad::geom::{self};
3
3
  use goad::problem::Problem;
4
+ use goad::settings::DEFAULT_PARTICLE_REFR_INDEX;
4
5
 
5
6
  fn main() {
6
- let geoms = geom::Geom::load("./examples/data/concave2.obj").unwrap();
7
+ let geoms =
8
+ geom::Geom::load("./examples/data/concave2.obj", vec![DEFAULT_PARTICLE_REFR_INDEX])
9
+ .unwrap();
7
10
  let mut geom = geoms[0].clone();
8
11
 
9
12
  geom.shapes[0].refr_index.re = 1.31;
10
13
  geom.shapes[0].refr_index.im = 0.001;
11
14
 
12
- let mut problem = Problem::new(Some(geom), None).unwrap();
15
+ let mut problem = Problem::new(geom, None).unwrap();
13
16
  problem.geom.write_obj("hex_hollow_rot.obj").unwrap();
14
17
 
15
18
  println!("Resetting problem...");
@@ -1,15 +1,17 @@
1
1
  use goad::cancel::CancelToken;
2
2
  use goad::geom::{self};
3
3
  use goad::problem::Problem;
4
+ use goad::settings::DEFAULT_PARTICLE_REFR_INDEX;
4
5
 
5
6
  fn main() {
6
- let geoms = geom::Geom::load("./examples/data/hex2.obj").unwrap();
7
+ let geoms =
8
+ geom::Geom::load("./examples/data/hex2.obj", vec![DEFAULT_PARTICLE_REFR_INDEX]).unwrap();
7
9
  let mut geom = geoms[0].clone();
8
10
 
9
11
  geom.shapes[0].refr_index.re = 1.5;
10
12
  geom.shapes[0].refr_index.im = 0.0001;
11
13
 
12
- let mut problem = Problem::new(Some(geom), None).unwrap();
14
+ let mut problem = Problem::new(geom, None).unwrap();
13
15
 
14
16
  problem.solve_near(&CancelToken::noop()).unwrap();
15
17
  }
@@ -43,7 +43,8 @@ fn main() {
43
43
  }
44
44
  wrote_any = true;
45
45
  let settings = (case.build_settings)();
46
- let mut mp = MultiProblem::new(None, Some(settings))
46
+ let geoms = (case.build_geoms)();
47
+ let mut mp = MultiProblem::new(geoms, Some(settings))
47
48
  .expect("Failed to create MultiProblem");
48
49
  mp.solve();
49
50