From ad18f2a94e16234ed8ba00831b1ff9e9b523da43 Mon Sep 17 00:00:00 2001 From: Katie Mummah Date: Fri, 25 Oct 2024 13:37:44 -0600 Subject: [PATCH 1/5] support for binomial active/dormant in storage --- CHANGELOG.rst | 1 + src/storage.cc | 14 ++++++++++++++ src/storage.h | 34 +++++++++++++++++++++++++++------- src/storage_tests.cc | 34 ++++++++++++++++++++++++++++++---- 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a580f31c2..6bff22dd9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,7 @@ Since last release * Added package parameter to source (#613, #617, #621, #623, #630) * Added default keep packaging to reactor (#618, #619) * Added support for Ubuntu 24.04 (#633) +* Added (negative)binomial distributions for disruption modeling to storage (#635) **Changed:** diff --git a/src/storage.cc b/src/storage.cc index 6be703644..964d4a667 100644 --- a/src/storage.cc +++ b/src/storage.cc @@ -78,6 +78,13 @@ void Storage::InitBuyPolicyParameters() { active_dist_ = cyclus::NormalIntDist::Ptr (new cyclus::NormalIntDist(active_buying_mean, active_buying_stddev, active_buying_min, active_buying_max)); } + else if (active_buying_frequency_type == "Binomial") { + if (active_buying_end_probability < 0 || active_buying_end_probability > 1) { + throw cyclus::ValueError("Active buying end probability must be between 0 and 1"); + } + int success = 1; // only one success is needed to end the active buying period + active_dist_ = cyclus::NegativeBinomialIntDist::Ptr (new cyclus::NegativeBinomialIntDist(success, active_buying_end_probability)); + } else { throw cyclus::ValueError("Invalid active buying frequency type");} @@ -101,6 +108,13 @@ void Storage::InitBuyPolicyParameters() { dormant_dist_ = cyclus::NormalIntDist::Ptr (new cyclus::NormalIntDist(dormant_buying_mean, dormant_buying_stddev, dormant_buying_min, dormant_buying_max)); } + else if (dormant_buying_frequency_type == "Binomial") { + if (dormant_buying_end_probability < 0 || dormant_buying_end_probability > 1) { + throw cyclus::ValueError("Dormant buying end probability must be between 0 and 1"); + } + int success = 1; // only one success is needed to end the dormant buying period + dormant_dist_ = cyclus::NegativeBinomialIntDist::Ptr (new cyclus::NegativeBinomialIntDist(success, dormant_buying_end_probability)); + } else { throw cyclus::ValueError("Invalid dormant buying frequency type");} diff --git a/src/storage.h b/src/storage.h index 7bf539c9b..d9ba40f4a 100644 --- a/src/storage.h +++ b/src/storage.h @@ -234,12 +234,12 @@ class Storage #pragma cyclus var {"default": "Fixed",\ "tooltip": "Type of active buying frequency",\ - "doc": "Options: Fixed, Uniform, Normal. Fixed requires active_buying_val. Uniform "\ + "doc": "Options: Fixed, Uniform, Normal, Binomial. Fixed requires active_buying_val. Uniform "\ "requires active_buying_min and active_buying_max. Normal "\ "requires active_buying_mean and active_buying_std, with optional "\ - "active_buying_min and active_buying_max.",\ + "active_buying_min and active_buying_max. Binomial requires active_buying_end_probability.",\ "uitype": "combobox",\ - "categorical": ["Fixed", "Uniform", "Normal"],\ + "categorical": ["Fixed", "Uniform", "Normal", "Binomial"],\ "uilabel": "Active Buying Frequency Type"} std::string active_buying_frequency_type; @@ -290,14 +290,24 @@ class Storage "uilabel": "Active Buying Frequency Standard Deviation"} double active_buying_stddev; + #pragma cyclus var {"default": 0,\ + "tooltip": "Probability that agent will go offline during the next time step",\ + "doc": "Binomial distribution has a fixed probability of going dormant at any given "\ + "timestep, like a weighted coin flip. Required for Binomial active_buying_frequency_type. "\ + "Must be between 0 and 1",\ + "uitype": "range", \ + "range": [0.0, 1.0], \ + "uilabel": "Active Buying Offline Probability"} + double active_buying_end_probability; + #pragma cyclus var {"default": "Fixed",\ "tooltip": "Type of dormant buying frequency",\ - "doc": "Options: Fixed, Uniform, Normal. Fixed requires dormant_buying_val. Uniform "\ - "requires dormant_buying_min and dormant_buying_max. Normal requires "\ + "doc": "Options: Fixed, Uniform, Normal, Binomial. Fixed requires dormant_buying_val. "\ + "Uniform requires dormant_buying_min and dormant_buying_max. Normal requires "\ "dormant_buying_mean and dormant_buying_std, with optional dormant_buying_min "\ - "and dormant_buying_max.",\ + "and dormant_buying_max. Binomial requires dormant_buying_end_probability.",\ "uitype": "combobox",\ - "categorical": ["Fixed", "Uniform", "Normal"],\ + "categorical": ["Fixed", "Uniform", "Normal", "Binomial"],\ "uilabel": "Dormant Buying Frequency Type"} std::string dormant_buying_frequency_type; @@ -346,6 +356,16 @@ class Storage "uilabel": "Dormant Buying Frequency Standard Deviation"} double dormant_buying_stddev; + #pragma cyclus var {"default": 0,\ + "tooltip": "Probability that agent will return to active during the next time step",\ + "doc": "Binomial distribution has a fixed probability of going active at any given "\ + "timestep, like a weighted coin flip. Required for Binomial dormant_buying_frequency_type. "\ + "Must be between 0 and 1",\ + "uitype": "range", \ + "range": [0.0, 1.0], \ + "uilabel": "Dormant Buying Offline Probability"} + double dormant_buying_end_probability; + #pragma cyclus var {"default": "Fixed",\ "tooltip": "Type of behavior used to determine size of buy request",\ "doc": "Behavior function used to determine the size of requests made. All values are "\ diff --git a/src/storage_tests.cc b/src/storage_tests.cc index 8bd80238c..b6346b65d 100644 --- a/src/storage_tests.cc +++ b/src/storage_tests.cc @@ -551,6 +551,36 @@ TEST_F(StorageTest, UniformActiveNormalDormant){ EXPECT_EQ(9, qr.GetVal("Time", 4)); } +TEST_F(StorageTest, BinomialActiveDormant) { + std::string config = + " commod " + " commod1 " + " 1" + " Binomial" + " 0.2" + " Binomial" + " 0.3"; + + int simdur = 30; + + cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"), config, simdur); + sim.AddSource("commod").capacity(5).Finalize(); + + int id = sim.Run(); + + std::vector conds; + conds.push_back(cyclus::Cond("Commodity", "==", std::string("commod"))); + cyclus::QueryResult qr = sim.db().Query("Transactions", &conds); + // confirm that transactions are only occurring during active periods + // first active length = 7 + EXPECT_EQ(0, qr.GetVal("Time", 0)); + EXPECT_EQ(1, qr.GetVal("Time", 1)); + // ... end of active + EXPECT_EQ(6, qr.GetVal("Time", 6)); + // transactions resume at time 10 + EXPECT_EQ(10, qr.GetVal("Time", 7)); +} + TEST_F(StorageTest, FixedBuyingSize){ std::string config = " spent_fuel " @@ -1080,10 +1110,6 @@ TEST_F(StorageTest, TransportUnit) { EXPECT_EQ(2, qr_trans.GetVal("Time", 4)); EXPECT_EQ(2, qr_trans.GetVal("Time", 5)); - for (int i = 0; i < qr_trans.rows.size(); i++) { - std::cerr << "transaction " << i << "is at time " << qr_trans.GetVal("Time", i) << std::endl; - } - std::vector res_conds; res_conds.push_back(cyclus::Cond("PackageName", "==", p->name())); cyclus::QueryResult qr_res = sim.db().Query("Resources", &res_conds); From 9c3184f67df2e7c38413cb63087beeb9cdcefa8b Mon Sep 17 00:00:00 2001 From: Katie Mummah Date: Mon, 28 Oct 2024 20:43:47 -0600 Subject: [PATCH 2/5] add fixedwithdisruption using binary int dist --- src/storage.cc | 14 +++++++++++ src/storage.h | 58 ++++++++++++++++++++++++++++++++++++++------ src/storage_tests.cc | 36 +++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/storage.cc b/src/storage.cc index 964d4a667..42c141e5a 100644 --- a/src/storage.cc +++ b/src/storage.cc @@ -84,6 +84,13 @@ void Storage::InitBuyPolicyParameters() { } int success = 1; // only one success is needed to end the active buying period active_dist_ = cyclus::NegativeBinomialIntDist::Ptr (new cyclus::NegativeBinomialIntDist(success, active_buying_end_probability)); + } else if (active_buying_frequency_type == "FixedWithDisruption") { + if (active_buying_disruption < 0) { + throw cyclus::ValueError("Disruption must be greater than or equal to 0"); + } + active_dist_ = cyclus::BinaryIntDist::Ptr ( + new cyclus::BinaryIntDist(active_buying_disruption_probability, + active_buying_disruption, active_buying_val)); } else { throw cyclus::ValueError("Invalid active buying frequency type");} @@ -114,6 +121,13 @@ void Storage::InitBuyPolicyParameters() { } int success = 1; // only one success is needed to end the dormant buying period dormant_dist_ = cyclus::NegativeBinomialIntDist::Ptr (new cyclus::NegativeBinomialIntDist(success, dormant_buying_end_probability)); + } else if (dormant_buying_frequency_type == "FixedWithDisruption") { + if (dormant_buying_disruption < 0) { + throw cyclus::ValueError("Disruption must be greater than or equal to 0"); + } + dormant_dist_ = cyclus::BinaryIntDist::Ptr ( + new cyclus::BinaryIntDist(dormant_buying_disruption_probability, + dormant_buying_disruption, dormant_buying_val)); } else { throw cyclus::ValueError("Invalid dormant buying frequency type");} diff --git a/src/storage.h b/src/storage.h index d9ba40f4a..e66edac7e 100644 --- a/src/storage.h +++ b/src/storage.h @@ -234,12 +234,17 @@ class Storage #pragma cyclus var {"default": "Fixed",\ "tooltip": "Type of active buying frequency",\ - "doc": "Options: Fixed, Uniform, Normal, Binomial. Fixed requires active_buying_val. Uniform "\ + "doc": "Options: Fixed, Uniform, Normal, Binomial, FixedWithDisruption. "\ + "Fixed requires active_buying_val. Uniform "\ "requires active_buying_min and active_buying_max. Normal "\ "requires active_buying_mean and active_buying_std, with optional "\ - "active_buying_min and active_buying_max. Binomial requires active_buying_end_probability.",\ + "active_buying_min and active_buying_max. Binomial requires active_buying_end_probability."\ + "FixedWithDisruption has a probability that any given cycle will have a disrupted, "\ + "active length. Once per cycle, a Bernoulli distribution (Binomial dist "\ + "with N=1) will be sampled to determine if typical or disrupted cycle. If typical, "\ + "active_buying_val is cycle length. If disrupted, active_buying_disruption.",\ "uitype": "combobox",\ - "categorical": ["Fixed", "Uniform", "Normal", "Binomial"],\ + "categorical": ["Fixed", "Uniform", "Normal", "Binomial", "FixedWithDisruption"],\ "uilabel": "Active Buying Frequency Type"} std::string active_buying_frequency_type; @@ -300,14 +305,36 @@ class Storage "uilabel": "Active Buying Offline Probability"} double active_buying_end_probability; + #pragma cyclus var {"default": 0,\ + "tooltip": "Probability that a cycle contains a disruption",\ + "doc": "Probability that the agent undergoes a disruption (disrupted active period) "\ + "during any given cycle. Required for FixedWithDisruption active_buying_frequency_type.",\ + "uitype": "range",\ + "range": [0.0, 1.0],\ + "uilabel": "Active Buying Disruption Probability"} + double active_buying_disruption_probability; + + #pragma cyclus var {"default": -1,\ + "tooltip": "Fixed length of disrupted active cycle",\ + "doc": "When a active cycle is disrupted, this is length of the active period instead "\ + "of active_buying_val. Required for FixedWithDisruption active_buying_frequency_type",\ + "uitype": "range",\ + "range": [0, CY_LARGE_INT]} + int active_buying_disruption; + #pragma cyclus var {"default": "Fixed",\ "tooltip": "Type of dormant buying frequency",\ - "doc": "Options: Fixed, Uniform, Normal, Binomial. Fixed requires dormant_buying_val. "\ + "doc": "Options: Fixed, Uniform, Normal, Binomial, FixedWithDisruption. "\ + "Fixed requires dormant_buying_val. "\ "Uniform requires dormant_buying_min and dormant_buying_max. Normal requires "\ "dormant_buying_mean and dormant_buying_std, with optional dormant_buying_min "\ - "and dormant_buying_max. Binomial requires dormant_buying_end_probability.",\ + "and dormant_buying_max. Binomial requires dormant_buying_end_probability. "\ + "FixedWithDisruption has a probability that any given cycle will have a disrupted, "\ + "or long, outage. Once per cycle, a Bernoulli distribution (Binomial dist "\ + "with N=1) will be sampled to determine if typical or disrupted cycle. If typical, "\ + "dormant_buying_val is cycle length. If disrupted, dormant_buying_disruption.",\ "uitype": "combobox",\ - "categorical": ["Fixed", "Uniform", "Normal", "Binomial"],\ + "categorical": ["Fixed", "Uniform", "Normal", "Binomial", "FixedWithDisruption"],\ "uilabel": "Dormant Buying Frequency Type"} std::string dormant_buying_frequency_type; @@ -363,9 +390,26 @@ class Storage "Must be between 0 and 1",\ "uitype": "range", \ "range": [0.0, 1.0], \ - "uilabel": "Dormant Buying Offline Probability"} + "uilabel": "Dormant Buying Binomial Offline Probability"} double dormant_buying_end_probability; + #pragma cyclus var {"default": 0,\ + "tooltip": "Probability that a cycle contains a disruption",\ + "doc": "Probability that the agent undergoes a disruption (longer offline period) "\ + "during any given cycle. Required for FixedWithDisruption dormant_buying_frequency_type.",\ + "uitype": "range",\ + "range": [0.0, 1.0],\ + "uilabel": "Dormant Buying Disruption Probability"} + double dormant_buying_disruption_probability; + + #pragma cyclus var {"default": -1,\ + "tooltip": "Fixed length of disrupted cycle",\ + "doc": "When a dormant cycle is disrupted, this is length of the offline period instead "\ + "of dormant_buying_val. Required for FixedWithDisruption dormant_buying_frequency_type",\ + "uitype": "range",\ + "range": [0, CY_LARGE_INT]} + int dormant_buying_disruption; + #pragma cyclus var {"default": "Fixed",\ "tooltip": "Type of behavior used to determine size of buy request",\ "doc": "Behavior function used to determine the size of requests made. All values are "\ diff --git a/src/storage_tests.cc b/src/storage_tests.cc index b6346b65d..8c1771b86 100644 --- a/src/storage_tests.cc +++ b/src/storage_tests.cc @@ -581,6 +581,42 @@ TEST_F(StorageTest, BinomialActiveDormant) { EXPECT_EQ(10, qr.GetVal("Time", 7)); } +TEST_F(StorageTest, DisruptionActiveDormant) { + std::string config = + " commod" + " commod1" + " 1" + " FixedWithDisruption" + " 0.4" + " 2" + " 5" + " FixedWithDisruption" + " 0.5" + " 1" + " 10"; + + int simdur = 50; + + cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"), config, simdur); + sim.AddSource("commod").capacity(5).Finalize(); + int id = sim.Run(); + + cyclus::QueryResult qr = sim.db().Query("Transactions", NULL); + // confirm that transactions are only occurring during active periods + // first active length = 5 (disrupted) + EXPECT_EQ(0, qr.GetVal("Time", 0)); + EXPECT_EQ(1, qr.GetVal("Time", 1)); // ... end of active + + // first dormant length = 1 (not disrupted) + // second active length = 2 (not disrupted) + EXPECT_EQ(3, qr.GetVal("Time", 2)); // ... end of dormant + EXPECT_EQ(4, qr.GetVal("Time", 3)); + + // second dormant length = 10 (disrupted) + // third active length = 2 (not disrupted) + EXPECT_EQ(15, qr.GetVal("Time", 4)); // ... end of second active +} + TEST_F(StorageTest, FixedBuyingSize){ std::string config = " spent_fuel " From b9c1a1b780097587f7c9486fb11f72f466a8a64f Mon Sep 17 00:00:00 2001 From: Katie Mummah Date: Wed, 30 Oct 2024 16:24:07 -0600 Subject: [PATCH 3/5] add new params to optional parameters documentation --- src/storage.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/storage.h b/src/storage.h index e66edac7e..cd34587cc 100644 --- a/src/storage.h +++ b/src/storage.h @@ -46,6 +46,11 @@ namespace cycamore { /// Normal (optional) /// active_buying_mean is the mean length of the active buying period if active_buying_frequency_type is Normal /// active_buying_std is the standard deviation of the active buying period if active_buying_frequency_type is Normal +/// active_buying_end_probability is the probability that at any given timestep, the agent ends the active buying period if +/// the active buying frequency type is Binomial +/// active_buying_disruption_probability is the probability that in any given cycle, the agent undergoes a disruption (disrupted +/// active period) if the active buying frequency type is FixedWithDisruption +/// active_buying_disruption is the length of the disrupted active cycle if the active buying frequency type is FixedWithDisruption /// dormant_buying_frequency_type is the type of distribution used to determine the length of the dormant buying period /// dormant_buying_val is the length of the dormant buying period if dormant_buying_frequency_type is Fixed /// dormant_buying_min is the minimum length of the dormant buying period if dormant_buying_frequency_type is Uniform (required) or @@ -54,6 +59,10 @@ namespace cycamore { /// Normal (optional) /// dormant_buying_mean is the mean length of the dormant buying period if dormant_buying_frequency_type is Normal /// dormant_buying_std is the standard deviation of the dormant buying period if dormant_buying_frequency_type is Normal +/// dormant_buying_end_probability is the probability that at any given timestep, the agent ends the dormant buying period if +/// the dormant buying frequency type is Binomial +/// dormant_buying_disruption_probability is the probability that in any given cycle, the agent undergoes a disruption (disrupted +/// offline period) if the dormant buying frequency type is FixedWithDisruption /// buying_size_type is the type of distribution used to determine the size of buy requests, as a fraction of the current capacity /// buying_size_val is the size of the buy request for Fixed buying_size_type /// buying_size_min is the minimum size of the buy request if buying_size_type is Uniform (required) or Normal (optional) From 081eb7d332c20c7b69cb1d00002cc406483e1ae4 Mon Sep 17 00:00:00 2001 From: Katie Mummah Date: Wed, 30 Oct 2024 20:25:05 -0600 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Paul Wilson --- src/storage.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/storage.h b/src/storage.h index cd34587cc..7fc732464 100644 --- a/src/storage.h +++ b/src/storage.h @@ -46,11 +46,12 @@ namespace cycamore { /// Normal (optional) /// active_buying_mean is the mean length of the active buying period if active_buying_frequency_type is Normal /// active_buying_std is the standard deviation of the active buying period if active_buying_frequency_type is Normal -/// active_buying_end_probability is the probability that at any given timestep, the agent ends the active buying period if -/// the active buying frequency type is Binomial -/// active_buying_disruption_probability is the probability that in any given cycle, the agent undergoes a disruption (disrupted -/// active period) if the active buying frequency type is FixedWithDisruption -/// active_buying_disruption is the length of the disrupted active cycle if the active buying frequency type is FixedWithDisruption +/// active_buying_end_probability is the probability that at any given timestep, the agent ends the active buying +/// period if the active buying frequency type is Binomial +/// active_buying_disruption_probability is the probability that in any given cycle, the agent undergoes a disruption +/// (disrupted active period) if the active buying frequency type is FixedWithDisruption +/// active_buying_disruption is the length of the disrupted active cycle if the active buying frequency type is +/// FixedWithDisruption /// dormant_buying_frequency_type is the type of distribution used to determine the length of the dormant buying period /// dormant_buying_val is the length of the dormant buying period if dormant_buying_frequency_type is Fixed /// dormant_buying_min is the minimum length of the dormant buying period if dormant_buying_frequency_type is Uniform (required) or From dfd4e23d1b3bed6031b2f01ac9c3096c2b5ef110 Mon Sep 17 00:00:00 2001 From: Katie Mummah Date: Wed, 30 Oct 2024 20:28:26 -0600 Subject: [PATCH 5/5] add dormant_buying_disruption to optional params --- src/storage.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storage.h b/src/storage.h index 7fc732464..4f34f962a 100644 --- a/src/storage.h +++ b/src/storage.h @@ -61,9 +61,11 @@ namespace cycamore { /// dormant_buying_mean is the mean length of the dormant buying period if dormant_buying_frequency_type is Normal /// dormant_buying_std is the standard deviation of the dormant buying period if dormant_buying_frequency_type is Normal /// dormant_buying_end_probability is the probability that at any given timestep, the agent ends the dormant buying period if -/// the dormant buying frequency type is Binomial +/// the dormant buying frequency type is Binomial /// dormant_buying_disruption_probability is the probability that in any given cycle, the agent undergoes a disruption (disrupted -/// offline period) if the dormant buying frequency type is FixedWithDisruption +/// offline period) if the dormant buying frequency type is FixedWithDisruption +/// dormant_buying_disruption is the length of the disrupted dormant cycle if the dormant buying frequency type is +/// FixedWithDisruption /// buying_size_type is the type of distribution used to determine the size of buy requests, as a fraction of the current capacity /// buying_size_val is the size of the buy request for Fixed buying_size_type /// buying_size_min is the minimum size of the buy request if buying_size_type is Uniform (required) or Normal (optional)