Skip to content

Commit

Permalink
Merge pull request #574 from nuclearkatie/R_Q_inventory
Browse files Browse the repository at this point in the history
  • Loading branch information
gonuke authored Feb 7, 2024
2 parents 2fe80d8 + 6381dfd commit 622db4c
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ cycamore Change Log
* GitHub workflows for building/testing on a PR and push to `main` (#549, #564)
* Add functionality for random behavior on the size (#550) and frequency (#565) of a sink
* GitHub workflow to check that the CHANGELOG has been updated (#562)
* Added inventory policies to Storage through the material buy policy (#574)

**Changed:**

Expand Down
32 changes: 23 additions & 9 deletions src/storage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Storage::Storage(cyclus::Context* ctx)
latitude(0.0),
longitude(0.0),
coordinates(latitude, longitude) {
inventory_tracker.Init({&inventory, &stocks, &ready, &processing}, 1e299);
cyclus::Warn<cyclus::EXPERIMENTAL_WARNING>(
"The Storage Facility is experimental.");};

Expand Down Expand Up @@ -130,11 +131,28 @@ void Storage::InitBuyPolicyParameters() {
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Storage::EnterNotify() {
cyclus::Facility::EnterNotify();

InitBuyPolicyParameters();

buy_policy.Init(this, &inventory, std::string("inventory"), throughput,
active_dist_, dormant_dist_, size_dist_);

inventory_tracker.set_capacity(max_inv_size);
if (reorder_point < 0) {
InitBuyPolicyParameters();
buy_policy.Init(this, &inventory, std::string("inventory"),
&inventory_tracker, throughput, active_dist_,
dormant_dist_, size_dist_);
}
else if (reorder_quantity > 0) {
if (reorder_point + reorder_quantity > max_inv_size) {
throw cyclus::ValueError(
"reorder_point + reorder_quantity must be less than or equal to max_inv_size");
}
buy_policy.Init(this, &inventory, std::string("inventory"),
&inventory_tracker, throughput, "RQ",
reorder_quantity, reorder_point);
}
else {
buy_policy.Init(this, &inventory, std::string("inventory"),
&inventory_tracker, throughput, "sS",
max_inv_size, reorder_point);
}

// dummy comp, use in_recipe if provided
cyclus::CompMap v;
Expand Down Expand Up @@ -208,10 +226,6 @@ void Storage::Tick() {

LOG(cyclus::LEV_INFO4, "ComCnv") << "current capacity " << max_inv_size << " - " << processing.quantity() << " - " << ready.quantity() << " - " << stocks.quantity() << " = " << current_capacity();

// Set available capacity for Buy Policy
inventory.capacity(current_capacity());


if (current_capacity() > cyclus::eps_rsrc()) {
LOG(cyclus::LEV_INFO4, "ComCnv")
<< " has capacity for " << current_capacity() << ".";
Expand Down
56 changes: 51 additions & 5 deletions src/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,11 @@ class Storage
/* --- Storage Members --- */

/// @brief current maximum amount that can be added to processing
inline double current_capacity() const {
return (max_inv_size - processing.quantity() - stocks.quantity()
- ready.quantity()); }
inline double current_capacity() {
return (inventory_tracker.space()); }

/// @brief returns total capacity
inline double capacity() { return inventory_tracker.capacity(); }

/// @brief returns the time key for ready materials
int ready_time(){ return context()->time() - residence_time; }
Expand Down Expand Up @@ -296,10 +298,10 @@ class Storage
"uilabel": "Dormant Buying Frequency Type"}
std::string dormant_buying_frequency_type;

#pragma cyclus var {"default": 0,\
#pragma cyclus var {"default": -1,\
"tooltip": "Fixed dormant buying frequency",\
"doc": "The length in time steps of the dormant buying period. Required for fixed "\
"dormant_buying_frequency_type. Can be zero and agent will only be active (default behavior)",\
"dormant_buying_frequency_type. Default is -1, agent has no dormant period and stays active.",\
"uitype": "range", \
"range": [-1, 1e299], \
"uilabel": "Dormant Buying Frequency Value"}
Expand Down Expand Up @@ -401,6 +403,47 @@ class Storage
"uilabel": "Buying Size Standard Deviation"}
double buying_size_stddev;

#pragma cyclus var {"default": -1,\
"tooltip":"Reorder point",\
"doc":"The point at which the facility will request more material. "\
"Above this point, no request will be made. Must be less than max_inv_size."\
"If paired with reorder_quantity, this agent will have an (R,Q) inventory policy. "\
"If reorder_point is used alone, this agent will have an (s,S) inventory policy, "\
" with S (the maximum) being set at max_inv_size.",\
"uilabel":"Reorder Point"}
double reorder_point;

#pragma cyclus var {"default": -1,\
"tooltip":"Reorder amount (R,Q inventory policy)",\
"doc":"The amount of material that will be requested when the reorder point is reached. "\
"Exclusive request, so will demand exactly reorder_quantity."\
"Reorder_point + reorder_quantity must be less than max_inv_size.",\
"uilabel":"Reorder Quantity"}
double reorder_quantity;

#pragma cyclus var {"default": 1,\
"tooltip": "Length of the active buying "\
"period",\
"doc":"During the length of the active buying "\
"period, agent exhibits regular behavior. "\
"If paired with dormant buying period, "\
"alternates between buying and not buying, "\
"regardless if space is available",\
"uilabel":"Active Buying Period"}
int active_buying;

#pragma cyclus var {"default": 0,\
"tooltip": "Length of the dormant buying "\
"period",\
"doc":"During the length of the dormant buying "\
"period, agent will not request any new "\
"material from the DRE. Paired with active "\
"buying period, alternates between buying "\
"and not buying, regardless if space is "\
"available",\
"uilabel":"Dormant (No Buying) Period"}
int dormant_buying;

#pragma cyclus var {"tooltip":"Incoming material buffer"}
cyclus::toolkit::ResBuf<cyclus::Material> inventory;

Expand All @@ -418,6 +461,9 @@ class Storage
#pragma cyclus var {"tooltip":"Buffer for material still waiting for required residence_time"}
cyclus::toolkit::ResBuf<cyclus::Material> processing;

#pragma cyclus var {"tooltip": "Total Inventory Tracker to restrict maximum agent inventory"}
cyclus::toolkit::TotalInvTracker inventory_tracker;

//// A policy for requesting material
cyclus::toolkit::MatlBuyPolicy buy_policy;

Expand Down
85 changes: 83 additions & 2 deletions src/storage_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void StorageTest::SetUpStorage(){
src_facility_->out_commods = out_c1;
src_facility_->residence_time = residence_time;
src_facility_->max_inv_size = max_inv_size;
src_facility_->inventory_tracker.set_capacity(max_inv_size);
src_facility_->throughput = throughput;
src_facility_->discrete_handling = discrete_handling;
}
Expand Down Expand Up @@ -457,6 +458,7 @@ TEST_F(StorageTest, MultipleCommods){
EXPECT_EQ(1, n_trans2) << "expected 1 transactions, got " << n_trans;
}


// Should get one transaction in a 2 step simulation when agent is active for
// one step and dormant for one step
TEST_F(StorageTest, ActiveDormant){
Expand Down Expand Up @@ -624,7 +626,7 @@ TEST_F(StorageTest, NormalActiveDormantBuyingSize){
" <buying_size_mean>0.5</buying_size_mean>"
" <buying_size_stddev>0.1</buying_size_stddev>";

int simdur = 15;
int simdur = 15;

cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"), config, simdur);

Expand Down Expand Up @@ -702,7 +704,6 @@ TEST_F(StorageTest, IncorrectBuyPolSetupMinMax) {
cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"),
config_uniform_min_bigger_max, simdur);
EXPECT_THROW(sim.Run(), cyclus::ValueError);

}

TEST_F(StorageTest, PositionInitialize){
Expand Down Expand Up @@ -753,6 +754,86 @@ TEST_F(StorageTest, Longitude){
EXPECT_EQ(qr.GetVal<double>("Longitude"), 35.0);
}

TEST_F(StorageTest, RQ_Inventory_Invalid) {
std::string config =
" <in_commods> <val>spent_fuel</val> </in_commods> "
" <out_commods> <val>dry_spent</val> </out_commods> "
" <max_inv_size>5</max_inv_size>"
" <reorder_point>2</reorder_point>"
" <reorder_quantity>10</reorder_quantity>";

int simdur = 2;

cyclus::MockSim sim(cyclus::AgentSpec(":cycamore:Storage"), config, simdur);

EXPECT_THROW(int id = sim.Run(), cyclus::ValueError);
}

TEST_F(StorageTest, RQ_Inventory) {
std::string config =
" <in_commods> <val>spent_fuel</val> </in_commods> "
" <out_commods> <val>dry_spent</val> </out_commods> "
" <max_inv_size>5</max_inv_size>"
" <reorder_point>2</reorder_point>"
" <reorder_quantity>3</reorder_quantity>";

int simdur = 5;

cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"), config, simdur);

sim.AddSource("spent_fuel").capacity(5).Finalize();
sim.AddSink("dry_spent").Finalize();

int id = sim.Run();

std::vector<cyclus::Cond> conds;
conds.push_back(cyclus::Cond("Commodity", "==", std::string("spent_fuel")));
cyclus::QueryResult qr = sim.db().Query("Transactions", &conds);
int n_trans = qr.rows.size();

EXPECT_EQ(3, n_trans) << "expected 3 transactions, got " << n_trans;
// check that the transactions occur at the expected time (0, 2, 4)
EXPECT_EQ(0, qr.GetVal<int>("Time", 0));
EXPECT_EQ(2, qr.GetVal<int>("Time", 1));
EXPECT_EQ(4, qr.GetVal<int>("Time", 2));

// check that all transactions are of size 3
qr = sim.db().Query("Resources", NULL);
EXPECT_EQ(3, qr.GetVal<double>("Quantity", 0));
}

TEST_F(StorageTest, sS_Inventory) {
std::string config =
" <in_commods> <val>spent_fuel</val> </in_commods> "
" <out_commods> <val>dry_spent</val> </out_commods> "
" <max_inv_size>5</max_inv_size>"
" <reorder_point>2</reorder_point>";

int simdur = 5;

cyclus::MockSim sim(cyclus::AgentSpec (":cycamore:Storage"), config, simdur);

sim.AddSource("spent_fuel").capacity(5).Finalize();
sim.AddSink("dry_spent").Finalize();

int id = sim.Run();

std::vector<cyclus::Cond> conds;
conds.push_back(cyclus::Cond("Commodity", "==", std::string("spent_fuel")));
cyclus::QueryResult qr = sim.db().Query("Transactions", &conds);
int n_trans = qr.rows.size();
EXPECT_EQ(3, n_trans) << "expected 3 transactions, got " << n_trans;
// check that the transactions occur at the expected time (0, 2, 4)
EXPECT_EQ(0, qr.GetVal<int>("Time", 0));
EXPECT_EQ(2, qr.GetVal<int>("Time", 1));
EXPECT_EQ(4, qr.GetVal<int>("Time", 2));

// check that all transactions are of size 5
qr = sim.db().Query("Resources", NULL);
EXPECT_EQ(5, qr.GetVal<double>("Quantity", 0));
}


} // namespace cycamore

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down

0 comments on commit 622db4c

Please sign in to comment.