Skip to content

generate.inclined_plane

Inclined plane stress field simulation.

This module provides functions for simulating the photoelastic response of a material under inclined plane stress conditions (rectangular mass with gravity acting at an angle).

inclined_plane

Functions

inclined_stress_cartesian(X, Y, rho, g=9.81, theta_deg=0.0, K0=0.5)

Stress field for an inclined plane (rectangular mass with inclined gravity).

This computes the stress field in a rectangular domain with gravity acting at an angle theta from vertical. The resulting stress field includes both normal stresses that vary with depth and shear stresses due to the inclined gravity.

Parameters:

Name Type Description Default
X array - like

X coordinates (horizontal position).

required
Y array - like

Y coordinates (depth, positive downward from surface).

required
rho float

Density (kg/m^3).

required
g float

Gravitational acceleration (m/s^2).

9.81
theta_deg float

Inclination angle of gravity from vertical (degrees). 0 degrees = vertical (standard lithostatic) Positive angles tilt gravity towards +x direction

0.0
K0 float

Coefficient of lateral earth pressure at rest. Used to relate stresses perpendicular to the inclined direction.

0.5

Returns:

Name Type Description
sigma_xx array - like

Normal stress in x direction (Pa).

sigma_yy array - like

Normal stress in y direction (Pa).

tau_xy array - like

Shear stress (Pa).

Notes

For an inclined gravity field, the body forces are: - f_x = rho * g * sin(theta) (horizontal component) - f_y = rho * g * cos(theta) (vertical component)

The stress field must satisfy equilibrium: - dσ_xx/dx + dτ_xy/dy + f_x = 0 - dτ_xy/dx + dσ_yy/dy + f_y = 0

For a uniform rectangular mass with no boundaries except at the top, we assume a solution where stresses increase linearly with depth in the direction of gravity, and include shear stress from the inclined component.

Source code in photoelastimetry/generate/inclined_plane.py
def inclined_stress_cartesian(X, Y, rho, g=9.81, theta_deg=0.0, K0=0.5):
    """
    Stress field for an inclined plane (rectangular mass with inclined gravity).

    This computes the stress field in a rectangular domain with gravity
    acting at an angle theta from vertical. The resulting stress field
    includes both normal stresses that vary with depth and shear stresses
    due to the inclined gravity.

    Parameters
    ----------
    X : array-like
        X coordinates (horizontal position).
    Y : array-like
        Y coordinates (depth, positive downward from surface).
    rho : float
        Density (kg/m^3).
    g : float
        Gravitational acceleration (m/s^2).
    theta_deg : float
        Inclination angle of gravity from vertical (degrees).
        0 degrees = vertical (standard lithostatic)
        Positive angles tilt gravity towards +x direction
    K0 : float
        Coefficient of lateral earth pressure at rest.
        Used to relate stresses perpendicular to the inclined direction.

    Returns
    -------
    sigma_xx : array-like
        Normal stress in x direction (Pa).
    sigma_yy : array-like
        Normal stress in y direction (Pa).
    tau_xy : array-like
        Shear stress (Pa).

    Notes
    -----
    For an inclined gravity field, the body forces are:
    - f_x = rho * g * sin(theta)  (horizontal component)
    - f_y = rho * g * cos(theta)  (vertical component)

    The stress field must satisfy equilibrium:
    - dσ_xx/dx + dτ_xy/dy + f_x = 0
    - dτ_xy/dx + dσ_yy/dy + f_y = 0

    For a uniform rectangular mass with no boundaries except at the top,
    we assume a solution where stresses increase linearly with depth
    in the direction of gravity, and include shear stress from the
    inclined component.
    """
    theta_rad = np.deg2rad(theta_deg)

    # Components of gravity
    g_x = g * np.sin(theta_rad)  # Horizontal component
    g_y = g * np.cos(theta_rad)  # Vertical component

    # For a simple inclined plane solution, we assume:
    # 1. Vertical stress component increases with depth due to g_y
    # 2. Horizontal stress is related by K0
    # 3. Shear stress arises from the horizontal gravity component

    # Stress in the direction of gravity (normal to inclined layers)
    # For simplicity, we compute stress as if in a rotated coordinate system
    # then transform back to x-y coordinates

    # Normal stress perpendicular to gravity direction
    sigma_normal = rho * g * Y  # Total weight effect with depth

    # In the inclined case, we decompose this into x-y components
    # The vertical stress component
    sigma_yy = rho * g_y * Y

    # The horizontal stress has contributions from both K0 effect and inclination
    sigma_xx = K0 * sigma_yy

    # Shear stress arises from the inclined gravity
    # In equilibrium, tau_xy must balance the horizontal body force
    # For a linear variation: dtau_xy/dy = -rho * g_x
    # Integrating: tau_xy = -rho * g_x * Y + C
    # With free surface at Y=0: tau_xy(Y=0) = 0, so C = 0
    tau_xy = rho * g_x * Y

    # Ensure non-negative normal stresses (no tension)
    sigma_yy = np.maximum(0, sigma_yy)
    sigma_xx = np.maximum(0, sigma_xx)

    return sigma_xx, sigma_yy, tau_xy

generate_synthetic_inclined_plane(X, Y, rho, g, theta_deg, K0, S_i_hat, wavelengths_nm, thickness, C)

Generate synthetic inclined plane stress data.

Parameters:

Name Type Description Default
X array - like

Coordinate grids

required
Y array - like

Coordinate grids

required
rho float

Density (kg/m^3)

required
g float

Gravitational acceleration (m/s^2)

required
theta_deg float

Inclination angle from vertical (degrees)

required
K0 float

Coefficient of lateral earth pressure

required
S_i_hat array - like

Incoming normalised Stokes vector

required
wavelengths_nm array - like

Wavelengths in meters

required
thickness float

Sample thickness (m)

required
C array - like

Stress-optic coefficients for each wavelength

required

Returns:

Name Type Description
synthetic_images array - like

Generated synthetic images [height, width, n_wavelengths, 4]

principal_diff array - like

Principal stress difference

theta_p array - like

Principal stress angle

sigma_xx, sigma_yy, tau_xy : array-like

Stress components

Source code in photoelastimetry/generate/inclined_plane.py
def generate_synthetic_inclined_plane(X, Y, rho, g, theta_deg, K0, S_i_hat, wavelengths_nm, thickness, C):
    """
    Generate synthetic inclined plane stress data.

    Parameters
    ----------
    X, Y : array-like
        Coordinate grids
    rho : float
        Density (kg/m^3)
    g : float
        Gravitational acceleration (m/s^2)
    theta_deg : float
        Inclination angle from vertical (degrees)
    K0 : float
        Coefficient of lateral earth pressure
    S_i_hat : array-like
        Incoming normalised Stokes vector
    wavelengths_nm : array-like
        Wavelengths in meters
    thickness : float
        Sample thickness (m)
    C : array-like
        Stress-optic coefficients for each wavelength

    Returns
    -------
    synthetic_images : array-like
        Generated synthetic images [height, width, n_wavelengths, 4]
    principal_diff : array-like
        Principal stress difference
    theta_p : array-like
        Principal stress angle
    sigma_xx, sigma_yy, tau_xy : array-like
        Stress components
    """
    # Get stress components
    sigma_xx, sigma_yy, tau_xy = inclined_stress_cartesian(X, Y, rho, g, theta_deg, K0)

    # Principal stress difference and angle
    sigma_avg = 0.5 * (sigma_xx + sigma_yy)
    R_mohr = np.sqrt(((sigma_xx - sigma_yy) / 2) ** 2 + tau_xy**2)
    sigma1 = sigma_avg + R_mohr
    sigma2 = sigma_avg - R_mohr
    principal_diff = sigma1 - sigma2
    theta_p = 0.5 * np.arctan2(2 * tau_xy, sigma_xx - sigma_yy)

    height, width = sigma_xx.shape
    n_colors = len(wavelengths_nm)

    synthetic_images = np.zeros((height, width, n_colors, 4))

    for i, lambda_light in enumerate(wavelengths_nm):
        # Stress-optic coefficient for this wavelength
        c_lambda = C[i]

        # Simulate polarimetry
        I0, I45, I90, I135 = simulate_four_step_polarimetry(
            sigma_xx, sigma_yy, tau_xy, c_lambda, 1.0, thickness, lambda_light, S_i_hat  # nu (solid fraction)
        )

        # Stack into our array
        synthetic_images[:, :, i, 0] = I0
        synthetic_images[:, :, i, 1] = I45
        synthetic_images[:, :, i, 2] = I90
        synthetic_images[:, :, i, 3] = I135

    return synthetic_images, principal_diff, theta_p, sigma_xx, sigma_yy, tau_xy