Skip to content

Allow writing a material parameter after construction, without invalidating bound references #23

Description

@petlenz

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions