diff --git a/include/numsim-materials/default_materials.h b/include/numsim-materials/default_materials.h index d433970..0d0045b 100644 --- a/include/numsim-materials/default_materials.h +++ b/include/numsim-materials/default_materials.h @@ -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" @@ -75,6 +83,33 @@ void register_default_materials() { factory.template register_type>("linear_elasticity"); factory.template register_type>("constant_scalar"); factory.template register_type>("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"); + factory.template register_type>("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"); + factory.template register_type>( + "exponential_isotropic_hardening"); + factory.template register_type>("linear_damage_law"); + factory.template register_type>("curing_rate"); + factory.template register_type>( + "strain_energy_state_function"); + factory.template register_type>( + "vector_strain_state_function"); factory.template register_type>("isotropic_tangent"); factory.template register_type>("linear_stress"); factory.template register_type>("autocatalytic_reaction"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4425a79..7f1d82b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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) diff --git a/tests/test_material_registry.cpp b/tests/test_material_registry.cpp new file mode 100644 index 0000000..306c790 --- /dev/null +++ b/tests/test_material_registry.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#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::factory_type; + +struct Registration { + Registration() { nm::register_default_materials(); } +}; +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 ctx; + ASSERT_NO_THROW({ + for (const auto& m : nlohmann::json::parse(doc)) + nm::create_from_json(ctx, m); + ctx.finalize(); + }); + + for (int i = 0; i < 40; ++i) { ctx.update(); ctx.commit(); } + EXPECT_GT(ctx.get("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