-
Notifications
You must be signed in to change notification settings - Fork 0
Add elastic.py with Boussinesq point load solution for photoelastic simulations #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Co-authored-by: benjym <3380296+benjym@users.noreply.github.com>
Co-authored-by: benjym <3380296+benjym@users.noreply.github.com>
Co-authored-by: benjym <3380296+benjym@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a new elastic.py module implementing the Boussinesq point load solution for elastic half-space photoelastic simulations, parallel to the existing Brazil test in disk.py. The implementation includes analytical stress field computation, synthetic image generation via Mueller matrix formalism, and comprehensive visualization tools.
Changes:
- New analytical elastic solution module with Boussinesq stress computation
- Configuration file for elastic simulation parameters
- Comprehensive test suite with 9 test cases covering stress computation, boundary conditions, and parameter validation
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| photoelastimetry/elastic.py | Core module implementing Boussinesq analytical solution, synthetic image generation, and 16-panel visualization |
| json/elastic.json5 | Configuration file with material properties and simulation parameters |
| tests/test_elastic.py | Test suite covering stress field computation, boundary conditions, and synthetic data generation |
| .gitignore | Adds patterns for generated output files and images directory |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_parameters(): | ||
| """Fixture providing standard test parameters.""" | ||
| return { | ||
| "wavelengths_nm": np.array([650e-9, 550e-9, 450e-9]), # R, G, B wavelengths in meters |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name wavelengths_nm suggests nanometers, but the values are in meters (650e-9, 550e-9, 450e-9) and the comment confirms "in meters". This is inconsistent with the equivalent fixture in test_disk.py line 23 which correctly uses nanometer values (650, 550, 450) with the same variable name. The variable should either be renamed to wavelengths_m or the values should be changed to [650, 550, 450] to match the naming convention and be consistent with test_disk.py.
| S_i_hat : [1.0, 0.0, 0.0], // Incoming polarization state | ||
| binning: 8, | ||
| wavelengths : [650, 550, 450], // R, G, B wavelengths (nm) | ||
| C : [3e-9, 3e-9, 3e-9], // stress-optic coefficient for each wavelength (1/Pa) |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stress-optic coefficient values [3e-9, 3e-9, 3e-9] are identical for all three wavelengths (R, G, B), which differs from the pattern in test fixtures and other JSON files that use wavelength-dependent values like [2e-12, 2.2e-12, 2.5e-12] in test_disk.py or json/test.json5. While this may be intentional, using identical C values removes the wavelength-dependent behavior that is typically expected in photoelastic simulations. Consider using wavelength-dependent values like [3e-9, 3.3e-9, 3.75e-9] to better represent realistic material dispersion, or add a comment explaining why identical values are appropriate for this elastic simulation.
| C : [3e-9, 3e-9, 3e-9], // stress-optic coefficient for each wavelength (1/Pa) | |
| C : [3e-9, 3.3e-9, 3.75e-9], // stress-optic coefficient for each wavelength (1/Pa) |
| height, width = sigma_xx.shape | ||
| n_wavelengths = len(wavelengths_nm) | ||
|
|
||
| synthetic_images = np.empty((height, width, n_wavelengths, 4)) # wavelengths, 4 polarizer angles |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says "wavelengths, 4 polarizer angles" but according to line 170 the hardcoded shape is (height, width, 3, 4) in disk.py, while here it dynamically uses n_wavelengths. The comment should be more explicit about the array dimensions, like "# (height, width, n_wavelengths, 4 polarizer angles)" to match the actual shape tuple for clarity.
| synthetic_images = np.empty((height, width, n_wavelengths, 4)) # wavelengths, 4 polarizer angles | |
| synthetic_images = np.empty((height, width, n_wavelengths, 4)) # (height, width, n_wavelengths, 4 polarizer angles) |
| height, width = sigma_xx.shape | ||
| n_wavelengths = len(wavelengths_nm) | ||
|
|
||
| synthetic_images = np.empty((height, width, n_wavelengths, 4)) # wavelengths, 4 polarizer angles |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The array is initialized with np.empty() which leaves uninitialized memory. While this is immediately populated in the loop below, using np.zeros() would be safer and make debugging easier if the loop fails to populate all values. This is consistent with defensive programming practices, especially for arrays that will be saved to files.
| synthetic_images = np.empty((height, width, n_wavelengths, 4)) # wavelengths, 4 polarizer angles | |
| synthetic_images = np.zeros((height, width, n_wavelengths, 4)) # wavelengths, 4 polarizer angles |
Implements Boussinesq point load solution for elastic half-space, parallel to existing Brazil test in
disk.py. Generates synthetic stress fields and RGB polarized images for elastic contact problems.Implementation
photoelastimetry/elastic.py: Core module with analytical Boussinesq solutionboussinesq_stress_cartesian(): Computes σ_xx, σ_yy, τ_xy for point load P on semi-infinite half-spacegenerate_synthetic_boussinesq(): Produces synthetic photoelastic images via Mueller matrix formalismpost_process_synthetic_data(): 16-panel visualization (stress components, fringes, polarimetry)json/elastic.json5: Configuration with material properties (C, thickness, wavelengths, Poisson's ratio)tests/test_elastic.py: 9 tests covering stress computation, boundary conditions, synthetic image generation, parameter validationUsage
Or run as script to generate TIFF outputs:
python -m photoelastimetry.elastic # Creates images/elastic/boussinesq_synthetic_{stress,images}.tiffTechnical notes
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.