CYCAMORE
Loading...
Searching...
No Matches
src/storage.cc
Go to the documentation of this file.
1// storage.cc
2// Implements the Storage class
3#include "storage.h"
4
5namespace cycamore {
6
7// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8Storage::Storage(cyclus::Context* ctx)
9 : cyclus::Facility(ctx),
10 latitude(0.0),
11 longitude(0.0),
13 inventory_tracker.Init({&inventory, &stocks, &ready, &processing}, cyclus::CY_LARGE_DOUBLE);
14 cyclus::Warn<cyclus::EXPERIMENTAL_WARNING>(
15 "The Storage Facility is experimental.");};
16
17// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18// pragmas
19
20#pragma cyclus def schema cycamore::Storage
21
22#pragma cyclus def annotations cycamore::Storage
23
24#pragma cyclus def initinv cycamore::Storage
25
26#pragma cyclus def snapshotinv cycamore::Storage
27
28#pragma cyclus def infiletodb cycamore::Storage
29
30#pragma cyclus def snapshot cycamore::Storage
31
32#pragma cyclus def clone cycamore::Storage
33
34//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35void Storage::InitFrom(Storage* m) {
36#pragma cyclus impl initfromcopy cycamore::Storage
37 cyclus::toolkit::CommodityProducer::Copy(m);
38}
39
40//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
41void Storage::InitFrom(cyclus::QueryableBackend* b) {
42#pragma cyclus impl initfromdb cycamore::Storage
43
44 cyclus::toolkit::Commodity commod = cyclus::toolkit::Commodity(out_commods.front());
45 cyclus::toolkit::CommodityProducer::Add(commod);
46 cyclus::toolkit::CommodityProducer::SetCapacity(commod, throughput);
47}
48
49void Storage::InitBuyPolicyParameters() {
51 if (active_buying_min > active_buying_max) {
52 throw cyclus::ValueError("Active min larger than max.");
53 }
54 if (dormant_buying_min > dormant_buying_max) {
55 throw cyclus::ValueError("Dormant min larger than max.");
56 }
57 if (buying_size_min > buying_size_max) {
58 throw cyclus::ValueError("Buying size min larger than max.");
59 }
60
61 if (active_buying_frequency_type == "Fixed") {
62 active_dist_ = cyclus::FixedIntDist::Ptr (new cyclus::FixedIntDist(active_buying_val));
63 }
64 else if (active_buying_frequency_type == "Uniform") {
65 if ((active_buying_min == -1) || (active_buying_max == -1)) {
66 throw cyclus::ValueError("Invalid active buying frequency range. Please provide both a min and max value.");
67 }
68 active_dist_ = cyclus::UniformIntDist::Ptr (new cyclus::UniformIntDist(active_buying_min, active_buying_max));
69 }
70 else if (active_buying_frequency_type == "Normal") {
71 if ((active_buying_mean == -1) || (active_buying_stddev == -1)) {
72 throw cyclus::ValueError("Invalid active buying frequency range. Please provide both a mean and standard deviation value.");
73 }
74 if (active_buying_min == -1) {active_buying_min = 1;}
75 if (active_buying_max == -1) {
76 active_buying_max = std::numeric_limits<int>::max();}
77
78 active_dist_ = cyclus::NormalIntDist::Ptr (new cyclus::NormalIntDist(active_buying_mean, active_buying_stddev,
79 active_buying_min, active_buying_max));
80 }
81 else {
82 throw cyclus::ValueError("Invalid active buying frequency type");}
83
85 if (dormant_buying_frequency_type == "Fixed") {
86 dormant_dist_ = cyclus::FixedIntDist::Ptr (new cyclus::FixedIntDist(dormant_buying_val));
87 }
88 else if (dormant_buying_frequency_type == "Uniform") {
89 if ((dormant_buying_min == -1) || (dormant_buying_max == -1)) {
90 throw cyclus::ValueError("Invalid dormant buying frequency range. Please provide both a min and max value.");
91 }
92 dormant_dist_ = cyclus::UniformIntDist::Ptr (new cyclus::UniformIntDist(dormant_buying_min, dormant_buying_max));
93 }
94 else if (dormant_buying_frequency_type == "Normal") {
95 if ((dormant_buying_mean == -1) || (dormant_buying_stddev == -1)) {
96 throw cyclus::ValueError("Invalid dormant buying frequency range. Please provide both a mean and standard deviation value.");
97 }
98 if (dormant_buying_min == -1) {dormant_buying_min = 1;}
99 if (dormant_buying_max == -1) {
100 dormant_buying_max = std::numeric_limits<int>::max();}
101 dormant_dist_ = cyclus::NormalIntDist::Ptr (new cyclus::NormalIntDist(dormant_buying_mean, dormant_buying_stddev,
102 dormant_buying_min, dormant_buying_max));
103 }
104 else {
105 throw cyclus::ValueError("Invalid dormant buying frequency type");}
106
108 if (buying_size_type == "Fixed") {
109 size_dist_ = cyclus::FixedDoubleDist::Ptr (new cyclus::FixedDoubleDist(buying_size_val));
110 }
111 else if (buying_size_type == "Uniform") {
112 if ((buying_size_min == -1) || (buying_size_max == -1)) {
113 throw cyclus::ValueError("Invalid buying size range. Please provide both a min and max value.");
114 }
115 size_dist_ = cyclus::UniformDoubleDist::Ptr (new cyclus::UniformDoubleDist(buying_size_min, buying_size_max));
116 }
117 else if (buying_size_type == "Normal") {
118 if ((buying_size_mean == -1) || (buying_size_stddev == -1)) {
119 throw cyclus::ValueError("Invalid buying size range. Please provide both a mean and standard deviation value.");
120 }
121 if (buying_size_min == -1) {buying_size_min = 0;}
122 if (buying_size_max == -1) {buying_size_max = 1;}
123 size_dist_ = cyclus::NormalDoubleDist::Ptr (new cyclus::NormalDoubleDist(buying_size_mean, buying_size_stddev,
124 buying_size_min, buying_size_max));
125 }
126 else {
127 throw cyclus::ValueError("Invalid buying size type");}
128}
129
130//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131void Storage::EnterNotify() {
132 cyclus::Facility::EnterNotify();
133
134 inventory_tracker.set_capacity(max_inv_size);
135 if (reorder_point < 0 && cumulative_cap <= 0) {
136 InitBuyPolicyParameters();
137 buy_policy.Init(this, &inventory, std::string("inventory"),
138 &inventory_tracker, throughput, active_dist_,
139 dormant_dist_, size_dist_);
140 }
141 else if (cumulative_cap > 0) {
142 InitBuyPolicyParameters();
143 buy_policy.Init(this, &inventory, std::string("inventory"),
144 &inventory_tracker, throughput, cumulative_cap,
145 dormant_dist_);
146 }
147 else if (reorder_quantity > 0) {
148 if (reorder_point + reorder_quantity > max_inv_size) {
149 throw cyclus::ValueError(
150 "reorder_point + reorder_quantity must be less than or equal to max_inv_size");
151 }
152 buy_policy.Init(this, &inventory, std::string("inventory"),
153 &inventory_tracker, throughput, "RQ",
154 reorder_quantity, reorder_point);
155 }
156 else {
157 buy_policy.Init(this, &inventory, std::string("inventory"),
158 &inventory_tracker, throughput, "sS",
159 max_inv_size, reorder_point);
160 }
161
162 // dummy comp, use in_recipe if provided
163 cyclus::CompMap v;
164 cyclus::Composition::Ptr comp = cyclus::Composition::CreateFromAtom(v);
165 if (in_recipe != "") {
166 comp = context()->GetRecipe(in_recipe);
167 }
168
169 if (in_commod_prefs.size() == 0) {
170 for (int i = 0; i < in_commods.size(); ++i) {
171 in_commod_prefs.push_back(cyclus::kDefaultPref);
172 }
173 } else if (in_commod_prefs.size() != in_commods.size()) {
174 std::stringstream ss;
175 ss << "in_commod_prefs has " << in_commod_prefs.size()
176 << " values, expected " << in_commods.size();
177 throw cyclus::ValueError(ss.str());
178 }
179
180 for (int i = 0; i != in_commods.size(); ++i) {
181 buy_policy.Set(in_commods[i], comp, in_commod_prefs[i]);
182 }
183 buy_policy.Start();
184
185 std::string package_name_ = context()->GetPackage(package)->name();
186 std::string tu_name_ = context()->GetTransportUnit(transport_unit)->name();
187 if (out_commods.size() == 1) {
188 sell_policy.Init(this, &stocks, std::string("stocks"), cyclus::CY_LARGE_DOUBLE, false,
189 sell_quantity, package_name_, tu_name_)
190 .Set(out_commods.front())
191 .Start();
192
193 } else {
194 std::stringstream ss;
195 ss << "out_commods has " << out_commods.size() << " values, expected 1.";
196 throw cyclus::ValueError(ss.str());
197 }
199}
200
201//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
202std::string Storage::str() {
203 std::stringstream ss;
204 std::string ans, out_str;
205 if (out_commods.size() == 1) {
206 out_str = out_commods.front();
207 } else {
208 out_str = "";
209 }
210 if (cyclus::toolkit::CommodityProducer::Produces(
211 cyclus::toolkit::Commodity(out_str))) {
212 ans = "yes";
213 } else {
214 ans = "no";
215 }
216 ss << cyclus::Facility::str();
217 ss << " has facility parameters {"
218 << "\n"
219 << " Output Commodity = " << out_str << ",\n"
220 << " Residence Time = " << residence_time << ",\n"
221 << " Throughput = " << throughput << ",\n"
222 << " commod producer members: "
223 << " produces " << out_str << "?:" << ans << "'}";
224 return ss.str();
225}
226
227//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
228void Storage::Tick() {
229
230
231 LOG(cyclus::LEV_INFO3, "ComCnv") << prototype() << " is ticking {";
232
233 LOG(cyclus::LEV_INFO5, "ComCnv") << "Processing = " << processing.quantity() << ", ready = " << ready.quantity() << ", stocks = " << stocks.quantity() << " and max inventory = " << max_inv_size;
234
235 LOG(cyclus::LEV_INFO4, "ComCnv") << "current capacity " << max_inv_size << " - " << processing.quantity() << " - " << ready.quantity() << " - " << stocks.quantity() << " = " << current_capacity();
236
237 if (current_capacity() > cyclus::eps_rsrc()) {
238 LOG(cyclus::LEV_INFO4, "ComCnv")
239 << " has capacity for " << current_capacity() << ".";
240 }
241 LOG(cyclus::LEV_INFO3, "ComCnv") << "}";
242}
243
244//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
245void Storage::Tock() {
246 LOG(cyclus::LEV_INFO3, "ComCnv") << prototype() << " is tocking {";
247
248 BeginProcessing_(); // place unprocessed inventory into processing
249
250 LOG(cyclus::LEV_INFO4, "ComCnv") << "processing currently holds " << processing.quantity() << ". ready currently holds " << ready.quantity() << ".";
251
252 if (ready_time() >= 0 || residence_time == 0 && !inventory.empty()) {
253 ReadyMatl_(ready_time()); // place processing into ready
254 }
255
256 LOG(cyclus::LEV_INFO5, "ComCnv") << "Ready now holds " << ready.quantity() << " kg.";
257
258 if (ready.quantity() > throughput) {
259 LOG(cyclus::LEV_INFO5, "ComCnv") << "Up to " << throughput << " kg will be placed in stocks based on throughput limits. ";
260 }
261
262 ProcessMat_(throughput); // place ready into stocks
263
264 std::vector<double>::iterator result;
265 result = std::max_element(in_commod_prefs.begin(), in_commod_prefs.end());
266 int maxindx = std::distance(in_commod_prefs.begin(), result);
267 double demand = 0;
268 demand = current_capacity();
269
270 cyclus::toolkit::RecordTimeSeries<double>("demand"+in_commods[maxindx], this, demand);
271
272 // Multiple commodity tracking is not supported, user can only
273 // provide one value for out_commods, despite it being a vector of strings.
274 cyclus::toolkit::RecordTimeSeries<double>("supply"+out_commods[0], this,
275 stocks.quantity());
276
277 LOG(cyclus::LEV_INFO4, "ComCnv") << "process has "
278 << processing.quantity() << ". Ready has " << ready.quantity() << ". Stocks has " << stocks.quantity() << ".";
279 LOG(cyclus::LEV_INFO3, "ComCnv") << "}";
280}
281
282//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
283void Storage::AddMat_(cyclus::Material::Ptr mat) {
284 LOG(cyclus::LEV_INFO5, "ComCnv") << prototype() << " is initially holding "
285 << inventory.quantity() << " total.";
286
287 try {
288 inventory.Push(mat);
289 } catch (cyclus::Error& e) {
290 e.msg(Agent::InformErrorMsg(e.msg()));
291 throw e;
292 }
293
294 LOG(cyclus::LEV_INFO5, "ComCnv")
295 << prototype() << " added " << mat->quantity()
296 << " of material to its inventory, which is holding "
297 << inventory.quantity() << " total.";
298}
299
300//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
301void Storage::BeginProcessing_() {
302 while (inventory.count() > 0) {
303 try {
304 processing.Push(inventory.Pop());
305 entry_times.push_back(context()->time());
306
307 LOG(cyclus::LEV_DEBUG2, "ComCnv")
308 << "Storage " << prototype()
309 << " added resources to processing at t= " << context()->time();
310 } catch (cyclus::Error& e) {
311 e.msg(Agent::InformErrorMsg(e.msg()));
312 throw e;
313 }
314 }
315}
316
317//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
318void Storage::ProcessMat_(double cap) {
319 if (!ready.empty()) {
320 try {
321 double max_pop = std::min(cap, ready.quantity());
322
323 if (discrete_handling) {
324 if (max_pop == ready.quantity()) {
325 stocks.Push(ready.PopN(ready.count()));
326 } else {
327 double cap_pop = ready.Peek()->quantity();
328 while (cap_pop <= max_pop && !ready.empty()) {
329 stocks.Push(ready.Pop());
330 cap_pop += ready.empty() ? 0 : ready.Peek()->quantity();
331 }
332 }
333 } else {
334 stocks.Push(ready.Pop(max_pop, cyclus::eps_rsrc()));
335 }
336
337 LOG(cyclus::LEV_INFO4, "ComCnv") << "Storage " << prototype()
338 << " moved resources"
339 << " from ready to stocks"
340 << " at t= " << context()->time();
341 } catch (cyclus::Error& e) {
342 e.msg(Agent::InformErrorMsg(e.msg()));
343 throw e;
344 }
345 }
346}
347
348//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
349void Storage::ReadyMatl_(int time) {
350 LOG(cyclus::LEV_INFO5, "ComCnv") << "Placing material into ready";
351
352 int to_ready = 0;
353
354 while (!entry_times.empty() && entry_times.front() <= time) {
355 entry_times.pop_front();
356 ++to_ready;
357 }
358
359 ready.Push(processing.PopN(to_ready));
360}
361
362void Storage::RecordPosition() {
363 std::string specification = this->spec();
364 context()
365 ->NewDatum("AgentPosition")
366 ->AddVal("Spec", specification)
367 ->AddVal("Prototype", this->prototype())
368 ->AddVal("AgentId", id())
369 ->AddVal("Latitude", latitude)
370 ->AddVal("Longitude", longitude)
371 ->Record();
372}
373
374
375// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
376extern "C" cyclus::Agent* ConstructStorage(cyclus::Context* ctx) {
377 return new Storage(ctx);
378}
379
380} // namespace cycamore
Storage(cyclus::Context *ctx)
void RecordPosition()
Records an agent's latitude and longitude to the output db.
cyclus::Agent * ConstructStorage(cyclus::Context *ctx)
cyclus::toolkit::Position coordinates