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
35 changes: 35 additions & 0 deletions include/numsim-materials/default_materials.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
#include "numsim-materials/materials/scalar_stepper.h"
#include "numsim-materials/materials/constant_scalar.h"
#include "numsim-materials/materials/props_scalar.h"
#include "numsim-materials/materials/small_strain_plasticity.h"
#include "numsim-materials/materials/rk_plasticity.h"
#include "numsim-materials/materials/linear_isotropic_hardening.h"
#include "numsim-materials/materials/exponential_isotropic_hardening.h"
#include "numsim-materials/materials/linear_damage_law.h"
#include "numsim-materials/materials/curing_rate.h"
#include "numsim-materials/materials/strain_energy_state_function.h"
#include "numsim-materials/materials/vector_strain_state_function.h"
#include "numsim-materials/materials/isotropic_tangent.h"
#include "numsim-materials/materials/linear_elasticity.h"
#include "numsim-materials/materials/linear_stress.h"
Expand Down Expand Up @@ -75,6 +83,33 @@ void register_default_materials() {
factory.template register_type<linear_elasticity<Traits>>("linear_elasticity");
factory.template register_type<constant_scalar<Traits>>("constant_scalar");
factory.template register_type<props_scalar<Traits>>("props_scalar");

// Plasticity. small_strain_plasticity and rk_plasticity are templates over
// the yield-function TYPE, so the registrable names are the concrete
// aliases, not the templates.
//
factory.template register_type<j2_plasticity<Traits>>("j2_plasticity");
factory.template register_type<j2_rk_plasticity<Traits>>("j2_rk_plasticity");

// drucker_prager_plasticity is deliberately NOT registered. Its yield
// function carries eta, beta and K_bulk and arrives as a C++ object through
// an undeclared "yield_function" parameter that the JSON reader cannot
// convert. Registered, a document could name it and would silently get a
// DEFAULT-constructed yield function -- eta = beta = k = 0 -- which builds,
// runs, never yields, and is indistinguishable from elasticity. An unknown
// material type is a loud error naming the type; a silently elastic
// Drucker-Prager is not. Register it once the yield function is expressible.

factory.template register_type<linear_isotropic_hardening<Traits>>(
"linear_isotropic_hardening");
factory.template register_type<exponential_isotropic_hardening<Traits>>(
"exponential_isotropic_hardening");
factory.template register_type<linear_damage_law<Traits>>("linear_damage_law");
factory.template register_type<curing_rate<Traits>>("curing_rate");
factory.template register_type<strain_energy_state_function<Traits>>(
"strain_energy_state_function");
factory.template register_type<vector_strain_state_function<Traits>>(
"vector_strain_state_function");
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");
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_numsim_test(test_umat_interface test_umat_interface.cpp)
add_numsim_test(test_tangent_generator test_tangent_generator.cpp)
add_numsim_test(test_json_model test_json_model.cpp)
add_numsim_test(test_props_scalar test_props_scalar.cpp)
add_numsim_test(test_material_registry test_material_registry.cpp)
target_link_libraries(test_umat_interface PRIVATE Threads::Threads)

# Data dumper for plotting (not a test — standalone executable)
Expand Down
74 changes: 74 additions & 0 deletions tests/test_material_registry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <gtest/gtest.h>
#include <string>
#include <nlohmann/json.hpp>
#include "numsim-materials/default_materials.h"
#include "numsim-materials/io/json_material_factory.h"

namespace {

namespace nm = numsim::materials;
using policy = nm::material_policy_default;
using T = policy::value_type;
using factory_type = nm::object_store<policy>::factory_type;

struct Registration {
Registration() { nm::register_default_materials<policy>(); }
};
const Registration registration_{};

/// A material that is not registered cannot be named in a document, whatever
/// else works about it. These were all absent, so a JSON model could build
/// elasticity and damage and essentially nothing else.
TEST(MaterialRegistry, PlasticityAndFriendsAreReachableFromJson) {
auto& f = factory_type::instance();
for (const char* name : {"j2_plasticity",
"j2_rk_plasticity", "linear_isotropic_hardening",
"exponential_isotropic_hardening", "linear_damage_law",
"curing_rate", "strain_energy_state_function",
"vector_strain_state_function"})
EXPECT_TRUE(f.contains(name)) << name << " cannot be named in a document";
}

/// The one that matters: a J2 model built entirely from a document, driven to
/// yield. Registration alone would pass the check above while still failing
/// here if a parameter were not JSON-convertible.
TEST(MaterialRegistry, AJ2ModelRunsFromADocumentAlone) {
const char* doc = R"([
{"type":"tensor_component_stepper_rank2","name":"stepper",
"increment":0.01,"indices":[0,0]},
{"type":"linear_elasticity","name":"elastic",
"strain_producer_name":"stepper","K":166.67,"G":76.92},
{"type":"backward_euler","name":"solver"},
{"type":"linear_isotropic_hardening","name":"hardening",
"source":"j2","K":1000.0},
{"type":"j2_plasticity","name":"j2","elastic_source":"elastic",
"hardening_source":"hardening","strain_source":"stepper",
"solver_source":"solver","G":76.92,"sigma_0":50.0}
])";

nm::material_context<policy> ctx;
ASSERT_NO_THROW({
for (const auto& m : nlohmann::json::parse(doc))
nm::create_from_json<policy>(ctx, m);
ctx.finalize();
});

for (int i = 0; i < 40; ++i) { ctx.update(); ctx.commit(); }
EXPECT_GT(ctx.get<T>("j2", "equivalent_plastic_strain"), 1e-6)
<< "the document built, but the model never yielded";
}

/// drucker_prager_plasticity is deliberately NOT registered. Its yield function
/// carries eta, beta and K_bulk and arrives as a C++ object the JSON reader
/// cannot convert, so a document naming it would get a default-constructed one:
/// eta = beta = k = 0, which builds, runs, never yields, and is
/// indistinguishable from elasticity. An unknown type is a loud error; a
/// silently elastic Drucker-Prager is not.
TEST(MaterialRegistry, DruckerPragerStaysUnregisteredWhileUnconfigurable) {
auto& f = factory_type::instance();
EXPECT_FALSE(f.contains("drucker_prager_plasticity"))
<< "registered, a document could name it and silently get eta=beta=k=0; "
"register it once yield_function is expressible in JSON";
}

} // namespace
Loading