Skip to content

Nonlinear Voigt rule of mixtures as a weighted_sum wiring - #140

Merged
petlenz merged 52 commits into
mainfrom
feature/voigt-composite
Oct 27, 2026
Merged

petlenz merged 52 commits into
mainfrom
feature/voigt-composite

Conversation

@petlenz

@petlenz petlenz commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Part of #117 (the Voigt half) and of the uvwmaterial port (#94); stacked on #139.

small_strain_rule_of_mixture_history with the Voigt kernel (equal strain in every phase, history per phase) needs no new material: each phase reads the composite strain source, and weighted_sum with constant_scalar fractions produces Σ cᵢ σᵢ and Σ cᵢ Cᵢ — the consistent Voigt tangent. This PR pins that with tests and documents it in the mapping.

Tests (test_voigt_composite, 2): a J2 phase and an elastic phase under uniaxial stress through the driver — the composite stress equals the fraction-weighted phase stresses at every step while the plastic phase yields, and the tangent matches central differences to 1e-6; while elastic the wiring equals the linear rule of mixtures (phase nodes on the two tangents, rule_of_mixture voigt, linear_stress) in stress and tangent.

Not in this PR: the Reuss kernel (equal stress, phase strains from an inner Newton with history) waits for the vector Newton work in flight; and weighted_sum cannot be written in JSON yet because the parameter converter has no reader for its terms (vector of string pairs), so there is no report for this wiring — both noted on #117. The converter (#139) emits the same Voigt wiring as rule_of_mixture + mean_field_stress for a card with a nonlinear phase.

942/942 tests pass (GCC 14, reports on).

@petlenz

petlenz commented Oct 17, 2026

Copy link
Copy Markdown
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.

Voigt composite wiring — ready (with one should)

  • [should] json_parameter_converter.h:117 already has variant<double, pair<string,string>>; a vector<pair<string,string>> reader is small and would let this ship docs/materials/voigt_composite/report.json instead of "not from JSON yet".

@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from b35575b to 68a6d39 Compare October 17, 2026 14:51
@petlenz
petlenz force-pushed the feature/voigt-composite branch from 3d2fd8e to 4e92931 Compare October 17, 2026 15:01
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from 68a6d39 to d920fb3 Compare October 17, 2026 16:16
@petlenz
petlenz force-pushed the feature/voigt-composite branch from 4e92931 to bf49f47 Compare October 17, 2026 16:16
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from d920fb3 to fdaa5f7 Compare October 17, 2026 17:22
@petlenz
petlenz force-pushed the feature/voigt-composite branch from bf49f47 to e5e56ce Compare October 17, 2026 17:22
@petlenz

petlenz commented Oct 17, 2026

Copy link
Copy Markdown
Member Author

Rebased: the linear reference is a rule_of_mixture over two inclusion phases fed by the same c_plastic/c_elastic constants the weighted_sum wiring uses.

@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from fdaa5f7 to 00adc74 Compare October 17, 2026 21:44
@petlenz
petlenz force-pushed the feature/voigt-composite branch from e5e56ce to 3693657 Compare October 17, 2026 21:44
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from 00adc74 to 439b34d Compare October 17, 2026 22:46
@petlenz
petlenz force-pushed the feature/voigt-composite branch from 3693657 to d067a3e Compare October 17, 2026 22:46
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from 439b34d to c81bf8f Compare October 18, 2026 13:13
@petlenz
petlenz force-pushed the feature/voigt-composite branch from d067a3e to a586b3c Compare October 18, 2026 13:25
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from c81bf8f to d9a9773 Compare October 18, 2026 13:38
@petlenz
petlenz force-pushed the feature/voigt-composite branch from a586b3c to 6cd5670 Compare October 18, 2026 13:38
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from d9a9773 to 76c0d56 Compare October 18, 2026 18:55
@petlenz
petlenz force-pushed the feature/voigt-composite branch from 6cd5670 to 8a28695 Compare October 18, 2026 18:55
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from 76c0d56 to 083302e Compare October 18, 2026 20:03
@petlenz
petlenz force-pushed the feature/voigt-composite branch from 8a28695 to 11c29c7 Compare October 18, 2026 20:03
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from 083302e to b6f2221 Compare October 18, 2026 20:22
@petlenz
petlenz force-pushed the feature/voigt-composite branch from 11c29c7 to a5df503 Compare October 18, 2026 20:22
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.
…history

sigma_{n+1} = sigma_n + C : (eps_{n+1} - eps_n) with the tangent read from
another material, for path-dependent tangents. Report: equals the total
form on every path, a closed path returns to zero, exact for any step.
Drivers: the convergence test also scales with |C| |d eps| (|A| |dF|), so
a hypoelastic stress crossing zero under stress control converges.
eps_th = alpha (T - T_ref) I from a scalar temperature source; linear
elasticity subtracts an optional eigenstrain: sigma = C : (eps - eps_eig).
dz/dt = (k1 + k2 z^m) (1 - z)^n with Arrhenius rate constants, as a rate
law for rk_integrator next to curing_rate (the autocatalytic term alone;
nth order is curing_rate with m = 0).
inclusion takes a fraction_source ("material::property") so the volume
fraction can follow the degree of cure; the chemical shrinkage
beta xi I is thermal_eigenstrain with the cure state as its source.
Three propagation laws of uvwmaterial next to the linear and exponential
ones (damage_exponential2 is the existing exponential law). Report of
isotropic_damage with every law recorded; the report point takes
stress_property and tangent_property; named entries of an include can be
replaced, so the tangent check skips the steps on the damage surface.
…d the state-function parameters

The converter writes an eshelby_sphere / _cylinder / _spheroid node per
uvwmaterial eshelby_tensor, wired to the composite's matrix, and the inclusion
or short_fibre_composite names it. Its output is the report layout
{"model", "point"}: json_model rejects an unknown top-level key, so the
earlier {"materials", "point"} did not load. uvwmaterial's linear law
D = K kappa is the power law with m = 1 (linear_damage_law is the kappa_0 ..
kappa_f ramp); strain_energy_state_function gets tangent_source and
youngs_modulus, vector_strain_state_function the axis indices. The C++ cards
test holds the converter's actual output.
Every phase reads the composite strain; weighted_sum with constant_scalar
fractions gives the Voigt stress and the consistent tangent. Tested with
a J2 and an elastic phase under uniaxial stress against the weighted
phase stresses and against rule_of_mixture while elastic.
@petlenz
petlenz force-pushed the feature/uvwmaterial-mapping branch from b6f2221 to 98ec074 Compare October 19, 2026 04:07
@petlenz
petlenz force-pushed the feature/voigt-composite branch from a5df503 to 53d3c19 Compare October 19, 2026 04:07
Main has the reviewed split of this branch (#199-#203), so main's version is
taken everywhere; the branch no longer differs from main.
…ls-and-constants

# Conflicts:
#	tests/CMakeLists.txt
@petlenz
petlenz changed the base branch from feature/uvwmaterial-mapping to main October 24, 2026 21:17
…eshelby-tensors

# Conflicts:
#	tests/CMakeLists.txt
…v-depolarisation

# Conflicts:
#	tests/CMakeLists.txt
…/rule-of-mixture

# Conflicts:
#	tests/CMakeLists.txt
# Conflicts:
#	include/numsim-materials/report/report_json.h
#	tests/CMakeLists.txt
residual_source, residual_tolerance and max_passes are driver parameters
(material_point's defaults) and keys of the report's "point"; the mean-field
tangent report uses them for the self-consistent fixed point.
…averaging

# Conflicts:
#	tests/CMakeLists.txt
…-composite

# Conflicts:
#	tests/CMakeLists.txt
…-elasticity

# Conflicts:
#	include/numsim-materials/umat/deformation_gradient_driver.h
#	include/numsim-materials/umat/material_point_driver.h
#	tests/CMakeLists.txt
…genstrain

# Conflicts:
#	tests/CMakeLists.txt
# Conflicts:
#	include/numsim-materials/report/report_json.h
#	tests/CMakeLists.txt
#	tests/test_report_case.cpp
The report's "point" names them for materials that publish e.g.
damaged_stress / damaged_tangent (isotropic_damage report).
# Conflicts:
#	reports/CMakeLists.txt
#	tests/CMakeLists.txt
@petlenz
petlenz marked this pull request as ready for review October 27, 2026 17:50
@petlenz
petlenz merged commit bfa1509 into main Oct 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant