diff --git a/src/random_number_generator.cc b/src/random_number_generator.cc index 30e5f192e8..618225f40f 100644 --- a/src/random_number_generator.cc +++ b/src/random_number_generator.cc @@ -68,19 +68,27 @@ namespace cyclus{ return UniformDoubleDist::dist(RandomNumberGenerator::gen_); } + double UniformDoubleDist::max() { + return UniformDoubleDist::dist.max(); + } + NormalDoubleDist::NormalDoubleDist(double mean, double std_dev, double min, double max) : dist(mean, std_dev) { - NormalDoubleDist::min = min; - NormalDoubleDist::max = max; + NormalDoubleDist::min_ = min; + NormalDoubleDist::max_ = max; } double NormalDoubleDist::sample() { double val = NormalDoubleDist::dist(RandomNumberGenerator::gen_); - while (val < NormalDoubleDist::min || val > NormalDoubleDist::max){ + while (val < NormalDoubleDist::min_ || val > NormalDoubleDist::max_){ val = NormalDoubleDist::dist(RandomNumberGenerator::gen_); } return val; } + double NormalDoubleDist::max() { + return NormalDoubleDist::dist.max(); + } + UniformIntDist::UniformIntDist(int min, int max) : dist(min, max) { } int UniformIntDist::sample() { @@ -88,16 +96,15 @@ namespace cyclus{ } NormalIntDist::NormalIntDist(double mean, double std_dev, int min, int max) : dist(mean, std_dev) { - NormalIntDist::min = std::min(min, 0); - NormalIntDist::max = max; + NormalIntDist::min_ = std::min(min, 0); + NormalIntDist::max_ = max; } int NormalIntDist::sample() { double val = NormalIntDist::dist(RandomNumberGenerator::gen_); - while (val < NormalIntDist::min || val > NormalIntDist::max){ + while (val < NormalIntDist::min_ || val > NormalIntDist::max_){ val = NormalIntDist::dist(RandomNumberGenerator::gen_); } return std::lrint(val); } - } \ No newline at end of file diff --git a/src/random_number_generator.h b/src/random_number_generator.h index 6958221688..95bd8c7d73 100644 --- a/src/random_number_generator.h +++ b/src/random_number_generator.h @@ -87,6 +87,7 @@ class RandomNumberGenerator { class DoubleDistribution { public: virtual double sample() = 0; + virtual double max() = 0; }; class FixedDoubleDist : public DoubleDistribution { @@ -95,6 +96,7 @@ class FixedDoubleDist : public DoubleDistribution { public: FixedDoubleDist(double value_) : value(value_) {}; virtual double sample() { return value; }; + virtual double max() { return value; }; }; class UniformDoubleDist : public DoubleDistribution { @@ -103,16 +105,18 @@ class UniformDoubleDist : public DoubleDistribution { public: UniformDoubleDist(double min = 0, double max=1); virtual double sample(); + virtual double max(); }; class NormalDoubleDist : public DoubleDistribution { private: boost::random::normal_distribution<> dist; - double min; - double max; + double min_; + double max_; public: NormalDoubleDist(double mean, double std_dev, double min=0, double max=std::numeric_limits::max()); virtual double sample(); + virtual double max(); }; class IntDistribution { @@ -139,8 +143,8 @@ class UniformIntDist : public IntDistribution { class NormalIntDist : public IntDistribution { private: boost::random::normal_distribution<> dist; - int min; - int max; + int min_; + int max_; public: NormalIntDist(double mean, double std_dev, int min=0, int max=std::numeric_limits::max()); virtual int sample(); diff --git a/src/toolkit/matl_buy_policy.cc b/src/toolkit/matl_buy_policy.cc index 5a4fbe6d70..584a2bbecd 100644 --- a/src/toolkit/matl_buy_policy.cc +++ b/src/toolkit/matl_buy_policy.cc @@ -169,6 +169,7 @@ std::set::Ptr> MatlBuyPolicy::GetMatlRequests() { if (current_time_ < next_active_end_ || next_dormant_end_ < 0) { // currently in the middle of active buying period + SetRequestSize(); amt = TotalQty(); } else if (current_time_ < next_dormant_end_) { @@ -180,12 +181,12 @@ std::set::Ptr> MatlBuyPolicy::GetMatlRequests() { // finished active. starting dormancy and sample/set length of dormant period amt = 0; SetNextDormantTime(); - } // the following is an if rather than if-else statement because if dormant // length is zero, buy policy should return to active immediately if (current_time_ == next_dormant_end_) { // finished dormant. starting buying and sample/set length of active period + SetRequestSize(); amt = TotalQty(); SetNextActiveTime(); } @@ -194,8 +195,8 @@ std::set::Ptr> MatlBuyPolicy::GetMatlRequests() { return ports; bool excl = Excl(); - double req_amt = ReqQty(); - int n_req = NReq(); + double req_amt = Excl() ? quantize_ : amt; + int n_req = Excl() ? static_cast(amt / quantize_) : 1; LGH(INFO3) << "requesting " << amt << " kg via " << n_req << " request(s)" << std::endl; // one portfolio for each request @@ -243,5 +244,14 @@ void MatlBuyPolicy::SetNextDormantTime() { return; } +void MatlBuyPolicy::SetRequestSize() { + sample_fraction_ = size_dist_->sample(); + if (sample_fraction_ > 1) { + sample_fraction_ = sample_fraction_ / size_dist_->max(); + } + return; +} + + } // namespace toolkit } // namespace cyclus diff --git a/src/toolkit/matl_buy_policy.h b/src/toolkit/matl_buy_policy.h index 039ea41f01..62928c394e 100644 --- a/src/toolkit/matl_buy_policy.h +++ b/src/toolkit/matl_buy_policy.h @@ -141,15 +141,18 @@ class MatlBuyPolicy : public Trader { /// is idempotent. void Stop(); + double sample_fraction_ = 1.0; + /// the total amount requested inline double TotalQty() const { - return std::min(throughput_, - fill_to_ * buf_->capacity() - buf_->quantity()); + return std::min((throughput_* sample_fraction_), + ((fill_to_ * buf_->capacity()) - buf_->quantity()) * sample_fraction_); } /// whether trades will be denoted as exclusive or not inline bool Excl() const { return quantize_ > 0; } + /// the amount requested per each request inline double ReqQty() const { return Excl() ? quantize_ : TotalQty(); @@ -172,10 +175,11 @@ class MatlBuyPolicy : public Trader { virtual std::set::Ptr> GetMatlRequests(); virtual void AcceptMatlTrades( const std::vector, Material::Ptr> >& resps); + /// }@ void SetNextActiveTime(); void SetNextDormantTime(); - /// }@ + void SetRequestSize(); private: struct CommodDetail { diff --git a/tests/toolkit/matl_buy_policy_tests.cc b/tests/toolkit/matl_buy_policy_tests.cc index 68f3b22028..15c6cd0318 100644 --- a/tests/toolkit/matl_buy_policy_tests.cc +++ b/tests/toolkit/matl_buy_policy_tests.cc @@ -405,5 +405,105 @@ TEST_F(MatlBuyPolicyTests, MixedActiveDormant) { delete a; } +TEST_F(MatlBuyPolicyTests, RandomSizeUniform) { + using cyclus::QueryResult; + + FixedIntDist a_dist = FixedIntDist(1); + FixedIntDist d_dist = FixedIntDist(-1); + UniformDoubleDist size_dist = UniformDoubleDist(0.5, 1.0); + + int dur = 2; + double throughput = 10; + + cyclus::MockSim sim(dur); + cyclus::Agent* a = new TestFacility(sim.context()); + sim.context()->AddPrototype(a->prototype(), a); + sim.agent = sim.context()->CreateAgent(a->prototype()); + sim.AddSource("commod1").Finalize(); + + TestFacility* fac = dynamic_cast(sim.agent); + + cyclus::toolkit::ResBuf inbuf; + cyclus::toolkit::MatlBuyPolicy policy; + policy.Init(fac, &inbuf, "inbuf", throughput, &a_dist, &d_dist, &size_dist) + .Set("commod1").Start(); + + EXPECT_NO_THROW(sim.Run()); + + QueryResult qr = sim.db().Query("Resources", NULL); + EXPECT_NEAR(6.59845, qr.GetVal("Quantity", 0), 0.00001); + EXPECT_NEAR(9.70636, qr.GetVal("Quantity", 1), 0.00001); + + delete a; +} + +TEST_F(MatlBuyPolicyTests, RandomSizeNormal) { + using cyclus::QueryResult; + + FixedIntDist a_dist = FixedIntDist(1); + FixedIntDist d_dist = FixedIntDist(-1); + NormalDoubleDist size_dist = NormalDoubleDist(0.5, 0.1); + + int dur = 2; + double throughput = 10; + + cyclus::MockSim sim(dur); + cyclus::Agent* a = new TestFacility(sim.context()); + sim.context()->AddPrototype(a->prototype(), a); + sim.agent = sim.context()->CreateAgent(a->prototype()); + sim.AddSource("commod1").Finalize(); + + TestFacility* fac = dynamic_cast(sim.agent); + + cyclus::toolkit::ResBuf inbuf; + cyclus::toolkit::MatlBuyPolicy policy; + policy.Init(fac, &inbuf, "inbuf", throughput, &a_dist, &d_dist, &size_dist) + .Set("commod1").Start(); + + EXPECT_NO_THROW(sim.Run()); + + QueryResult qr = sim.db().Query("Resources", NULL); + EXPECT_NEAR(6.40838, qr.GetVal("Quantity", 0), 0.00001); + EXPECT_NEAR(3.26489, qr.GetVal("Quantity", 1), 0.00001); + + delete a; +} + +TEST_F(MatlBuyPolicyTests, RandomSizeAndFrequency) { + using cyclus::QueryResult; + + UniformIntDist a_dist = UniformIntDist(1, 2); + UniformIntDist d_dist = UniformIntDist(1, 2); + NormalDoubleDist size_dist = NormalDoubleDist(0.5, 0.25); + + int dur = 8; + double throughput = 10; + + cyclus::MockSim sim(dur); + cyclus::Agent* a = new TestFacility(sim.context()); + sim.context()->AddPrototype(a->prototype(), a); + sim.agent = sim.context()->CreateAgent(a->prototype()); + sim.AddSource("commod1").Finalize(); + + TestFacility* fac = dynamic_cast(sim.agent); + + cyclus::toolkit::ResBuf inbuf; + cyclus::toolkit::MatlBuyPolicy policy; + policy.Init(fac, &inbuf, "inbuf", throughput, &a_dist, &d_dist, &size_dist) + .Set("commod1").Start(); + + EXPECT_NO_THROW(sim.Run()); + + QueryResult qr = sim.db().Query("Resources", NULL); + EXPECT_NEAR(0.66224, qr.GetVal("Quantity", 0), 0.00001); + EXPECT_NEAR(4.02323, qr.GetVal("Quantity", 1), 0.00001); + + QueryResult qr2 = sim.db().Query("Transactions", NULL); + EXPECT_EQ(0, qr2.GetVal("Time", 0)); + EXPECT_EQ(4, qr2.GetVal("Time", 2)); + + delete a; +} + } }