Skip to content

Commit

Permalink
Merge pull request #635 from nuclearkatie/storage_random_behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
gonuke authored Oct 31, 2024
2 parents f0cfd77 + dfd4e23 commit ce67519
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:**

Expand Down
28 changes: 28 additions & 0 deletions src/storage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ 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 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");}

Expand All @@ -101,6 +115,20 @@ 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 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");}

Expand Down
90 changes: 83 additions & 7 deletions src/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +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
/// 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
Expand All @@ -54,6 +60,12 @@ 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
/// 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)
Expand Down Expand Up @@ -234,12 +246,17 @@ 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, 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.",\
"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"],\
"categorical": ["Fixed", "Uniform", "Normal", "Binomial", "FixedWithDisruption"],\
"uilabel": "Active Buying Frequency Type"}
std::string active_buying_frequency_type;

Expand Down Expand Up @@ -290,14 +307,46 @@ 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": 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. Fixed requires dormant_buying_val. Uniform "\
"requires dormant_buying_min and dormant_buying_max. Normal requires "\
"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.",\
"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"],\
"categorical": ["Fixed", "Uniform", "Normal", "Binomial", "FixedWithDisruption"],\
"uilabel": "Dormant Buying Frequency Type"}
std::string dormant_buying_frequency_type;

Expand Down Expand Up @@ -346,6 +395,33 @@ 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 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 "\
Expand Down
70 changes: 66 additions & 4 deletions src/storage_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,72 @@ TEST_F(StorageTest, UniformActiveNormalDormant){
EXPECT_EQ(9, qr.GetVal<int>("Time", 4));
}

TEST_F(StorageTest, BinomialActiveDormant) {
std::string config =
" <in_commods> <val>commod</val> </in_commods> "
" <out_commods> <val>commod1</val> </out_commods> "
" <throughput>1</throughput>"
" <active_buying_frequency_type>Binomial</active_buying_frequency_type>"
" <active_buying_end_probability>0.2</active_buying_end_probability>"
" <dormant_buying_frequency_type>Binomial</dormant_buying_frequency_type>"
" <dormant_buying_end_probability>0.3</dormant_buying_end_probability>";

int simdur = 30;

cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"), config, simdur);
sim.AddSource("commod").capacity(5).Finalize();

int id = sim.Run();

std::vector<cyclus::Cond> 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<int>("Time", 0));
EXPECT_EQ(1, qr.GetVal<int>("Time", 1));
// ... end of active
EXPECT_EQ(6, qr.GetVal<int>("Time", 6));
// transactions resume at time 10
EXPECT_EQ(10, qr.GetVal<int>("Time", 7));
}

TEST_F(StorageTest, DisruptionActiveDormant) {
std::string config =
" <in_commods><val>commod</val></in_commods>"
" <out_commods><val>commod1</val></out_commods>"
" <throughput>1</throughput>"
" <active_buying_frequency_type>FixedWithDisruption</active_buying_frequency_type>"
" <active_buying_disruption_probability>0.4</active_buying_disruption_probability>"
" <active_buying_val>2</active_buying_val>"
" <active_buying_disruption>5</active_buying_disruption>"
" <dormant_buying_frequency_type>FixedWithDisruption</dormant_buying_frequency_type>"
" <dormant_buying_disruption_probability>0.5</dormant_buying_disruption_probability>"
" <dormant_buying_val>1</dormant_buying_val>"
" <dormant_buying_disruption>10</dormant_buying_disruption>";

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<int>("Time", 0));
EXPECT_EQ(1, qr.GetVal<int>("Time", 1)); // ... end of active

// first dormant length = 1 (not disrupted)
// second active length = 2 (not disrupted)
EXPECT_EQ(3, qr.GetVal<int>("Time", 2)); // ... end of dormant
EXPECT_EQ(4, qr.GetVal<int>("Time", 3));

// second dormant length = 10 (disrupted)
// third active length = 2 (not disrupted)
EXPECT_EQ(15, qr.GetVal<int>("Time", 4)); // ... end of second active
}

TEST_F(StorageTest, FixedBuyingSize){
std::string config =
" <in_commods> <val>spent_fuel</val> </in_commods> "
Expand Down Expand Up @@ -1080,10 +1146,6 @@ TEST_F(StorageTest, TransportUnit) {
EXPECT_EQ(2, qr_trans.GetVal<int>("Time", 4));
EXPECT_EQ(2, qr_trans.GetVal<int>("Time", 5));

for (int i = 0; i < qr_trans.rows.size(); i++) {
std::cerr << "transaction " << i << "is at time " << qr_trans.GetVal<int>("Time", i) << std::endl;
}

std::vector<cyclus::Cond> res_conds;
res_conds.push_back(cyclus::Cond("PackageName", "==", p->name()));
cyclus::QueryResult qr_res = sim.db().Query("Resources", &res_conds);
Expand Down

0 comments on commit ce67519

Please sign in to comment.