Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/numsim-materials/default_materials.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
#include "numsim-materials/solvers/backward_euler.h"
#include "numsim-materials/solvers/vector_newton.h"
#include "numsim-materials/materials/scalar_stepper.h"
#include "numsim-materials/materials/constant_scalar.h"
#include "numsim-materials/materials/isotropic_tangent.h"
#include "numsim-materials/materials/linear_elasticity.h"
#include "numsim-materials/materials/linear_stress.h"
#include "numsim-materials/materials/autocatalytic_reaction.h"
#include "numsim-materials/materials/tensor_component_stepper.h"
#include "numsim-materials/materials/scalar_identity_weight.h"
Expand Down Expand Up @@ -69,6 +72,9 @@ void register_default_materials() {
auto& factory = material_factory<Traits>::instance();
factory.template register_type<scalar_stepper<Traits>>("scalar_stepper");
factory.template register_type<linear_elasticity<Traits>>("linear_elasticity");
factory.template register_type<constant_scalar<Traits>>("constant_scalar");
factory.template register_type<isotropic_tangent<Traits>>("isotropic_tangent");
factory.template register_type<linear_stress<Traits>>("linear_stress");
factory.template register_type<autocatalytic_reaction<Traits>>("autocatalytic_reaction");
factory.template register_type<backward_euler<Traits>>("backward_euler");
factory.template register_type<tensor_component_stepper<1, Traits>>("tensor_component_stepper_rank1");
Expand Down
41 changes: 41 additions & 0 deletions include/numsim-materials/materials/constant_scalar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef NUMSIM_MATERIALS_CONSTANT_SCALAR_H
#define NUMSIM_MATERIALS_CONSTANT_SCALAR_H

#include "numsim-materials/core/material_base.h"

namespace numsim::materials {

/// A fixed scalar, published as a graph property.
///
/// Makes a modulus or yield stress a real edge instead of a parameter, so the
/// consumer is ordered after it. Plain, not history, so it costs no STATEV
/// slot; use external_scalar_source when a consumer needs an old/new pair.
/// No update callback — the value is set once, at construction.
template <typename Traits>
class constant_scalar final
: public material_base<constant_scalar<Traits>, Traits> {
public:
using base = material_base<constant_scalar<Traits>, Traits>;
using value_type = typename base::value_type;
using input_parameter_controller = typename base::input_parameter_controller;

template <typename... Args>
explicit constant_scalar(Args&&... args)
: base(std::forward<Args>(args)...),
m_value(base::template add_output<value_type>("value")) {
m_value = base::template get_parameter<value_type>("value");
}

static input_parameter_controller parameters() {
input_parameter_controller para{base::parameters()};
para.template insert<value_type>("value").template add<is_required>();
return para;
}

private:
value_type& m_value;
};

} // namespace numsim::materials

#endif // NUMSIM_MATERIALS_CONSTANT_SCALAR_H
78 changes: 78 additions & 0 deletions include/numsim-materials/materials/isotropic_tangent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef NUMSIM_MATERIALS_ISOTROPIC_TANGENT_H
#define NUMSIM_MATERIALS_ISOTROPIC_TANGENT_H

#include <tmech/tmech.h>
#include "numsim-materials/core/material_base.h"
#include "numsim-materials/materials/plasticity_utils.h"

namespace numsim::materials {

/// Isotropic elastic stiffness as a material, with K and G as graph inputs.
///
/// A material reading its OWN property creates no edge, so linear_elasticity's
/// stress sorts before its tangent and would consume a stale stiffness. Reading
/// another material's property is a real edge the sort honours — which is why
/// the moduli are inputs rather than parameters.
///
/// Wire from constant_scalar when fixed, or any scalar producer when they vary;
/// K_property/G_property if it does not publish under "value". Which one you
/// wire IS the choice, so no flag can disagree with it.
///
/// Rebuilds on every update: no memo, so no cached state to go stale. The pair
/// costs ~315 ns per update against ~26 ns for linear_elasticity, which
/// computes its tangent once — so where the moduli are fixed and 12x matters,
/// that is still the cheaper material.
template <typename Traits>
class isotropic_tangent final
: public material_base<isotropic_tangent<Traits>, Traits> {
public:
using base = material_base<isotropic_tangent<Traits>, Traits>;
using value_type = typename base::value_type;
using input_parameter_controller = typename base::input_parameter_controller;
using base::Dim;
using tensor4 = tmech::tensor<value_type, Dim, 4>;

template <typename... Args>
explicit isotropic_tangent(Args&&... args)
: base(std::forward<Args>(args)...),
m_C(base::template add_output<tensor4>(
"tangent", &isotropic_tangent::update_tangent)),
m_K(base::template add_input<value_type>(
base::template get_parameter<std::string>("K_source"),
base::template get_parameter<std::string>("K_property"),
EdgeKind::Global)),
m_G(base::template add_input<value_type>(
base::template get_parameter<std::string>("G_source"),
base::template get_parameter<std::string>("G_property"),
EdgeKind::Global)) {}

static input_parameter_controller parameters() {
input_parameter_controller para{base::parameters()};
para.template insert<std::string>("K_source").template add<is_required>();
para.template insert<std::string>("G_source").template add<is_required>();
// Defaults to the scalar-output convention constant_scalar and
// scalar_identity_weight follow. Override for a source that publishes under
// another name — external_scalar_source publishes "state", for instance.
para.template insert<std::string>("K_property")
.template add<set_default>(std::string{"value"});
para.template insert<std::string>("G_property")
.template add<set_default>(std::string{"value"});
return para;
}

void update_tangent() {
const auto I{tmech::eye<value_type, Dim, 2>()};
const auto IIvol{tmech::otimes(I, I) / Dim};
m_C = 3 * m_K.get() * IIvol +
2 * m_G.get() * plasticity_detail::make_IIdev<value_type, Dim>();
}

private:
tensor4& m_C;
const input_property<value_type, property_traits>& m_K;
const input_property<value_type, property_traits>& m_G;
};

} // namespace numsim::materials

#endif // NUMSIM_MATERIALS_ISOTROPIC_TANGENT_H
57 changes: 57 additions & 0 deletions include/numsim-materials/materials/linear_stress.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#ifndef NUMSIM_MATERIALS_LINEAR_STRESS_H
#define NUMSIM_MATERIALS_LINEAR_STRESS_H

#include <tmech/tmech.h>
#include "numsim-materials/core/material_base.h"

namespace numsim::materials {

/// sigma = C : eps, with C supplied by another material.
///
/// linear_elasticity with the tangent as a Global input rather than an owned
/// output, which is what makes the ordering correct: another material's
/// property is an edge, your own is not. Pair with any tangent generator;
/// linear_elasticity stays better when the moduli are fixed.
template <typename Traits>
class linear_stress final
: public material_base<linear_stress<Traits>, Traits> {
public:
using base = material_base<linear_stress<Traits>, Traits>;
using value_type = typename base::value_type;
using input_parameter_controller = typename base::input_parameter_controller;
using base::Dim;
using tensor2 = tmech::tensor<value_type, Dim, 2>;
using tensor4 = tmech::tensor<value_type, Dim, 4>;

template <typename... Args>
explicit linear_stress(Args&&... args)
: base(std::forward<Args>(args)...),
m_sig(base::template add_output<tensor2>(
"stress", &linear_stress::update_stress)),
m_C(base::template add_input<tensor4>(
base::template get_parameter<std::string>("tangent_source"),
"tangent", EdgeKind::Global)),
m_eps(base::template add_input<tensor2>(
base::template get_parameter<std::string>("strain_source"),
"strain", EdgeKind::Global)) {}

static input_parameter_controller parameters() {
input_parameter_controller para{base::parameters()};
para.template insert<std::string>("tangent_source")
.template add<is_required>();
para.template insert<std::string>("strain_source")
.template add<is_required>();
return para;
}

void update_stress() { m_sig = tmech::dcontract(m_C.get(), m_eps.get()); }

private:
tensor2& m_sig;
const input_property<tensor4, property_traits>& m_C;
const input_property<tensor2, property_traits>& m_eps;
};

} // namespace numsim::materials

#endif // NUMSIM_MATERIALS_LINEAR_STRESS_H
13 changes: 10 additions & 3 deletions include/numsim-materials/umat/material_point_evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <cstddef>
#include <memory>
#include <optional>
#include <span>
#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -43,7 +44,7 @@ class material_point_evaluator {
struct config {
/// Name of the external_strain_source material.
std::string strain_source;
/// Material producing the stress and tangent the host wants back.
/// Material producing the stress the host wants back.
std::string stress_source;
std::string stress_property{"stress"};
std::string tangent_property{"tangent"};
Expand All @@ -59,6 +60,11 @@ class material_point_evaluator {
/// Additional host-owned history to keep out of STATEV, beyond the strain
/// and time sources (which are excluded automatically).
std::vector<statev_exclusion> extra_exclusions{};
/// Unset means "same as stress_source"; set it when the stiffness is its
/// own material. Optional rather than "" so the two stay distinct, and
/// APPENDED — a field inserted mid-struct would silently re-bind the
/// trailing arguments of an existing aggregate initialiser.
std::optional<std::string> tangent_source{};
};

/// One host call's arguments.
Expand Down Expand Up @@ -111,8 +117,9 @@ class material_point_evaluator {

m_stress =
resolve_property<tensor2>(m_cfg.stress_source, m_cfg.stress_property);
m_tangent =
resolve_property<tensor4>(m_cfg.stress_source, m_cfg.tangent_property);
const std::string& tangent_owner =
m_cfg.tangent_source ? *m_cfg.tangent_source : m_cfg.stress_source;
m_tangent = resolve_property<tensor4>(tangent_owner, m_cfg.tangent_property);

if (!m_cfg.plastic_strain_property.empty()) {
const auto src = connection_source::parse(m_cfg.plastic_strain_property);
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_numsim_test(test_statev_map test_statev_map.cpp)
add_numsim_test(test_material_point_evaluator test_material_point_evaluator.cpp)
add_numsim_test(test_plane_stress_evaluator test_plane_stress_evaluator.cpp)
add_numsim_test(test_umat_interface test_umat_interface.cpp)
add_numsim_test(test_tangent_generator test_tangent_generator.cpp)
target_link_libraries(test_umat_interface PRIVATE Threads::Threads)

# Data dumper for plotting (not a test — standalone executable)
Expand Down
Loading
Loading