goad-py 0.5.5__tar.gz → 0.6.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.
Potentially problematic release.
This version of goad-py might be problematic. Click here for more details.
- {goad_py-0.5.5 → goad_py-0.6.0}/PKG-INFO +1 -1
- goad_py-0.6.0/goad-py/examples/direct/multiproblem_phips_example.py +163 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/09_phips_convergence.py +0 -3
- goad_py-0.6.0/goad-py/examples/unified/10_advanced_parameters.py +216 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/python/goad_py/unified_convergence.py +245 -3
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/src/lib.rs +4 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/pyproject.toml +1 -1
- {goad_py-0.5.5 → goad_py-0.6.0}/python/goad_py/unified_convergence.py +245 -3
- {goad_py-0.5.5 → goad_py-0.6.0}/src/settings.rs +50 -0
- goad_py-0.5.5/goad-py/examples/unified/09_phips_convergence_results.json +0 -220
- {goad_py-0.5.5 → goad_py-0.6.0}/.github/workflows/python.yml +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/.github/workflows/rust.yml +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/.gitignore +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/Cargo.lock +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/Cargo.toml +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/LICENSE +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/README-python.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/README.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/blender/addon/__init__.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/blender/addon/goad_py/__init__.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/blender/addon.zip +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/blender/build.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/blender/dev.blend +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/config/default.toml +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/config_editor.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/8col.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/clip_test.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/concave1.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/concave2.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cone.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cube.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cube2.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cube_inside_cube.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cube_inside_hex.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cube_inside_ico.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/cubes.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex2.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex3.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex4.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex5.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex6.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex7.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex_20_30_30.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex_distort.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex_hollow.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/hex_indented.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/icosphere1.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/multiple.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/multiple2.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/multiple3.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/octo.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/octo2.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/para.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/para_rough1.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/plane_xy.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/plane_yz.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/plate.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/data/plate_distort.obj +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/multi-problem.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/problem-diff.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/problem1.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/examples/simplify.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/.gitignore +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/CLAUDE.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/Cargo.toml +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/DISTRIBUTION.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/README-python.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/UNIFIED_API.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/UNIFIED_API_SUMMARY.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/build_and_test.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/build_wheels_local.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/convergence.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/README.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/README.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/backscatter_convergence_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/convergence_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/ensemble_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/multiproblem_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/phips_convergence_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/phips_ensemble_convergence_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/s11_convergence_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/direct/simple_example.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/01_simple_asymmetry.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/02_interval_binning.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/03_multiple_targets.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/04_mueller_element.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/05_backscatter_specific_bin.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/06_ensemble_convergence.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/07_advanced_config.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/08_parameter_sweep.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/examples/unified/README.md +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/goad_py.pyi +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/plot.ipynb +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/publish_test.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/python/goad_py/__init__.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/python/goad_py/convergence.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/python/goad_py/goad_py.pyi +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/python/goad_py/phips_convergence.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/release.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/goad-py/test_wheels.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/python/goad_py/__init__.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/python/goad_py/convergence.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/python/goad_py/goad_py.pyi +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/python/goad_py/phips_convergence.py +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/setup.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/_quickstart.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/beam.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/bins.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/clip.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/containment.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/diff.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/distortion.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/field.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/fresnel.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/geom.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/lib.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/main.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/multiproblem.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/orientation.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/output.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/params.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/powers.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/problem.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/result.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/settings/cli.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/settings/constants.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/settings/loading.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/settings/validation.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/src/snell.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/template/custom_bins.toml +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/template/goad_pbs.sh +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/tests/fixed_orientation_tests.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/tests/helpers.rs +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/tests/test_data/fixed_hex_30_20_20_mueller_scatgrid +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/tests/test_data/fixed_hex_30_30_30_mueller_scatgrid +0 -0
- {goad_py-0.5.5 → goad_py-0.6.0}/tests/test_data/hex.obj +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example script demonstrating MultiProblem Python API without config file dependencies.
|
|
3
|
+
|
|
4
|
+
This script shows how to:
|
|
5
|
+
1. Create binning schemes explicitly
|
|
6
|
+
2. Create orientation schemes explicitly
|
|
7
|
+
3. Use Settings with absolute geometry paths
|
|
8
|
+
4. Use MultiProblem for multi-orientation averaging with no external dependencies
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import goad_py as goad
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
import sys
|
|
15
|
+
import toml
|
|
16
|
+
|
|
17
|
+
PHIPS_BINS_FILE = "../../../phips_bins_edges.toml"
|
|
18
|
+
|
|
19
|
+
# Check that PHIPS bins file exists
|
|
20
|
+
phips_bins_path = Path(PHIPS_BINS_FILE)
|
|
21
|
+
if not phips_bins_path.exists():
|
|
22
|
+
print(f"\nError: PHIPS bins file not found at {phips_bins_path}")
|
|
23
|
+
print("Please run phips_detector_angles_edges.py first to generate the file.")
|
|
24
|
+
sys.exit(1)
|
|
25
|
+
|
|
26
|
+
with open(phips_bins_path, "r") as f:
|
|
27
|
+
bins_data = toml.load(f)
|
|
28
|
+
|
|
29
|
+
# Convert to format expected by BinningScheme.custom()
|
|
30
|
+
custom_bins = bins_data["bins"]
|
|
31
|
+
print(f"Loaded {len(custom_bins)} custom bins")
|
|
32
|
+
|
|
33
|
+
# Create binning scheme
|
|
34
|
+
binning = goad.BinningScheme.custom(custom_bins)
|
|
35
|
+
|
|
36
|
+
print("MultiProblem Example - Config-Free API")
|
|
37
|
+
print("=" * 50)
|
|
38
|
+
|
|
39
|
+
# Get absolute path to geometry file
|
|
40
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
41
|
+
geom_path = os.path.join(current_dir, "..", "..", "..", "examples", "data", "hex.obj")
|
|
42
|
+
geom_path = os.path.abspath(geom_path)
|
|
43
|
+
|
|
44
|
+
print(f"Using geometry file: {geom_path}")
|
|
45
|
+
|
|
46
|
+
# Example 1: Uniform orientation scheme with custom settings
|
|
47
|
+
print("\n1. Creating MultiProblem with uniform orientations...")
|
|
48
|
+
|
|
49
|
+
# # Create custom binning scheme
|
|
50
|
+
# binning = goad.BinningScheme.simple(181, 181) # 181x181 angular grid
|
|
51
|
+
# print("Created binning scheme: Simple 181x181")
|
|
52
|
+
|
|
53
|
+
# Create uniform orientation (100 random orientations)
|
|
54
|
+
uniform_orientation = goad.create_uniform_orientation(100)
|
|
55
|
+
print("Created uniform orientation: 100 random orientations")
|
|
56
|
+
|
|
57
|
+
# Create settings with all parameters explicit (no config file dependencies)
|
|
58
|
+
settings = goad.Settings(
|
|
59
|
+
geom_path=geom_path,
|
|
60
|
+
wavelength=0.532, # 532nm green laser
|
|
61
|
+
particle_refr_index_re=1.31, # glass refractive index
|
|
62
|
+
particle_refr_index_im=0.0, # no absorption
|
|
63
|
+
medium_refr_index_re=1.0, # air/vacuum
|
|
64
|
+
medium_refr_index_im=0.0,
|
|
65
|
+
orientation=uniform_orientation,
|
|
66
|
+
binning=binning,
|
|
67
|
+
beam_power_threshold=0.005,
|
|
68
|
+
cutoff=0.99,
|
|
69
|
+
max_rec=10,
|
|
70
|
+
max_tir=10,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Create and solve MultiProblem
|
|
74
|
+
print("Creating MultiProblem with uniform orientations...")
|
|
75
|
+
multi_problem = goad.MultiProblem(settings)
|
|
76
|
+
print(f"Number of orientations: {multi_problem.num_orientations}")
|
|
77
|
+
|
|
78
|
+
print("Solving MultiProblem (this averages over all orientations)...")
|
|
79
|
+
multi_problem.py_solve()
|
|
80
|
+
|
|
81
|
+
# Access averaged results
|
|
82
|
+
results = multi_problem.results
|
|
83
|
+
print(
|
|
84
|
+
f"Averaged Mueller matrix shape: {len(results.mueller)}x{len(results.mueller[0])}"
|
|
85
|
+
)
|
|
86
|
+
print(f"Averaged asymmetry parameter: {results.asymmetry}")
|
|
87
|
+
|
|
88
|
+
# Example 2: Discrete orientation scheme with custom binning
|
|
89
|
+
print("\n2. Creating MultiProblem with discrete orientations...")
|
|
90
|
+
|
|
91
|
+
# Create custom binning scheme with higher resolution in forward direction
|
|
92
|
+
interval_binning = goad.BinningScheme.interval(
|
|
93
|
+
thetas=[0.0, 30.0, 180.0], # Split at 30 degrees
|
|
94
|
+
theta_spacings=[1.0, 5.0], # Fine resolution near forward, coarse elsewhere
|
|
95
|
+
phis=[0.0, 360.0], # Full phi range
|
|
96
|
+
phi_spacings=[5.0], # 5 degree phi spacing
|
|
97
|
+
)
|
|
98
|
+
print("Created interval binning scheme")
|
|
99
|
+
|
|
100
|
+
# Create specific Euler angles
|
|
101
|
+
euler1 = goad.Euler(0.0, 0.0, 0.0) # No rotation
|
|
102
|
+
euler2 = goad.Euler(30.0, 30.0, 30.0) # 30 degree rotations
|
|
103
|
+
euler3 = goad.Euler(45.0, 60.0, 90.0) # Mixed rotations
|
|
104
|
+
|
|
105
|
+
# Create discrete orientation scheme
|
|
106
|
+
discrete_orientation = goad.create_discrete_orientation([euler1, euler2, euler3])
|
|
107
|
+
print("Created discrete orientation: 3 specific orientations")
|
|
108
|
+
|
|
109
|
+
# Create settings with discrete orientation and custom binning
|
|
110
|
+
settings2 = goad.Settings(
|
|
111
|
+
geom_path=geom_path,
|
|
112
|
+
wavelength=0.633, # 633nm red laser
|
|
113
|
+
particle_refr_index_re=1.5, # different material
|
|
114
|
+
particle_refr_index_im=0.01, # slight absorption
|
|
115
|
+
orientation=discrete_orientation,
|
|
116
|
+
binning=interval_binning,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Create and solve MultiProblem
|
|
120
|
+
print("Creating MultiProblem with discrete orientations...")
|
|
121
|
+
multi_problem2 = goad.MultiProblem(settings2)
|
|
122
|
+
print(f"Number of orientations: {multi_problem2.num_orientations}")
|
|
123
|
+
|
|
124
|
+
print("Solving MultiProblem with specific orientations...")
|
|
125
|
+
multi_problem2.py_solve()
|
|
126
|
+
|
|
127
|
+
# Access averaged results
|
|
128
|
+
results2 = multi_problem2.results
|
|
129
|
+
print(
|
|
130
|
+
f"Averaged Mueller matrix shape: {len(results2.mueller)}x{len(results2.mueller[0])}"
|
|
131
|
+
)
|
|
132
|
+
print(f"Averaged asymmetry parameter: {results2.asymmetry}")
|
|
133
|
+
|
|
134
|
+
# Example 3: Custom binning with specific angles
|
|
135
|
+
print("\n3. Creating MultiProblem with custom binning...")
|
|
136
|
+
|
|
137
|
+
# Create custom binning scheme with specific angle pairs
|
|
138
|
+
custom_bins = [
|
|
139
|
+
(0.0, 0.0), # Forward scattering
|
|
140
|
+
(10.0, 0.0), # Near-forward
|
|
141
|
+
(30.0, 0.0), # Small angle
|
|
142
|
+
(90.0, 0.0), # Side scattering
|
|
143
|
+
(150.0, 0.0), # Backscattering region
|
|
144
|
+
(180.0, 0.0), # Exact backscattering
|
|
145
|
+
]
|
|
146
|
+
custom_binning = goad.BinningScheme.custom(custom_bins)
|
|
147
|
+
print(f"Created custom binning with {len(custom_bins)} specific angles")
|
|
148
|
+
|
|
149
|
+
# Simple settings with default values
|
|
150
|
+
settings3 = goad.Settings(
|
|
151
|
+
geom_path=geom_path,
|
|
152
|
+
binning=custom_binning,
|
|
153
|
+
# All other parameters use defaults
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
multi_problem3 = goad.MultiProblem(settings3)
|
|
157
|
+
print(f"Number of orientations: {multi_problem3.num_orientations}")
|
|
158
|
+
|
|
159
|
+
print("Solving MultiProblem with custom binning...")
|
|
160
|
+
multi_problem3.py_solve()
|
|
161
|
+
|
|
162
|
+
results3 = multi_problem3.results
|
|
163
|
+
print(f"Custom binned results: {len(results3.mueller)} angle pairs")
|
|
@@ -6,10 +6,7 @@ Demonstrates converging on PHIPS detector bins (all except the first one).
|
|
|
6
6
|
PHIPS detectors measure scattering at 20 specific angles from 18° to 170°.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
import sys
|
|
10
9
|
from pathlib import Path
|
|
11
|
-
|
|
12
|
-
sys.path.insert(0, "../../python")
|
|
13
10
|
import goad_py as goad
|
|
14
11
|
|
|
15
12
|
print("=" * 80)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example 10: Advanced Parameters - Comprehensive Demonstration
|
|
4
|
+
|
|
5
|
+
Demonstrates ALL modifiable parameters in run_convergence():
|
|
6
|
+
- Optical parameters (wavelength, refractive indices)
|
|
7
|
+
- Convergence parameters (batch size, max orientations, min batches)
|
|
8
|
+
- Beam tracing parameters (thresholds, recursion limits, cutoff)
|
|
9
|
+
- Geometry transformations (problem scale, per-axis scaling, distortion)
|
|
10
|
+
- Advanced configuration (mapping, coherence, field of view)
|
|
11
|
+
- Reproducibility (random seed)
|
|
12
|
+
|
|
13
|
+
This example showcases the full flexibility of the unified convergence API.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import goad_py as goad
|
|
18
|
+
|
|
19
|
+
print("=" * 80)
|
|
20
|
+
print("Example 10: Advanced Parameters - ALL Modifiable Parameters")
|
|
21
|
+
print("=" * 80)
|
|
22
|
+
|
|
23
|
+
# Get paths relative to this script's location
|
|
24
|
+
script_dir = Path(__file__).parent
|
|
25
|
+
geom_file = script_dir / "../../../examples/data/hex.obj"
|
|
26
|
+
phips_bins_file = script_dir / "../../../phips_bins_edges.toml"
|
|
27
|
+
|
|
28
|
+
# Resolve to absolute paths
|
|
29
|
+
geom_file = str(geom_file.resolve())
|
|
30
|
+
phips_bins_file = str(phips_bins_file.resolve())
|
|
31
|
+
|
|
32
|
+
# Configuration summary
|
|
33
|
+
print("\n" + "=" * 80)
|
|
34
|
+
print("Configuration Summary:")
|
|
35
|
+
print("=" * 80)
|
|
36
|
+
print("OPTICAL PARAMETERS:")
|
|
37
|
+
print(" Wavelength: 0.633 μm (HeNe laser)")
|
|
38
|
+
print(" Particle refractive index: 1.5 + 0.01i (absorbing particle)")
|
|
39
|
+
print(" Medium refractive index: 1.33 + 0.0i (water)")
|
|
40
|
+
print()
|
|
41
|
+
print("CONVERGENCE PARAMETERS:")
|
|
42
|
+
print(" Batch size: 12 orientations per batch")
|
|
43
|
+
print(" Max orientations: 500")
|
|
44
|
+
print(" Min batches: 3")
|
|
45
|
+
print()
|
|
46
|
+
print("BEAM TRACING PARAMETERS:")
|
|
47
|
+
print(" Beam power threshold: 0.01 (stricter than default 0.05)")
|
|
48
|
+
print(" Beam area threshold factor: 2.0 (half of default 4.0)")
|
|
49
|
+
print(" Cutoff: 0.0005 (stricter than default 0.001)")
|
|
50
|
+
print(" Max recursion depth: 6 (limited for demonstration)")
|
|
51
|
+
print(" Max TIR bounces: 50 (half of default 100)")
|
|
52
|
+
print()
|
|
53
|
+
print("GEOMETRY TRANSFORMATIONS:")
|
|
54
|
+
print(" Problem scale: 2.0 (scales entire problem by 2x)")
|
|
55
|
+
print(" Per-axis geometry scale: [1.0, 1.0, 1.5] (stretch z-axis by 1.5x)")
|
|
56
|
+
print(" Distortion: 0.1 (adds 10% geometric distortion)")
|
|
57
|
+
print()
|
|
58
|
+
print("ADVANCED CONFIGURATION:")
|
|
59
|
+
print(" Mapping: GeometricOptics (instead of default ApertureDiffraction)")
|
|
60
|
+
print(" Coherence: True (enable coherent scattering calculations)")
|
|
61
|
+
print(" Field of view factor: 2.0 (doubled FOV)")
|
|
62
|
+
print()
|
|
63
|
+
print("REPRODUCIBILITY:")
|
|
64
|
+
print(" Random seed: 42 (for reproducible results)")
|
|
65
|
+
print()
|
|
66
|
+
print("CONVERGENCE TARGET:")
|
|
67
|
+
print(" Mode: PHIPS detector convergence")
|
|
68
|
+
print(" Detectors: Indices 1-19 (26° to 170°, skipping 18° forward scatter)")
|
|
69
|
+
print(" Tolerance: 50% relative SEM (relaxed for demo)")
|
|
70
|
+
print("=" * 80 + "\n")
|
|
71
|
+
|
|
72
|
+
# Converge on all PHIPS detectors except the first one (indices 1-19)
|
|
73
|
+
detector_indices = list(range(1, 20)) # [1, 2, 3, ..., 19]
|
|
74
|
+
|
|
75
|
+
print(f"Starting convergence on {len(detector_indices)} PHIPS detectors...\n")
|
|
76
|
+
|
|
77
|
+
# Run PHIPS convergence with ALL MODIFIABLE PARAMETERS
|
|
78
|
+
results = goad.run_convergence(
|
|
79
|
+
# Required parameters
|
|
80
|
+
geometry=geom_file,
|
|
81
|
+
targets=[
|
|
82
|
+
{
|
|
83
|
+
"tolerance": 0.25, # 50% relative SEM (relaxed for demo)
|
|
84
|
+
"tolerance_type": "relative",
|
|
85
|
+
"detector_indices": detector_indices,
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
mode=goad.PHIPSMode(bins_file=phips_bins_file),
|
|
89
|
+
# ========================================================================
|
|
90
|
+
# OPTICAL PARAMETERS
|
|
91
|
+
# ========================================================================
|
|
92
|
+
wavelength=0.633, # HeNe laser wavelength in microns
|
|
93
|
+
particle_refr_index_re=1.5, # Real part of particle refractive index
|
|
94
|
+
particle_refr_index_im=0.01, # Imaginary part (absorption)
|
|
95
|
+
medium_refr_index_re=1.33, # Real part of medium refractive index (water)
|
|
96
|
+
medium_refr_index_im=0.0, # Imaginary part (no absorption in medium)
|
|
97
|
+
# ========================================================================
|
|
98
|
+
# CONVERGENCE PARAMETERS
|
|
99
|
+
# ========================================================================
|
|
100
|
+
batch_size=12, # Orientations per batch (smaller batches for finer control)
|
|
101
|
+
max_orientations=500, # Maximum total orientations
|
|
102
|
+
min_batches=10, # Minimum batches before checking convergence
|
|
103
|
+
mueller_1d=False, # Mueller matrix output (N/A for PHIPS mode)
|
|
104
|
+
# ========================================================================
|
|
105
|
+
# BEAM TRACING PARAMETERS
|
|
106
|
+
# ========================================================================
|
|
107
|
+
beam_power_threshold=0.01, # Beam power threshold (stricter than default)
|
|
108
|
+
beam_area_threshold_fac=0.001, # Beam area threshold factor (tighter threshold)
|
|
109
|
+
cutoff=0.0005, # Ray power cutoff (more accurate but slower)
|
|
110
|
+
max_rec=6, # Maximum recursion depth (limited for demo)
|
|
111
|
+
max_tir=20, # Maximum total internal reflection bounces
|
|
112
|
+
# ========================================================================
|
|
113
|
+
# GEOMETRY TRANSFORMATIONS
|
|
114
|
+
# ========================================================================
|
|
115
|
+
scale=1.0, # Problem scaling factor (numerical changes only)
|
|
116
|
+
geom_scale=[3.0, 3.0, 6.0], # Per-axis geometry scaling
|
|
117
|
+
distortion=0.0, # Geometry distortion factor
|
|
118
|
+
# ========================================================================
|
|
119
|
+
# ADVANCED CONFIGURATION
|
|
120
|
+
# ========================================================================
|
|
121
|
+
mapping=goad.Mapping.ApertureDiffraction, # or GeometricOptics
|
|
122
|
+
coherence=True, # Enable coherent scattering calculations
|
|
123
|
+
fov_factor=2.0, # Field of view factor (doubled)
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Print summary
|
|
127
|
+
print(results.summary())
|
|
128
|
+
|
|
129
|
+
# Save results
|
|
130
|
+
results.save("10_advanced_parameters_results.json")
|
|
131
|
+
|
|
132
|
+
# Show detailed PHIPS output
|
|
133
|
+
print("\n" + "=" * 80)
|
|
134
|
+
print("PHIPS Detector DSCS Values (all 20 detectors)")
|
|
135
|
+
print("=" * 80)
|
|
136
|
+
|
|
137
|
+
import json
|
|
138
|
+
|
|
139
|
+
with open("10_advanced_parameters_results.json", "r") as f:
|
|
140
|
+
data = json.load(f)
|
|
141
|
+
|
|
142
|
+
phips_dscs = data.get("phips_dscs")
|
|
143
|
+
detector_angles = data.get("detector_angles")
|
|
144
|
+
|
|
145
|
+
if phips_dscs and detector_angles:
|
|
146
|
+
print(
|
|
147
|
+
f"\n{'Detector':<10} {'Angle':<10} {'DSCS Mean':<15} {'DSCS SEM':<15} {'Rel. SEM':<10}"
|
|
148
|
+
)
|
|
149
|
+
print("-" * 70)
|
|
150
|
+
|
|
151
|
+
for i, (dscs_data, angle) in enumerate(zip(phips_dscs, detector_angles)):
|
|
152
|
+
mean, sem = dscs_data[0], dscs_data[1]
|
|
153
|
+
rel_sem = (sem / abs(mean) * 100) if mean != 0 else float("inf")
|
|
154
|
+
|
|
155
|
+
# Mark which detectors were converged on
|
|
156
|
+
marker = "✓" if i in detector_indices else "○"
|
|
157
|
+
|
|
158
|
+
print(
|
|
159
|
+
f"{marker} {i:<8} {angle:<10.1f} {mean:<15.4e} {sem:<15.4e} {rel_sem:<10.2f}%"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
print("\n" + "=" * 80)
|
|
163
|
+
print("Legend:")
|
|
164
|
+
print(" ✓ = Converged on this detector")
|
|
165
|
+
print(" ○ = Not a convergence target (but still computed)")
|
|
166
|
+
print("=" * 80)
|
|
167
|
+
|
|
168
|
+
# Show configuration that was used
|
|
169
|
+
print("\n" + "=" * 80)
|
|
170
|
+
print("Configuration Used (from saved results):")
|
|
171
|
+
print("=" * 80)
|
|
172
|
+
|
|
173
|
+
config = data.get("config", {})
|
|
174
|
+
if config:
|
|
175
|
+
print(f"\nOptical parameters:")
|
|
176
|
+
print(f" Wavelength: {config.get('wavelength')} μm")
|
|
177
|
+
print(
|
|
178
|
+
f" Particle refractive index: {config.get('particle_refr_index_re')} + {config.get('particle_refr_index_im')}i"
|
|
179
|
+
)
|
|
180
|
+
print(
|
|
181
|
+
f" Medium refractive index: {config.get('medium_refr_index_re')} + {config.get('medium_refr_index_im')}i"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
beam_tracing = config.get("beam_tracing", {})
|
|
185
|
+
if beam_tracing:
|
|
186
|
+
print(f"\nBeam tracing parameters:")
|
|
187
|
+
print(f" Max recursion depth: {beam_tracing.get('max_rec')}")
|
|
188
|
+
print(f" Max TIR bounces: {beam_tracing.get('max_tir')}")
|
|
189
|
+
print(f" Cutoff: {beam_tracing.get('cutoff')}")
|
|
190
|
+
print(f" Beam power threshold: {beam_tracing.get('beam_power_threshold')}")
|
|
191
|
+
print(
|
|
192
|
+
f" Beam area threshold factor: {beam_tracing.get('beam_area_threshold_fac')}"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
geom_transform = config.get("geometry_transform", {})
|
|
196
|
+
if geom_transform:
|
|
197
|
+
print(f"\nGeometry transformations:")
|
|
198
|
+
print(f" Problem scale: {geom_transform.get('scale')}")
|
|
199
|
+
if geom_transform.get("distortion"):
|
|
200
|
+
print(f" Distortion: {geom_transform.get('distortion')}")
|
|
201
|
+
if geom_transform.get("geom_scale"):
|
|
202
|
+
print(f" Per-axis geometry scale: {geom_transform.get('geom_scale')}")
|
|
203
|
+
|
|
204
|
+
advanced = config.get("advanced_config", {})
|
|
205
|
+
if advanced:
|
|
206
|
+
print(f"\nAdvanced configuration:")
|
|
207
|
+
print(f" Mapping: {advanced.get('mapping')}")
|
|
208
|
+
print(f" Coherence: {advanced.get('coherence')}")
|
|
209
|
+
if advanced.get("fov_factor"):
|
|
210
|
+
print(f" Field of view factor: {advanced.get('fov_factor')}")
|
|
211
|
+
|
|
212
|
+
if config.get("seed"):
|
|
213
|
+
print(f"\nReproducibility:")
|
|
214
|
+
print(f" Random seed: {config.get('seed')}")
|
|
215
|
+
|
|
216
|
+
print("\n✓ Example completed successfully!")
|