Repository navigation
rule_of_mixture: Voigt, Reuss and Hill effective stiffness - #130
Merged
Merged
Conversation
This was referenced Oct 16, 2026
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 16, 2026 23:43
782e7f9 to
94b5a8a
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 16, 2026 23:43
b6b98af to
ed86d1b
Compare
Member
Author
|
Review findings (design, tmech expressions instead of component loops, modern C++, comments, tests, correctness). Severity: must = wrong result, hang, build break or unreachable feature; should = design, duplication, accuracy; nit = style. rule_of_mixture — needs changes (minor)
|
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
2 times, most recently
from
October 17, 2026 13:45
a9613ff to
0050150
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 17, 2026 13:45
ed86d1b to
46c99de
Compare
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 17, 2026 15:30
0050150 to
191fe75
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
2 times, most recently
from
October 17, 2026 16:32
cced83c to
7d5a01f
Compare
Member
Author
|
Producer/consumer pass: |
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 17, 2026 21:07
191fe75 to
dea9c37
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 17, 2026 21:07
7d5a01f to
1a2e21a
Compare
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 17, 2026 22:25
dea9c37 to
1141085
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 17, 2026 22:32
1a2e21a to
13a8bd0
Compare
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 18, 2026 11:34
1141085 to
daf4cd1
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 18, 2026 11:42
13a8bd0 to
f64e188
Compare
This was referenced Oct 18, 2026
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 18, 2026 13:38
daf4cd1 to
361a892
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 18, 2026 13:38
f64e188 to
6528f13
Compare
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 18, 2026 20:03
361a892 to
6e9cbdc
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 18, 2026 20:03
6528f13 to
5d53585
Compare
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 18, 2026 20:22
6e9cbdc to
1d143ff
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 18, 2026 20:22
5d53585 to
57ada14
Compare
load_driver runs one material point under mixed strain/stress control (uniaxial stress solves the five lateral strains with the material tangent) and records the Newton residuals; material_report runs the load cases of a case.json and writes CSV; reports/make_report.py turns them into figures and the results section of docs/materials/<material>/README.md.
The correction solves (P:C:P + Isym - P + Iskw) : d_eps = -P:(sigma - sigma*) with tmech::invf instead of a hand-written 6x6 elimination; Iskw makes the operator regular on the full 9x9 space. Strain, stress and tangent are tensors, converted to and from the evaluator buffers with tensor_conversion.
A report document holds the model graph, the material point, recorded
columns wired to any graph property ("material::property[i,j]"), the load
cases, the figures and the checks. Includes merge shared cases and figures;
"$name" strings take parameters. material_report writes resolved.json,
graph.json (materials, parameters, produced and consumed properties) and
CSV per case; make_report.py evaluates the checks against closed forms,
draws the figures and writes the results with the wiring diagram. Every
report is a ctest (checks only).
C++: load_control (stress/strain projectors), load_path (steps as a view), report_json (parsing into value types), case_runner (material_point and run_case over a step_sink concept), csv_sink, graph_description; the tool is now an entry point. load_driver keeps no per-step state: a step_result carries its start state, so tangent_error works for any earlier step. Produced properties are listed by name (the registry orders by address). Python: dataclasses for runs, cases and check results; expressions, checks, panel renderers (registry by kind) and Markdown sections as separate functions; unit tests in reports/test_make_report.py (ctest report_script).
The Markdown pages and committed figures are removed. make_report.py --out <dir> writes <material>.html with embedded figures and an index; nothing generated is committed. Each report starts with the parameters of report.json, where each one is used (material, case or check), the derived values and the material parameters as resolved. resolve_report records the substitutions in "parameter_usage".
- core/tensor_identities.h: sym/skew identities, volumetric and deviatoric projectors, the symmetric 3D basis in Abaqus order; used by linear_elasticity, saint_venant_kirchhoff and plasticity_utils (make_IIdev / cached_IIdev now delegate; make_isotropic_tangent keeps its K I(x)I form). - core/property_value.h: value of a plain or history property; used by material_point_evaluator::resolve_property and the report columns. - core/graph_description.h: materials with produced (history flag, sorted) and consumed properties; the report adds types and parameters. - umat/load_control.h and umat/material_point_driver.h (was report/load_driver.h): mixed strain/stress control of a material point.
make_report.py is the entry point of reports/numsim_report. Expressions own the document; Raw marks unescaped cells; ReportSummary replaces the index tuples; axis labels show tensor components as symbols. Tests per module in reports/tests (ctest report_script discovers them).
parse_point and parse_columns live in report_json.h; step_record and the step_sink concept in step_record.h, so csv_sink no longer includes the model builder. load_path::at checks its range, include nesting is capped at 16 levels, and the finite-difference step of tangent_error is a driver option (fd_step).
A plain output "iterations", so reports can record the return-map convergence of the material next to the driver's own Newton.
A check with "plot" draws value and expected per case next to its error against the tolerance (relative for relative checks); the separate closed-form figures are gone. Cases take tangent_every (default 1, 0 = never); the standard cases check every fifth step. The J2 reports record solver::iterations and show the return map next to the driver's Newton.
…n_property)
Every small-strain consumer took the strain from the fixed property "strain"
of its source. The composites that follow produce one strain per phase
("strain_matrix", "strain_<phase>"), and the phase materials have to read
those. strain_property (default "strain") names the property next to the
existing strain_source / strain_producer_name, the same way tangent_property
and nu_property do; nothing changes for existing documents.
linear_elasticity, linear_stress, j2_plasticity, drucker_prager_plasticity and
the three state functions; tests wire a material to another's stress under
the new name and check the default and a missing property.
"studies" rerun a case with several step counts; the error of a final quantity against the finest run is fitted with a power of the step size, and errors below ten times the driver tolerance count as exact. Cases take "points" (strain states in order) for non-proportional paths; the load step carries its segment and fraction. The J2 reports show the radial return exact on a proportional path and first order on tension followed by shear.
core/elliptic_integrals.h: R_F, R_C, R_D, R_J by Carlson's duplication algorithm and the complete integrals K, E, so the Eshelby tensors of ellipsoids and the orientation averaging need no Boost. core/elastic_constants.h: K, G, E, nu, lambda conversions, the isotropic stiffness, rotation of rank-2 and rank-4 tensors, rotations from axis and angle and onto a direction.
umat/deformation_gradient_driver.h drives a material point by F under mixed F / P control, Newton on the full nine components with dP/dF; deformation_control names them (21, 31, 32 included). A report whose point has a deformation_gradient_source records F and P with nine components, the Cauchy stress as stress_11..23 and J; tensors in cases may have nine components. Reports for neo_hooke and saint_venant_kirchhoff with exact checks (S = F^-1 P under uniaxial stress, simple shear, volumetric).
core/eshelby.h: sphere in closed form from the projectors; elliptic and circular cylinders along any axis or direction (Mura 11.21); ellipsoids with any semi-axes from Mura's I-integrals through Carlson's R_D, the degenerate pairs (spheroid, sphere) from the sum rules, an infinite axis dispatching to the cylinder. Tests against the closed forms, the limits, uvwmaterial's spheroid formula and the identity S_iikk = (1 + nu)/(1 - nu).
…ses, projectors of the controls, load path accessors
…n tensor, float-safe rotation_to The elliptic integrals come from Boost.Math where they are first used (the Eshelby tensors). rotation() builds [axis]_x as -(epsilon . axis); rotation_to() uses 8 eps of the scalar type instead of 1e-14, which did not compile for float and would have been c > 1 there. [[nodiscard]] on the pure helpers.
…per shape eshelby_sphere, eshelby_cylinder, eshelby_spheroid and eshelby_ellipsoid consume nu_source / nu_property and publish the output "tensor"; the engine orders and re-evaluates them with nu. Two scalar producers feed them: poisson_ratio_from_moduli (K_source, G_source -> value) and isotropic_moduli (tangent_source -> K, G, poisson_ratio through isotropize, rejecting an anisotropic tangent). Composites hold a node through eshelby_tensor_interface (tensor() at the wired nu, tensor(nu) for the self-consistent iterate). core/eshelby.h keeps the closed forms: the integrals come from Boost.Math (ellint_rd), the tensors are assembled on the eigenprojectors, equal axes are detected at sqrt(eps).
core/isotropize.h: K = Pvol::C / Dim, G = Pdev::C / (2 (Dim(Dim+1)/2 - 1)), and the isotropic part built from them. core/lebedev.h with generated tables (tools/extract_lebedev.py from uvwmaterial's rule, precisions 3 to 23, up to 194 points): spherical means and integrals of tensor-valued functions of the direction. eshelby::depolarisation for ellipsoids via Carlson's R_J, the elliptic cylinder in closed form, and the cylinder along a direction.
Phases are materials providing a tangent, with volume fractions; outputs the effective tangent, the stress and the strain concentration tensors (sum c_i A_i = Isym). Report with the closed forms of the three kernels and their ordering. Report generator: derived values resolve in dependency order, independent of the key order.
petlenz
force-pushed
the
feature/isotropize-lebedev-depolarisation
branch
from
October 19, 2026 04:06
1d143ff to
207536a
Compare
petlenz
force-pushed
the
feature/rule-of-mixture
branch
from
October 19, 2026 04:06
57ada14 to
6520437
Compare
…ls-and-constants # Conflicts: # tests/CMakeLists.txt
petlenz
changed the base branch from
feature/isotropize-lebedev-depolarisation
to
main
October 24, 2026 21:16
…eshelby-tensors # Conflicts: # tests/CMakeLists.txt
…v-depolarisation # Conflicts: # tests/CMakeLists.txt
…/rule-of-mixture # Conflicts: # tests/CMakeLists.txt
petlenz
marked this pull request as ready for review
October 27, 2026 17:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #106. Part of the uvwmaterial port (#94); stacked on #129.
phase(introduced here, the phase node of every composite): a phase is a bundle of produced properties, never a material.tangent_source(+tangent_property),fraction_source(+fraction_property, defaultvalue: aconstant_scalarwhen fixed,"cure", "state"when it evolves — there is no parameter fallback) and, for the mean-field schemes,eshelby_source/depolarisation_source(the nodes of #128/#129, default propertytensor). Outputstangent,volume_fractionand, when wired,eshelby,depolarisation. One callback; the fraction must be non-negative. Nomaterial_ref: a composite that consumes a phase consumes its properties and the engine orders everything.rule_of_mixtureis a tangent producer:phases("phases": ["stiff", "soft"]),kernelvoigt(equal strain),reuss(equal stress) orhill(their mean). Outputstangentand the strain concentration tensorsconcentration_<phase>with Σ cᵢ Aᵢ = Isym (Voigt: Isym; Reuss: Cᵢ⁻¹ : C_R; Hill: their mean, consistent with the Hill tangent). The stress is alinear_stresson the tangent, as for every tangent producer. The fractions are summed and checked per update, so phases with changing fractions or tangents (cure, damage) work. Replacessmall_strain_rule_of_mixture_materialand its kernel base.Tests (
test_rule_of_mixture, 8): Voigt is the arithmetic and Reuss the harmonic mean of K and G; Hill is their mean and lies between; a single phase returns its tangent; for every kernel thelinear_stressgives C_eff : ε, the concentrations average to Isym and the phase stresses average to the composite stress; bad fractions and kernels throw; creation from JSON; a phase republishes its Eshelby and depolarisation tensors and a bare phase publishes none.Report
docs/materials/rule_of_mixture/report.json: the three kernels in one graph (hillwith itslinear_stressas the point, Voigt and Reuss recorded), checks against E_V, E_R, E_H and the ordering, the Hill concentrations averaging to one.Also in this PR: the report generator resolves
derivedvalues in dependency order.835/835 tests pass (GCC 14, reports on).
JSON input
New material types:
phase,rule_of_mixture. Ajson_modeldocument that loads (theFromJsontest of the PR):{"materials": [ {"type": "external_strain_source", "name": "strain"}, {"type": "constant_scalar", "name": "Ka", "value": 100.0}, {"type": "constant_scalar", "name": "Ga", "value": 40.0}, {"type": "constant_scalar", "name": "Kb", "value": 10.0}, {"type": "constant_scalar", "name": "Gb", "value": 3.0}, {"type": "isotropic_tangent", "name": "Ca", "K_source": "Ka", "G_source": "Ga"}, {"type": "isotropic_tangent", "name": "Cb", "K_source": "Kb", "G_source": "Gb"}, {"type": "constant_scalar", "name": "ca", "value": 0.3}, {"type": "constant_scalar", "name": "cb", "value": 0.7}, {"type": "phase", "name": "pa", "tangent_source": "Ca", "fraction_source": "ca"}, {"type": "phase", "name": "pb", "tangent_source": "Cb", "fraction_source": "cb"}, {"type": "rule_of_mixture", "name": "rom", "phases": ["pa", "pb"], "kernel": "voigt"}, {"type": "linear_stress", "name": "composite", "tangent_source": "rom", "strain_source": "strain"} ]}phase:tangent_source/tangent_property,fraction_source/fraction_property, optionaleshelby_source/eshelby_property,depolarisation_source/depolarisation_property; outputstangent,volume_fraction,eshelby,depolarisation.rule_of_mixture:phases,kernelvoigt|reuss|hill; outputstangent,concentration_<phase>.