Summary
Material parameters are write-once. A material binds them in its constructor —
m_K(base::template get_parameter<value_type>("K"))
— and holds a const value_type&. There is no supported way to change that value
afterwards, so a host whose material constants vary between calls cannot be
represented at all.
That is not hypothetical. Abaqus fixes PROPS per material name, so reading it once
at graph-construction time is correct there. CalculiX interpolates *USER MATERIAL
constants by temperature, so they genuinely differ from call to call — the
codegen'd CalculiX material reads them fresh on every call for exactly this reason.
The mechanism
The bound reference points at the object inside the std::any inside the handler's
map node, so a write is observable by every material that bound it — provided the
object does not move.
template <typename T>
void set_parameter(std::string const& key, T const& value) {
m_parameter_handler.template get<T>(key) = value;
}
Assigning through the non-const get<T>() is the entire point. insert() must
not be used: it goes through insert_or_assign, which replaces the whole
std::any. For a value larger than std::any's small buffer that destroys the
contained object and constructs a new one elsewhere, dangling every reference bound
at construction.
Why this needs a test rather than a comment
The distinction is invisible with scalar parameters. A double fits the small
buffer, so insert() preserves its address by accident:
| write path |
double |
256-byte parameter |
insert(key, v) |
address stable (small-buffer optimisation) |
relocates → bound refs dangle |
get<T>(key) = v |
stable |
stable |
An implementation built on insert() would pass any test written against moduli and
break the first time someone stored a tensor-valued parameter.
test_set_parameter asserts address stability for a 256-byte parameter, and
separately pins the underlying parameter_handler behaviour, so the rationale lives
next to the mechanism.
Out of scope
Quantities derived from parameters. A material that precomputes something in its
constructor will not notice a later write — see #24 for how that is handled
where the derived value lives.
Branch
feature/material-set-parameter (06136f2), based on feature/vector-solver.
184/184 tests pass.
Summary
Material parameters are write-once. A material binds them in its constructor —
— and holds a
const value_type&. There is no supported way to change that valueafterwards, so a host whose material constants vary between calls cannot be
represented at all.
That is not hypothetical. Abaqus fixes
PROPSper material name, so reading it onceat graph-construction time is correct there. CalculiX interpolates
*USER MATERIALconstants by temperature, so they genuinely differ from call to call — the
codegen'd CalculiX material reads them fresh on every call for exactly this reason.
The mechanism
The bound reference points at the object inside the
std::anyinside the handler'smap node, so a write is observable by every material that bound it — provided the
object does not move.
Assigning through the non-const
get<T>()is the entire point.insert()mustnot be used: it goes through
insert_or_assign, which replaces the wholestd::any. For a value larger thanstd::any's small buffer that destroys thecontained object and constructs a new one elsewhere, dangling every reference bound
at construction.
Why this needs a test rather than a comment
The distinction is invisible with scalar parameters. A
doublefits the smallbuffer, so
insert()preserves its address by accident:doubleinsert(key, v)get<T>(key) = vAn implementation built on
insert()would pass any test written against moduli andbreak the first time someone stored a tensor-valued parameter.
test_set_parameterasserts address stability for a 256-byte parameter, andseparately pins the underlying
parameter_handlerbehaviour, so the rationale livesnext to the mechanism.
Out of scope
Quantities derived from parameters. A material that precomputes something in its
constructor will not notice a later write — see #24 for how that is handled
where the derived value lives.
Branch
feature/material-set-parameter(06136f2), based onfeature/vector-solver.184/184 tests pass.