Analytic compliance gradient of a thin cantilever plate.
+A clamped, isotropic rectangular plate under uniform normal pressure has one uniform
thickness design variable t. In pure bending its stiffness is proportional to
t**3, hence C(t) = k/t**3 and dC/dt = -3*C/t exactly. This example
compares that closed-form derivative with the CSDL total derivative, providing an
adjoint check which is independent of finite differences.
Reissner–Mindlin transverse shear adds a term proportional to 1/t to the
compliance, so the pure-bending identity is not mathematically exact for this shell.
The deliberately thin t = 0.01 plate makes the residual small; the script reports
the measured derivative ratio and infers the corresponding shear fraction
(3/2) * (1 - ratio). The 1% tolerance is fixed to admit that physical, not
numerical, contamination.
"""Analytic compliance gradient of a thin cantilever plate.
+A clamped, isotropic rectangular plate under uniform normal pressure has one uniform
thickness design variable ``t``. In pure bending its stiffness is proportional to
``t**3``, hence ``C(t) = k/t**3`` and ``dC/dt = -3*C/t`` exactly. This example
compares that closed-form derivative with the CSDL total derivative, providing an
adjoint check which is independent of finite differences.
Reissner--Mindlin transverse shear adds a term proportional to ``1/t`` to the
compliance, so the pure-bending identity is not mathematically exact for this shell.
The deliberately thin ``t = 0.01`` plate makes the residual small; the script reports
the measured derivative ratio and infers the corresponding shear fraction
``(3/2) * (1 - ratio)``. The 1% tolerance is fixed to admit that physical, not
numerical, contamination.
"""
import pathlib
import sys
import csdl_alpha as csdl
import numpy as np
import hermit as hm
sys.path.insert(0, str(pathlib.Path(__file__).parent))
from _geometry import rect_plate # noqa: E402
from _harness import Case, main # noqa: E402
LENGTH, WIDTH = 4.0, 1.0
E, NU, THICKNESS, PRESSURE = 4.32e8, 0.0, 0.01, 1.0
def solve_at(n):
"""Return ``dC/dt`` divided by the thin-plate pure-bending identity."""
mesh = rect_plate(LENGTH, WIDTH, nx=4 * n, ny=n, cell="quad")
rec = csdl.Recorder(inline=True)
rec.start()
t = csdl.Variable(value=THICKNESS, name="uniform_thickness")
domain = hm.ShellDomain(mesh, element="CG2CG1")
material = hm.isotropic(domain, E=E, nu=NU, thickness=t, density=1.0)
state = hm.solve(domain, material, hm.pressure(domain, PRESSURE),
hm.clamp(domain, where=lambda x: np.isclose(x[0], 0.0)))
compliance = hm.compliance(state)
sim = csdl.experimental.PySimulator(rec)
derivative = float(np.asarray(sim.compute_totals([compliance], [t])[compliance, t]).ravel()[0])
value = float(np.asarray(compliance.value).ravel()[0])
rec.stop()
bending = -3.0 * value / THICKNESS
ratio = derivative / bending
shear_fraction = 1.5 * (1.0 - ratio)
print(f" C={value:.6e} dC/dt(CSDL)={derivative:.6e} "
f"-3C/t={bending:.6e} ratio={ratio:.8f} "
f"inferred shear fraction={shear_fraction:.3e}")
return ratio
CASE = Case(
name="Analytic compliance gradient: uniform thin cantilever",
quantity="dC/dt (CSDL) / (-3 C/t)",
reference=1.0,
tolerance=0.01,
citation="Euler--Bernoulli pure-bending scaling: D = E t^3 / [12(1-nu^2)]",
levels=(2, 4, 6),
quick_level=2,
solve=solve_at,
monotone=False,
notes="remaining discrepancy is quantified Reissner--Mindlin shear, not FD error",
)
if __name__ == "__main__":
main(CASE)