-
Notifications
You must be signed in to change notification settings - Fork 0
materials: let weighted_sum and isotropic_damage source a tangent separately #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
petlenz
wants to merge
13
commits into
feature/elastic-stiffness-material
Choose a base branch
from
feature/tangent-source-consumers
base: feature/elastic-stiffness-material
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
a1bd102
materials: let weighted_sum and isotropic_damage source a tangent sep…
petlenz 1f7a9c6
materials: drop weighted_sum's dead update(), and state what tangent_…
petlenz af2c6bc
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz ab4d458
materials: shorten the comments
petlenz 4a2a294
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz 33a6975
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz d546bb8
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz c6f7449
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz b2b9ec9
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz 6d26c7b
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz b0df337
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz baad8ec
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz ca85f69
Merge branch 'feature/elastic-stiffness-material' into feature/tangen…
petlenz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,213 @@ | ||
| #include <gtest/gtest.h> | ||
| #include <string> | ||
| #include <utility> | ||
| #include <vector> | ||
| #include <tmech/tmech.h> | ||
| #include "numsim-materials/core/material_context.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/scalar_identity_weight.h" | ||
| #include "numsim-materials/materials/scalar_stepper.h" | ||
| #include "numsim-materials/materials/weighted_sum.h" | ||
| #include "numsim-materials/umat/external_state_source.h" | ||
|
|
||
| namespace { | ||
|
|
||
| namespace nm = numsim::materials; | ||
|
|
||
| using policy = nm::material_policy_default; | ||
| using T = policy::value_type; | ||
| using ctx_type = nm::material_context<policy>; | ||
| using param_type = policy::ParameterHandler; | ||
| using tensor2 = tmech::tensor<T, 3, 2>; | ||
| using tensor4 = tmech::tensor<T, 3, 4>; | ||
| using terms_type = std::vector<std::pair<std::string, std::string>>; | ||
|
|
||
| constexpr T KA = 100.0, GA = 40.0; | ||
| constexpr T KB = 300.0, GB = 140.0; | ||
|
|
||
| /// A weight in [0,1] published as "value", via scalar_identity_weight over a | ||
| /// scalar_stepper's history. | ||
| void add_weight(ctx_type& ctx, const std::string& name, T increment) { | ||
| param_type p; | ||
| p.insert<std::string>("name", name + "_drv"); | ||
| p.insert<T>("increment", increment); | ||
| ctx.create<nm::scalar_stepper<policy>>(p); | ||
| p.clear(); | ||
| p.insert<std::string>("name", name); | ||
| p.insert<std::string>("source", name + "_drv::state"); | ||
| ctx.create<nm::scalar_identity_weight<policy>>(p); | ||
| } | ||
|
|
||
| void add_monolithic(ctx_type& ctx, const std::string& name, T k, T g) { | ||
| param_type p; | ||
| p.insert<std::string>("name", name); | ||
| p.insert<std::string>("strain_producer_name", "strain_in"); | ||
| p.insert<T>("K", k); | ||
| p.insert<T>("G", g); | ||
| ctx.create<nm::linear_elasticity<policy>>(p); | ||
| } | ||
|
|
||
| /// A constituent whose stiffness lives in its OWN material, so its stress and | ||
| /// tangent come from two different names. | ||
| void add_decomposed(ctx_type& ctx, const std::string& name, T k, T g) { | ||
| param_type p; | ||
| p.insert<std::string>("name", name + "_K"); | ||
| p.insert<T>("value", k); | ||
| ctx.create<nm::constant_scalar<policy>>(p); | ||
| p.clear(); | ||
| p.insert<std::string>("name", name + "_G"); | ||
| p.insert<T>("value", g); | ||
| ctx.create<nm::constant_scalar<policy>>(p); | ||
| p.clear(); | ||
| p.insert<std::string>("name", name + "_stiff"); | ||
| p.insert<std::string>("K_source", name + "_K"); | ||
| p.insert<std::string>("G_source", name + "_G"); | ||
| ctx.create<nm::isotropic_tangent<policy>>(p); | ||
| p.clear(); | ||
| p.insert<std::string>("name", name); | ||
| p.insert<std::string>("tangent_source", name + "_stiff"); | ||
| p.insert<std::string>("strain_source", "strain_in"); | ||
| ctx.create<nm::linear_stress<policy>>(p); | ||
| } | ||
|
|
||
| nm::external_strain_source<policy>& add_strain(ctx_type& ctx) { | ||
| param_type p; | ||
| p.insert<std::string>("name", "strain_in"); | ||
| return ctx.create<nm::external_strain_source<policy>>(p); | ||
| } | ||
|
|
||
| tensor2 uniaxial(T v) { | ||
| tensor2 e; | ||
| e.fill(0.0); | ||
| e(0, 0) = v; | ||
| return e; | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Baseline: the mixture rule itself | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| /// Two monolithic constituents at weights 0.25 and 0.5. Both stress and tangent | ||
| /// must be the weighted sum. | ||
| TEST(WeightedSum, SumsStressAndTangentByWeight) { | ||
| ctx_type ctx; | ||
| auto& src = add_strain(ctx); | ||
| add_weight(ctx, "wA", 0.25); | ||
| add_weight(ctx, "wB", 0.5); | ||
| add_monolithic(ctx, "matA", KA, GA); | ||
| add_monolithic(ctx, "matB", KB, GB); | ||
|
|
||
| param_type p; | ||
| p.insert<std::string>("name", "mix"); | ||
| p.insert<terms_type>("terms", {{"wA", "matA"}, {"wB", "matB"}}); | ||
| ctx.create<nm::weighted_sum<policy>>(p); | ||
| ctx.finalize(); | ||
|
|
||
| src.bind(uniaxial(0.001), uniaxial(0.001)); | ||
| ctx.update(); | ||
|
|
||
| const T cA = KA + 4.0 * GA / 3.0; | ||
| const T cB = KB + 4.0 * GB / 3.0; | ||
| EXPECT_NEAR(ctx.get<tensor2>("mix", "stress")(0, 0), | ||
| (0.25 * cA + 0.5 * cB) * 0.001, 1e-10); | ||
| EXPECT_NEAR(ctx.get<tensor4>("mix", "tangent")(0, 0, 0, 0), | ||
| 0.25 * cA + 0.5 * cB, 1e-9); | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // tangent_sources | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| /// Absent: every term takes its tangent from the material producing its stress. | ||
| TEST(WeightedSum, AbsentTangentSourcesUsesEachTermsOwnMaterial) { | ||
| ctx_type ctx; | ||
| auto& src = add_strain(ctx); | ||
| add_weight(ctx, "wA", 1.0); | ||
| add_monolithic(ctx, "matA", KA, GA); | ||
|
|
||
| param_type p; | ||
| p.insert<std::string>("name", "mix"); | ||
| p.insert<terms_type>("terms", {{"wA", "matA"}}); | ||
| ctx.create<nm::weighted_sum<policy>>(p); | ||
| ctx.finalize(); | ||
|
|
||
| src.bind(uniaxial(0.001), uniaxial(0.001)); | ||
| ctx.update(); | ||
| EXPECT_NEAR(ctx.get<tensor4>("mix", "tangent")(0, 0, 0, 0), | ||
| KA + 4.0 * GA / 3.0, 1e-9); | ||
| } | ||
|
|
||
| /// What tangent_sources exists for: a constituent whose stress and tangent have | ||
| /// different owners. | ||
| TEST(WeightedSum, OverridesOneTermsTangentOwner) { | ||
| ctx_type ctx; | ||
| auto& src = add_strain(ctx); | ||
| add_weight(ctx, "wA", 1.0); | ||
| add_decomposed(ctx, "matA", KA, GA); | ||
|
|
||
| param_type p; | ||
| p.insert<std::string>("name", "mix"); | ||
| p.insert<terms_type>("terms", {{"wA", "matA"}}); | ||
| p.insert<std::vector<std::string>>("tangent_sources", {"matA_stiff"}); | ||
| ctx.create<nm::weighted_sum<policy>>(p); | ||
| ctx.finalize(); | ||
|
|
||
| src.bind(uniaxial(0.001), uniaxial(0.001)); | ||
| ctx.update(); | ||
| EXPECT_NEAR(ctx.get<tensor4>("mix", "tangent")(0, 0, 0, 0), | ||
| KA + 4.0 * GA / 3.0, 1e-9); | ||
| } | ||
|
|
||
| /// An empty entry keeps that term's own tangent, so a NON-LEADING term can be | ||
| /// overridden alone; without it a positional list could only override a prefix. | ||
| TEST(WeightedSum, EmptyEntryKeepsATermsOwnTangent) { | ||
| ctx_type ctx; | ||
| auto& src = add_strain(ctx); | ||
| add_weight(ctx, "wA", 0.5); | ||
| add_weight(ctx, "wB", 0.5); | ||
| add_monolithic(ctx, "matA", KA, GA); // keeps its own tangent | ||
| add_decomposed(ctx, "matB", KB, GB); // tangent lives elsewhere | ||
|
|
||
| param_type p; | ||
| p.insert<std::string>("name", "mix"); | ||
| p.insert<terms_type>("terms", {{"wA", "matA"}, {"wB", "matB"}}); | ||
| p.insert<std::vector<std::string>>("tangent_sources", {"", "matB_stiff"}); | ||
| ctx.create<nm::weighted_sum<policy>>(p); | ||
| ctx.finalize(); | ||
|
|
||
| src.bind(uniaxial(0.001), uniaxial(0.001)); | ||
| ctx.update(); | ||
|
|
||
| const T cA = KA + 4.0 * GA / 3.0; | ||
| const T cB = KB + 4.0 * GB / 3.0; | ||
| EXPECT_NEAR(ctx.get<tensor4>("mix", "tangent")(0, 0, 0, 0), | ||
| 0.5 * cA + 0.5 * cB, 1e-9); | ||
| } | ||
|
|
||
| /// A shorter list is rejected: positional matching would apply the override to | ||
| /// the WRONG constituent, and both names still resolve. The only symptom would | ||
| /// be a wrong summed tangent — slow Newton, correct stresses. | ||
| TEST(WeightedSum, RejectsATangentSourcesListThatDoesNotMatchTheTermCount) { | ||
| auto build = [](std::vector<std::string> sources) { | ||
| ctx_type ctx; | ||
| add_strain(ctx); | ||
| add_weight(ctx, "wA", 0.5); | ||
| add_weight(ctx, "wB", 0.5); | ||
| add_monolithic(ctx, "matA", KA, GA); | ||
| add_decomposed(ctx, "matB", KB, GB); | ||
| param_type p; | ||
| p.insert<std::string>("name", "mix"); | ||
| p.insert<terms_type>("terms", {{"wA", "matA"}, {"wB", "matB"}}); | ||
| p.insert<std::vector<std::string>>("tangent_sources", std::move(sources)); | ||
| ctx.create<nm::weighted_sum<policy>>(p); | ||
| }; | ||
|
|
||
| EXPECT_THROW(build({"matB_stiff"}), std::runtime_error); // too short | ||
| EXPECT_THROW(build({"", "matB_stiff", "extra"}), std::runtime_error); // long | ||
| EXPECT_NO_THROW(build({"", "matB_stiff"})); // exact | ||
| } | ||
|
|
||
| } // namespace |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Limitation worth stating in the doc comment rather than a defect.
The length check closes the case where a short list shifts every override onto the wrong constituent. It cannot close the case where a correct-length list names the wrong material — say
tangent_sources = {"", "matA_stiff"}when term 1 ismatB. Both names resolve,wire_inputs()succeeds, and the symptom is identical to the bug this check was added for: correct stresses, a wrong summed tangent, degraded Newton convergence and nothing in any log.That is inherent to decoupling stress from tangent — the whole point of the parameter — so no validation can catch it. But the class comment currently reads as though supplying one entry per term is sufficient for correctness, and it is only sufficient for alignment. One sentence saying the entry must name the material that produced that term's stiffness would earn its place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both done, no behaviour change.
The dead
update()is deleted, with a comment in its place saying why there isn't one — that the engine drives each output through itsadd_outputcallback, and thatbackward_euler/vector_newtononly useupdate()because they route it themselves. Better than silence: the absence is now deliberate rather than looking like an oversight.The class comment now states the limitation outright — one entry per term buys alignment, not correctness, and no validation can close the wrong-name case because decoupling stress from tangent is the point of the parameter.