Skip to content
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

support for binomial active/dormant in storage #635

Merged
merged 5 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading