diff --git a/src/material.cc b/src/material.cc index 74405274da..601addf35a 100644 --- a/src/material.cc +++ b/src/material.cc @@ -106,8 +106,8 @@ void Material::Absorb(Material::Ptr mat) { // force both mateiral objects to advance to the same decay time int common_decay_time = std::max(this->prev_decay_time_, mat->prev_decay_time_); - if (ctx_ != NULL && ctx_->sim_info().decay != "never") { - common_decay_time = ctx_->time(); + if (HasContext() && mat->HasContext() && ctx_->sim_info().decay != "never") { + common_decay_time = std::max(ctx_->time(), common_decay_time); } mat->Decay(common_decay_time); this->Decay(common_decay_time); @@ -128,7 +128,11 @@ void Material::Absorb(Material::Ptr mat) { comp_ = Composition::CreateFromMass(compmath::Add(v, otherv)); } - qty_ += mat->qty_; + double tot_mass = qty_ + mat->quantity(); + double avg_unit_value = + (qty_ * UnitValue() + mat->quantity() * mat->UnitValue()) / tot_mass; + SetUnitValue(avg_unit_value); + qty_ = tot_mass; mat->qty_ = 0; tracker_.Absorb(&mat->tracker_); } @@ -204,7 +208,8 @@ void Material::Decay(int curr_time) { curr_time = ctx_->time(); } - int dt = curr_time - prev_decay_time_; + // Block backwards decay with std::max + int dt = std::max(curr_time - prev_decay_time_, 0); if (dt == 0) { return; } @@ -242,7 +247,8 @@ void Material::Decay(int curr_time) { } } - prev_decay_time_ = curr_time; // this must go before Transmute call + // Need to set prev_decay_time before Transmute. Block setting it backwards. + prev_decay_time_ = std::max(curr_time, prev_decay_time_); Composition::Ptr decayed = comp_->Decay(dt, secs_per_timestep); Transmute(decayed); } diff --git a/src/material.h b/src/material.h index 9ed29950b4..2e7635069a 100644 --- a/src/material.h +++ b/src/material.h @@ -108,6 +108,9 @@ class Material : public Resource { /// Returns the mass of this material in kg. virtual double quantity() const; + /// Returns true if the material has a context, false otherwise. + virtual bool HasContext() const {return ctx_ != NULL;} + virtual Resource::Ptr ExtractRes(double qty); /// Same as ExtractComp with c = this->comp(). diff --git a/tests/material_tests.cc b/tests/material_tests.cc index a0566102f8..341c5c0e63 100644 --- a/tests/material_tests.cc +++ b/tests/material_tests.cc @@ -134,6 +134,38 @@ TEST_F(MaterialTest, AbsorbIntoZeroMaterial) { EXPECT_FLOAT_EQ(test_size_, same_as_test_mat->quantity()); } +TEST_F(MaterialTest, AbsorbMatlWithoutContext) { + Material::Ptr no_ctx_mat = Material::CreateUntracked(0, test_comp_); + EXPECT_FALSE(no_ctx_mat->HasContext()); + EXPECT_NO_THROW(test_mat_->Absorb(no_ctx_mat)); +} + +TEST_F(MaterialTest, BackwardsDecay) { + FakeContext* fake_ctx = new FakeContext(&ti, &rec); + TestFacility* fake_fac = new TestFacility(fake_ctx); + + Material::Ptr m1 = Material::Create(fake_fac, 1, diff_comp_); + Material::Ptr m2 = Material::Create(fake_fac, 1, diff_comp_); + + // Set context time to 10 to match the decay time + fake_ctx->time(10); + + m2->Decay(); // decay m2 to time 10 + EXPECT_EQ(0, m1->prev_decay_time()); + EXPECT_EQ(10, m2->prev_decay_time()); + + fake_ctx->time(9); + + // After manually setting the ctx time backwards, common_decay_time is 10, + // and ctx->time() is 9, meaning decay will set dt = 0 with std::max, and + // prev_decay_time for the combined mat should remain at 10. + m1->Absorb(m2); + EXPECT_EQ(10, m1->prev_decay_time()); + + delete fake_fac; + delete fake_ctx; +} + TEST_F(MaterialTest, ExtractMass) { double amt = test_size_ / 3; double diff = test_size_ - amt; @@ -408,23 +440,34 @@ TEST_F(MaterialTest, TransmutePrevDecay) { // as coded. We may decide to change the behavior in the future breaking // this test; the test will need to be modified accordingly. // -// This test checks to see that, when materials are absorbed together, the -// previous decay time for the larger quantity material is used as the value -// for the new, combined material. +// This test checks to see that, when materials are absorbed together, both +// materials are decayed prior to the absorption. + TEST_F(MaterialTest, AbsorbPrevDecay) { - Material::Ptr m1 = Material::Create(fac, 1, diff_comp_); - Material::Ptr m2 = Material::Create(fac, 1, diff_comp_); - Material::Ptr m3 = Material::Create(fac, 1000, diff_comp_); - m3->Decay(10); + FakeContext* fake_ctx = new FakeContext(&ti, &rec); + TestFacility* fake_fac = new TestFacility(fake_ctx); + + Material::Ptr m1 = Material::Create(fake_fac, 1, diff_comp_); + Material::Ptr m2 = Material::Create(fake_fac, 1, diff_comp_); + Material::Ptr m3 = Material::Create(fake_fac, 1000, diff_comp_); + // Set context time to 10 to match the decay time + fake_ctx->time(10); + + m3->Decay(); // decay m3 to time 10 EXPECT_EQ(0, m1->prev_decay_time()); EXPECT_EQ(0, m2->prev_decay_time()); EXPECT_EQ(10, m3->prev_decay_time()); + fake_ctx->time(11); + m1->Absorb(m3); - EXPECT_EQ(10, m1->prev_decay_time()); + EXPECT_EQ(11, m1->prev_decay_time()); m1->Absorb(m2); - EXPECT_EQ(10, m1->prev_decay_time()); + EXPECT_EQ(11, m1->prev_decay_time()); + + delete fake_fac; + delete fake_ctx; } TEST_F(MaterialTest, DecayHeatTest) { diff --git a/tests/material_tests.h b/tests/material_tests.h index a562f21b3d..e49b4c35f5 100644 --- a/tests/material_tests.h +++ b/tests/material_tests.h @@ -11,6 +11,7 @@ #include "test_agents/test_facility.h" #include "recorder.h" #include "timer.h" +#include "test_context.h" namespace cyclus {