pyshs-optics 4.0.2__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 (41) hide show
  1. pyshs_optics-4.0.2/LICENSE +21 -0
  2. pyshs_optics-4.0.2/PKG-INFO +457 -0
  3. pyshs_optics-4.0.2/README.md +433 -0
  4. pyshs_optics-4.0.2/pyproject.toml +44 -0
  5. pyshs_optics-4.0.2/setup.cfg +4 -0
  6. pyshs_optics-4.0.2/src/py_shs/HRS.py +521 -0
  7. pyshs_optics-4.0.2/src/py_shs/SHS.py +666 -0
  8. pyshs_optics-4.0.2/src/py_shs/__init__.py +7 -0
  9. pyshs_optics-4.0.2/src/py_shs/__main__.py +5 -0
  10. pyshs_optics-4.0.2/src/py_shs/cli.py +50 -0
  11. pyshs_optics-4.0.2/src/py_shs/cube_SHS.py +658 -0
  12. pyshs_optics-4.0.2/src/py_shs/cylinder_SHS.py +571 -0
  13. pyshs_optics-4.0.2/src/py_shs/ellipsoid_SHS.py +612 -0
  14. pyshs_optics-4.0.2/src/py_shs/graph_angle.py +60 -0
  15. pyshs_optics-4.0.2/src/py_shs/graph_assembly.py +74 -0
  16. pyshs_optics-4.0.2/src/py_shs/pyshs_gui.py +1911 -0
  17. pyshs_optics-4.0.2/src/py_shs/script_cylinder_random.py +60 -0
  18. pyshs_optics-4.0.2/src/py_shs/script_gauss2PySHS.py +108 -0
  19. pyshs_optics-4.0.2/src/py_shs/script_sphere.py +61 -0
  20. pyshs_optics-4.0.2/src/py_shs/script_sphere_random.py +67 -0
  21. pyshs_optics-4.0.2/src/py_shs/script_spheroid_random.py +80 -0
  22. pyshs_optics-4.0.2/src/py_shs/shs_angles.py +41 -0
  23. pyshs_optics-4.0.2/src/py_shs/shs_grid.py +167 -0
  24. pyshs_optics-4.0.2/src/py_shs/shs_io.py +20 -0
  25. pyshs_optics-4.0.2/src/py_shs/shs_mie.py +714 -0
  26. pyshs_optics-4.0.2/src/py_shs/shs_units.py +76 -0
  27. pyshs_optics-4.0.2/src/py_shs/sphere_SHS.py +579 -0
  28. pyshs_optics-4.0.2/src/pyshs_optics.egg-info/PKG-INFO +457 -0
  29. pyshs_optics-4.0.2/src/pyshs_optics.egg-info/SOURCES.txt +39 -0
  30. pyshs_optics-4.0.2/src/pyshs_optics.egg-info/dependency_links.txt +1 -0
  31. pyshs_optics-4.0.2/src/pyshs_optics.egg-info/entry_points.txt +9 -0
  32. pyshs_optics-4.0.2/src/pyshs_optics.egg-info/requires.txt +3 -0
  33. pyshs_optics-4.0.2/src/pyshs_optics.egg-info/top_level.txt +1 -0
  34. pyshs_optics-4.0.2/tests/test_core.py +210 -0
  35. pyshs_optics-4.0.2/tests/test_golden.py +32 -0
  36. pyshs_optics-4.0.2/tests/test_grids.py +120 -0
  37. pyshs_optics-4.0.2/tests/test_housekeeping.py +206 -0
  38. pyshs_optics-4.0.2/tests/test_models.py +150 -0
  39. pyshs_optics-4.0.2/tests/test_smoke.py +19 -0
  40. pyshs_optics-4.0.2/tests/test_tools.py +28 -0
  41. pyshs_optics-4.0.2/tests/test_units_angles.py +123 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2026 Pierre-Marie Gassin, Gaelle Gassin
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,457 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyshs-optics
3
+ Version: 4.0.2
4
+ Summary: Second Harmonic Scattering (SHS) and Hyper-Rayleigh Scattering (HRS) calculations - pure Python / NumPy
5
+ Author-email: Pierre-Marie Gassin <pierre-marie.gassin@enscm.fr>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/pmgassin/Py_SHS
8
+ Project-URL: Repository, https://github.com/pmgassin/Py_SHS
9
+ Project-URL: Issues, https://github.com/pmgassin/Py_SHS/issues
10
+ Keywords: second harmonic scattering,SHS,HRS,hyper-Rayleigh,nonlinear optics,hyperpolarizability
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
14
+ Classifier: Topic :: Scientific/Engineering :: Physics
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Operating System :: OS Independent
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy
21
+ Requires-Dist: scipy
22
+ Requires-Dist: matplotlib
23
+ Dynamic: license-file
24
+
25
+ # Py_SHS – A Python Second Harmonic Scattering package.
26
+
27
+ [![PyPI version](https://img.shields.io/pypi/v/pyshs-optics.svg)](https://pypi.org/project/pyshs-optics/)
28
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyshs-optics.svg)](https://pypi.org/project/pyshs-optics/)
29
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/pmgassin/Py_SHS/blob/Py_SHS_V4/LICENSE)
30
+ [![User guide](https://img.shields.io/badge/docs-User%20Manual%20(PDF)-orange.svg)](https://github.com/pmgassin/Py_SHS/blob/Py_SHS_V4/Documentation/PySHS_User_Manual.pdf)
31
+
32
+ **Py_SHS** is a collection of programs that compute the **second-harmonic intensity** scattered by
33
+ a molecule, or by a colloidal / supramolecular structure (sphere, cylinder, ellipsoid, box,
34
+ assembly of oriented dipoles). It covers incoherent Hyper-Rayleigh Scattering (HRS) as well as
35
+ coherent Second Harmonic Scattering (SHS), and comes with a graphical interface.
36
+
37
+ Written in Python on top of NumPy: **no C compiler is needed**, and it installs with a single
38
+ `pip` command.
39
+
40
+ > 📖 **User guide:** [PySHS_User_Manual.pdf](https://github.com/pmgassin/Py_SHS/blob/Py_SHS_V4/Documentation/PySHS_User_Manual.pdf)
41
+ > 🐛 **Issues and questions:** [github.com/pmgassin/Py_SHS/issues](https://github.com/pmgassin/Py_SHS/issues)
42
+
43
+ ---
44
+
45
+ ## ✨ What it computes
46
+
47
+ | Module | Description |
48
+ |--------|-------------|
49
+ | **HRS** | Incoherent Hyper-Rayleigh Scattering (single molecule) |
50
+ | **SHS** | Coherent SHS of an assembly of N oriented dipoles |
51
+ | **Sphere** | Colloidal sphere (NLRGD / NLWKB continuum models) |
52
+ | **Sphere Mie** | Nonlinear Mie theory for spheres |
53
+ | **Cylinder** | Continuum model for colloidal cylinders |
54
+ | **Ellipsoid** | Spheroid / ellipsoid of revolution |
55
+ | **Cube / Box** | Rectangular box (or cube) |
56
+
57
+ Keywords shared by most modules:
58
+
59
+ - `polarplot_single` – polar plot at one scattering angle
60
+ - `polarplot_integrate` – average over a range of angles
61
+ - `angle_scattering` – angular distribution: you enter N, and the code computes N+1 angles from 0° to 180° (step 180°/N), identically in all modules
62
+
63
+ ---
64
+
65
+ ## 📦 Installation
66
+
67
+ ### 1. Requirements
68
+
69
+ - **Python 3.8 or newer** ([python.org/downloads](https://www.python.org/downloads/))
70
+ - **tkinter**, only for the graphical interface. It is included in the official Python installers for
71
+ Windows and macOS, but is a separate system package on some systems (see the note below).
72
+
73
+ NumPy, SciPy and matplotlib are installed automatically by `pip`.
74
+
75
+ ### 2. Install with pip
76
+
77
+ ```bash
78
+ pip install pyshs-optics
79
+ ```
80
+
81
+ That's it. Check that the installation worked:
82
+
83
+ ```bash
84
+ python -c "import py_shs; print(py_shs.__version__)"
85
+ ```
86
+
87
+ > 💡 **Recommended:** install inside a virtual environment, so that Py_SHS and its dependencies stay
88
+ > separate from the rest of your Python installation.
89
+ >
90
+ > ```bash
91
+ > python3 -m venv pyshs-env
92
+ > source pyshs-env/bin/activate # Windows: pyshs-env\Scripts\activate
93
+ > pip install pyshs-optics
94
+ > ```
95
+
96
+ ### 3. Update or uninstall
97
+
98
+ ```bash
99
+ pip install --upgrade pyshs-optics
100
+ pip uninstall pyshs-optics
101
+ ```
102
+
103
+ ### tkinter not found?
104
+
105
+ If launching the GUI fails with `No module named 'tkinter'`, install it for your system:
106
+
107
+ | System | Command |
108
+ |--------|---------|
109
+ | Debian / Ubuntu | `sudo apt install python3-tk` |
110
+ | Fedora | `sudo dnf install python3-tkinter` |
111
+ | macOS (Homebrew Python) | `brew install python-tk` |
112
+ | Windows | re-run the Python installer and tick *tcl/tk and IDLE* |
113
+
114
+ The command-line programs do not need tkinter.
115
+
116
+ ---
117
+
118
+ ## 🚀 Launching the GUI
119
+
120
+ Once the package is installed, open a terminal and type:
121
+
122
+ ```bash
123
+ pyshs-optics-gui
124
+ ```
125
+
126
+ or, equivalently:
127
+
128
+ ```bash
129
+ python -m py_shs
130
+ ```
131
+
132
+ The graphical interface opens. Choose a module, enter your parameters and input files, and run the
133
+ calculation: progress is streamed live in the log panel and results are plotted in the window.
134
+ An *Intensity units* selector and a scale factor apply to every module.
135
+
136
+ **Where are my files?** The GUI writes its input / output files and temporary calculation folders in
137
+
138
+ ```text
139
+ ~/PySHS_Work/
140
+ ```
141
+
142
+ (that is `C:\Users\<you>\PySHS_Work` on Windows). You can choose another folder with the environment
143
+ variable `PYSHS_WORK`:
144
+
145
+ ```bash
146
+ export PYSHS_WORK=/path/to/my/calculations # macOS / Linux
147
+ pyshs-optics-gui
148
+ ```
149
+
150
+ If the `pyshs-optics-gui` command is not found, use `python -m py_shs` instead, which always works.
151
+
152
+ 📖 The full description of the interface and of the physical models is in the
153
+ **[User Manual (PDF)](https://github.com/pmgassin/Py_SHS/blob/Py_SHS_V4/Documentation/PySHS_User_Manual.pdf)**.
154
+
155
+ ---
156
+
157
+ ## 💻 Command-line use (without the GUI)
158
+
159
+ Each module can also be run from a terminal. The protocol is: a keyword, the beta (or ki2) file, an
160
+ optional orientation file and the output file; the numerical parameters are read from standard input.
161
+
162
+ | Command | Module |
163
+ |---------|--------|
164
+ | `pyshs-optics-hrs` | HRS |
165
+ | `pyshs-optics-shs` | SHS (dipole assembly) |
166
+ | `pyshs-optics-sphere` | Sphere (NLRGD / NLWKB) |
167
+ | `pyshs-optics-mie` | Nonlinear Mie theory |
168
+ | `pyshs-optics-cylinder` | Cylinder |
169
+ | `pyshs-optics-ellipsoid` | Ellipsoid |
170
+ | `pyshs-optics-cube` | Cube / box |
171
+
172
+ Examples (macOS / Linux shell; on Windows use Git Bash or WSL), with a beta file `beta.txt`
173
+ in the current folder:
174
+
175
+ ```bash
176
+ # HRS polar plot at 90°
177
+ printf "800\n1.33\n0.0\n90\n" | pyshs-optics-hrs polarplot_single beta.txt out_hrs.txt
178
+
179
+ # SHS (N dipoles + orientation file)
180
+ printf "100\n800\n1.33\n0.0\n90\n" | pyshs-optics-shs polarplot_single beta.txt orient.txt out_shs.txt
181
+
182
+ # Sphere NLWKB
183
+ printf "1\n800\n1.5\n0.0\n1.33\n0.0\n50\n90\n" | pyshs-optics-sphere polarplot_single beta.txt out_sph.txt
184
+
185
+ # Cylinder
186
+ printf "800\n1.5\n0.0\n1.33\n0.0\n20\n80\n90\n" | pyshs-optics-cylinder polarplot_single beta.txt out_cyl.txt
187
+ ```
188
+
189
+ Every module can also be started with `python -m py_shs.<module>` (for example `python -m py_shs.HRS`).
190
+
191
+ ---
192
+
193
+ ## 📄 Input file formats
194
+
195
+ **Beta / ki(2) file** – one header line, then 27 lines `name value` (order `xxx` … `zzz`):
196
+
197
+ ```text
198
+ # surface hyperpolarizability
199
+ xxx 0.0
200
+ xxy 0.0
201
+ ...
202
+ zzz 1.0
203
+ ```
204
+
205
+ **Orientation file** (SHS only) – one line per dipole:
206
+
207
+ ```text
208
+ phi theta psi x y z
209
+ ```
210
+
211
+ (angles in radians, positions in nm).
212
+
213
+ ---
214
+
215
+ ## ⚙️ Environment variables
216
+
217
+ | Variable | Effect |
218
+ |----------|--------|
219
+ | `PYSHS_WORK=dir` | Working folder of the GUI (default: `~/PySHS_Work`) |
220
+ | `PYSHS_THREADS=k` | Thread count for HRS / SHS (default: CPU cores) |
221
+ | `PYSHS_LEGACY=1` | Reproduce two old C quirks of HRS / SHS (affects only bv1, bv2, bh1, bh2, which are zero after the isotropic average) |
222
+ | `PYSHS_I_SCALE=x` | Intensity scale factor, applied by **every** module (HRS, SHS, sphere, cylinder, ellipsoid, cube, Mie) |
223
+ | `PYSHS_UNITS=rad\|raw` | Intensity units common to all modules (see *Intensity units* below) |
224
+ | `PYSHS_ANGLE_RANGE=half\|negative\|full` | Angle range of `angle_scattering` (see *Scattering-angle grid* below) |
225
+ | `PYSHS_GRID=fixed` | Use the historical fixed quadrature grids (see *Automatic quadrature grids*) |
226
+ | `PYSHS_GRID_SCALE=x` | Multiplies the size parameter used by the grid rules (2 = safer and slower, 0.5 = faster) |
227
+ | `PYSHS_GRID_MAX=n` | Upper bound on the grid size (memory / time guard) |
228
+ | `PYSHS_THETA_RULE=midpoint` | Former mid-point rule in theta |
229
+
230
+ ---
231
+
232
+ ## 🔬 Technical notes
233
+
234
+ The notes below describe the numerical conventions of this version. Click a title to expand it.
235
+
236
+ <details>
237
+ <summary><b>Package layout</b></summary>
238
+
239
+ ```text
240
+ py_shs/ (installed in site-packages)
241
+ ├── pyshs_gui.py # Tkinter GUI -> command `pyshs-optics-gui`
242
+ ├── HRS.py, SHS.py
243
+ ├── sphere_SHS.py, cylinder_SHS.py, ellipsoid_SHS.py, cube_SHS.py
244
+ ├── shs_mie.py # nonlinear Mie theory
245
+ ├── graph_*.py, script_*.py # plots and dipole generators (sphere, spheroid, cylinder)
246
+ ├── shs_grid.py, shs_units.py, shs_angles.py, shs_io.py # shared helpers
247
+ └── cli.py # console commands pyshs-optics-hrs, pyshs-optics-shs, ...
248
+ ```
249
+
250
+ All calculation modules are pure Python and are invoked with the same interpreter
251
+ (`python -m py_shs.<module>`).
252
+
253
+ </details>
254
+
255
+ <details>
256
+ <summary><b>What changed in V4 (pure Python)</b></summary>
257
+
258
+ - All former `.c` sources (`HRS.c`, `SHS.c`, `sphere_SHS.c`, `cylinder_SHS.c`, `ellipsoid_SHS.c`,
259
+ `cube_SHS.c`) are replaced by equivalent NumPy implementations with the **same physics and the same
260
+ stdin / file protocol**.
261
+ - The GUI no longer compiles anything; it launches `python -u -m py_shs.<module> …`.
262
+ - Dependencies: Python 3 + NumPy (+ SciPy for `shs_mie.py`; tkinter / matplotlib for the GUI).
263
+
264
+ Equivalence with the previous C programs: the C sources/binaries are **not** part of this package, so
265
+ this package does not itself demonstrate it. What *is* verified (see the `tests/` folder of the GitHub
266
+ repository): analytic values, an independent brute-force evaluation of the polarisation formulas, mutual
267
+ consistency of all the models (absolute scale included) and a frozen snapshot of the current outputs. To
268
+ check against the C programs, run both on the same input and compare the output files.
269
+
270
+ `PYSHS_LEGACY=1` (HRS and SHS only) reproduces two defects of the old C code (normalisation of bv1, bv2,
271
+ bh1, bh2, and the pairing of the sin*cos cross terms of bh1, bh2). These four coefficients are identically
272
+ zero after the isotropic orientational average (shown analytically and tested numerically), so the option
273
+ changes only rounding noise in them and none of av, bv, cv, ah, bh, ch, I2 and I4.
274
+
275
+ </details>
276
+
277
+ <details>
278
+ <summary><b>Hyperpolarizability tensor (symmetrisation)</b></summary>
279
+
280
+ All modules assume beta_ijk = beta_ikj (intrinsic permutation symmetry in the last two indices). The
281
+ beta/surface-susceptibility file reader of HRS, SHS, sphere_SHS, cylinder_SHS, ellipsoid_SHS and cube_SHS
282
+ symmetrises the input (beta_ijk <- (beta_ijk + beta_ikj)/2) and prints a WARNING if the file was not
283
+ symmetric. `shs_mie.py` already averages the equivalent components (xzx/xxz, yzy/yyz).
284
+
285
+ </details>
286
+
287
+ <details>
288
+ <summary><b>Orientation quadrature (normalisation)</b></summary>
289
+
290
+ The orientation average over the polar angle theta uses a Gauss-Legendre rule in cos(theta) in HRS, SHS,
291
+ cylinder_SHS and ellipsoid_SHS (cube_SHS already did). The weights then sum exactly to 8*pi^2 (SHS/HRS) so
292
+ the 1/(8*pi^2) normalisation is exact, and all modules normalise consistently. The former midpoint rule had
293
+ a weight sum of 1.0041 * 8*pi^2, i.e. a +0.4 % bias on rotation-invariant quantities. Set
294
+ `PYSHS_THETA_RULE=midpoint` to restore the previous grid (e.g. to reproduce earlier results). Grid sizes
295
+ (N_PHI, N_THETA, ...) are unchanged.
296
+
297
+ </details>
298
+
299
+ <details>
300
+ <summary><b>Automatic quadrature grids (convergence)</b></summary>
301
+
302
+ All intensities contain the phase factor exp(i q.r) with |q| <= q_max = 2 Re(k_w) + Re(K_2w). A grid that is
303
+ fine for a small object silently becomes under-resolved for a large one, so the grids are sized from the
304
+ size parameter `a = q_max x (largest half-extent)` by `py_shs/shs_grid.py` (rules calibrated numerically
305
+ against very fine reference grids; typical error <= 1e-4, usually ~1e-7):
306
+
307
+ | Module | What is sized | Rule |
308
+ |---|---|---|
309
+ | `sphere_SHS` | surface grid (Gauss-Legendre in cos theta_c x trapezoid in phi_c) | ny >= a/2 + 20, nx = 2 ny |
310
+ | `cylinder_SHS` | azimuth points, orientation grid; axial integral is analytic (sinc) | n_beta >= qR + 14 ; N >= q sqrt(R^2+L^2/4) + 12 |
311
+ | `ellipsoid_SHS` | surface (alpha, beta) and orientation grids | n_alpha >= a/2+20, n_beta >= a+16, N >= a+12 |
312
+ | `cube_SHS` | orientation grid (faces are analytic) | N >= q d + 12, d = half diagonal |
313
+ | `SHS` | orientation grid (phi, theta, psi) | N_phi = N_psi >= 2 a + 8, N_theta = N/2, a = q max&#124;r&#124; |
314
+ | `HRS`, `shs_mie` | nothing to size (HRS: single molecule; Mie: Wiscombe cutoff already adaptive) | |
315
+
316
+ The grid used is printed in the run log (`Grid: ...` / `Orientation grid: ...`). The historical values (the
317
+ module constants) are used as minimum sizes: the grids are never coarser than before (for sphere, dipole
318
+ assemblies and box, small objects use exactly the historical sizes).
319
+
320
+ * `PYSHS_GRID=fixed` : use the historical fixed grids (reproduces earlier runs; may be inaccurate for large objects).
321
+ * `PYSHS_GRID_SCALE=<float>` : multiplies the size parameter used by the rules (2 = safer and slower, 0.5 = faster).
322
+ * `PYSHS_GRID_MAX=<int>` : upper bound on the grid size (memory / time guard). When the bound prevents the rule from being satisfied, a `WARNING` is printed.
323
+ * `PYSHS_THETA_RULE=midpoint` : former mid-point rule in theta.
324
+
325
+ Other changes: `cylinder_SHS` integrates the axial direction analytically (the former `N_Z` no longer
326
+ exists, so no aliasing for long rods); `ellipsoid_SHS`, `cube_SHS` and `cylinder_SHS` are vectorised
327
+ (5-10x faster).
328
+
329
+ </details>
330
+
331
+ <details>
332
+ <summary><b>Intensity units (comparing modules)</b></summary>
333
+
334
+ Two conventions exist, related by the radiative prefactor `P = (|K_2w|^2 / 4 pi)^2`
335
+ (`K = 4 pi n / lambda`, in nm^-1):
336
+
337
+ | Convention | Meaning | Default for |
338
+ |---|---|---|
339
+ | `rad` | `I = r^2 \|E_2w\|^2 / \|E_w\|^4`, prefactor `P` **included** | sphere, cylinder, ellipsoid, cube, `shs_mie` |
340
+ | `raw` | orientation average of `\|sum beta exp(i q.r)\|^2`, **no** prefactor (beta in atomic units; e.g. `<beta_ZZZ^2> = 1/7` for `beta_zzz = 1`) | HRS, SHS |
341
+
342
+ `I_rad = P * I_raw`. `PYSHS_UNITS=rad` or `raw` forces one convention on every module, and `PYSHS_I_SCALE`
343
+ multiplies every module's result, so any two modules can be put on the same scale. The convention used is
344
+ printed in the run log and in the header of the output file. Default outputs are unchanged. (HRS/SHS switch
345
+ to scientific notation when the multiplier is not 1, since `rad` values are ~1e-9.) The GUI has an
346
+ *Intensity units* selector and a scale factor that apply to all modules.
347
+
348
+ Absolute consistency (checked numerically): a continuum model with surface susceptibility `chi` is
349
+ equivalent to a dipole assembly of surface density `sigma` [dipoles/nm^2] and molecular `beta` with
350
+ `chi = sigma * beta` (so chi is in units of beta per nm^2). With both on the same scale,
351
+ `I_SHS(assembly) = sigma^2 * I_continuum` (agreement to 1e-5 for a sphere, cylinder and cube), and the
352
+ nonlinear Mie theory equals the sphere NLRGD model at matched index.
353
+
354
+ </details>
355
+
356
+ <details>
357
+ <summary><b>Scattering-angle grid (<code>angle_scattering</code>)</b></summary>
358
+
359
+ All modules use the same grid: the number N you enter is the number of intervals between 0 and 180
360
+ degrees, so N+1 angles `Theta = 0, 180/N, ..., 180`. Previously HRS, SHS and the cylinder covered
361
+ [-180, 0] with N+1 points, while the sphere, ellipsoid, cube and Mie covered [-180, +180] with 2N+1 points,
362
+ so the same N did not mean the same thing (and half of the sphere/ellipsoid/cube/Mie work was redundant).
363
+
364
+ A half range is sufficient because the four reported intensities satisfy `I(Theta) = I(-Theta)`; this was
365
+ checked numerically in every module with a random chiral tensor.
366
+
367
+ `PYSHS_ANGLE_RANGE` restores the former ranges: `negative` (-180...0, N+1 points; former HRS/SHS/cylinder
368
+ output) or `full` (-180...+180, 2N+1 points; former sphere/ellipsoid/cube/Mie output). The values at a given
369
+ angle are identical in all modes. `graph_angle.py` accepts any of the three ranges and plots the full
370
+ -180...+180 curve.
371
+
372
+ </details>
373
+
374
+ <details>
375
+ <summary><b>Models: notes and limitations</b></summary>
376
+
377
+ **Output files.** `out_plot` and `out_arrows_gnuplot` are written in the directory of the output file given
378
+ on the command line. Running twice in the same directory overwrites them.
379
+
380
+ **Models.**
381
+
382
+ - `cylinder_SHS` models the lateral surface only (no end caps): use it for objects long compared with their
383
+ radius. The surface frame uses the exact polar angle pi/2 (the old C code used the truncated 1.570796;
384
+ `PYSHS_THETA_MESO_LEGACY=1` restores it, effect ~1e-7).
385
+ - The classic Rayleigh-Gans sphere model is the NLWKB model with `n_p = n_m`: in the GUI enter the same
386
+ index twice.
387
+ - `shs_mie.py` has three independent surface constants (isotropic achiral surface: `zzz`, `zxx`/`zyy`,
388
+ `xzx`/`xxz`/`yzy`/`yyz`); other tensor components are ignored and a warning lists them. The
389
+ command-line/GUI interface uses the same index at omega and 2 omega and drops the imaginary part of the
390
+ medium index (`shs_sphere()` accepts distinct indices).
391
+ - With an absorbing medium (complex index) the phase factor is `exp(i q.r)` with complex `q`, so the result
392
+ depends on the origin of the positions (the attenuation is `exp(-Im q . r)`): put the origin where the
393
+ incident beam enters the object.
394
+ - `polarplot_integrate` is a plain average over the scattering angles, not weighted by `sin(Theta)`.
395
+ - The sphere and Mie outputs do not contain `b1`, `b2` (they are zero anyway, see the legacy note).
396
+
397
+ **Generators and converters (`py_shs/`).**
398
+
399
+ - `script_sphere.py`, `script_sphere_random.py`, `script_spheroid_random.py`, `script_cylinder_random.py`:
400
+ write `phi theta psi x y z` files for `SHS.py` (dipoles along the outward normal; disorder = Gaussian
401
+ noise on `phi`, `theta`; a noise on `phi` is a real tilt of `sigma*sin(theta)`).
402
+ `script_spheroid_random.py` (a, c, N, sigma) places the points with a uniform *surface* density and
403
+ reproduces `ellipsoid_SHS.py` through `chi = sigma * beta`.
404
+ - `script_gauss2PySHS.py job.log beta_out [--marker TEXT] [--occurrence K] [--offset N]` reads the first
405
+ `Beta(-2w;w,w)` block (see its docstring; the layout was not checked against every Gaussian version) and
406
+ writes a tensor symmetric in the last two indices.
407
+ - `graph_assembly.py orientation_file image.png [--positions-first]` expects `phi theta psi x y z`.
408
+
409
+ **GUI.** The *Intensity units* selector and the scale factor apply to every module; run directories
410
+ `~/PySHS_Work/pyshs_*` older than 7 days are removed automatically; the unit of polar plots (radians) is
411
+ decided once per file.
412
+
413
+ </details>
414
+
415
+ <details>
416
+ <summary><b>Tests (GitHub repository)</b></summary>
417
+
418
+ A regression and validation suite (standard library only, no pytest needed) is kept in the `tests/` folder
419
+ of the [GitHub repository](https://github.com/pmgassin/Py_SHS):
420
+
421
+ ```bash
422
+ python tests/run_tests.py # everything, about 2 minutes
423
+ python tests/run_tests.py -f # fast subset (skips the slow convergence tests)
424
+ ```
425
+
426
+ | File | What it checks |
427
+ |---|---|
428
+ | `test_core.py` | Euler matrices, exact orientation quadrature, analytic HRS values, HRS = SHS(N=1), the polarisation expansion against a brute-force evaluation, legacy mode, Theta -> -Theta symmetry |
429
+ | `test_models.py` | absolute scale of sphere, ellipsoid, cylinder, cube and Mie against dipole assemblies (chi = sigma beta), symmetrisation of beta in every module |
430
+ | `test_grids.py` | automatic grids against much finer references for large objects |
431
+ | `test_units_angles.py` | `PYSHS_UNITS`, `PYSHS_I_SCALE`, the angle grid and its compatibility ranges, `graph_angle.py` |
432
+ | `test_golden.py` | frozen snapshot of command-line outputs of every module (it detects unintended changes; it is not a C reference) |
433
+ | `test_tools.py` | `compare_outputs.py` |
434
+
435
+ The Mie tests are skipped when SciPy is not installed.
436
+
437
+ </details>
438
+
439
+ ---
440
+
441
+ ## 📚 How to cite
442
+
443
+ If you use Py_SHS in your work, please cite:
444
+
445
+ - J. Chem. Inf. Model. **2020**, 60, 12, 5912–5917
446
+ - J. Chem. Inf. Model. **2021**, 61, 11, 5719
447
+
448
+ ## 👥 Authors and license
449
+
450
+ Dr Pierre-Marie GASSIN and Dr Gaelle GASSIN – ICGM / ENSCM.
451
+
452
+ Open-source research software, released under the MIT License (see the
453
+ [LICENSE](https://github.com/pmgassin/Py_SHS/blob/Py_SHS_V4/LICENSE) file).
454
+
455
+ ## 📘 Documentation note
456
+
457
+ The PDF [User Manual] is available here: (https://github.com/pmgassin/Py_SHS/blob/Py_SHS_V4/Documentation/PySHS_User_Manual.pdf)