4using cyclus::toolkit::MatVec;
6using cyclus::ValueError;
12 : cyclus::Facility(ctx),
30#pragma cyclus def clone cycamore::Reactor
32#pragma cyclus def schema cycamore::Reactor
34#pragma cyclus def annotations cycamore::Reactor
36#pragma cyclus def infiletodb cycamore::Reactor
38#pragma cyclus def snapshot cycamore::Reactor
40#pragma cyclus def snapshotinv cycamore::Reactor
42#pragma cyclus def initinv cycamore::Reactor
44void Reactor::InitFrom(Reactor* m) {
45 #pragma cyclus impl initfromcopy cycamore::Reactor
46 cyclus::toolkit::CommodityProducer::Copy(m);
49void Reactor::InitFrom(cyclus::QueryableBackend* b) {
50 #pragma cyclus impl initfromdb cycamore::Reactor
52 namespace tk = cyclus::toolkit;
53 tk::CommodityProducer::Add(tk::Commodity(power_name),
54 tk::CommodInfo(power_cap, power_cap));
56 for (
int i = 0; i < side_products.size(); i++) {
57 tk::CommodityProducer::Add(tk::Commodity(side_products[i]),
58 tk::CommodInfo(side_product_quantity[i],
59 side_product_quantity[i]));
63void Reactor::EnterNotify() {
64 cyclus::Facility::EnterNotify();
67 fresh.keep_packaging(keep_packaging);
68 core.keep_packaging(keep_packaging);
69 spent.keep_packaging(keep_packaging);
73 if (fuel_prefs.size() == 0) {
74 for (
int i = 0; i < fuel_outcommods.size(); i++) {
75 fuel_prefs.push_back(cyclus::kDefaultPref);
80 if (side_products.size() == 0){
85 int n = recipe_change_times.size();
87 if (recipe_change_commods.size() != n) {
88 ss <<
"prototype '" << prototype() <<
"' has "
89 << recipe_change_commods.size()
90 <<
" recipe_change_commods vals, expected " << n <<
"\n";
92 if (recipe_change_in.size() != n) {
93 ss <<
"prototype '" << prototype() <<
"' has " << recipe_change_in.size()
94 <<
" recipe_change_in vals, expected " << n <<
"\n";
96 if (recipe_change_out.size() != n) {
97 ss <<
"prototype '" << prototype() <<
"' has " << recipe_change_out.size()
98 <<
" recipe_change_out vals, expected " << n <<
"\n";
101 n = pref_change_times.size();
102 if (pref_change_commods.size() != n) {
103 ss <<
"prototype '" << prototype() <<
"' has " << pref_change_commods.size()
104 <<
" pref_change_commods vals, expected " << n <<
"\n";
106 if (pref_change_values.size() != n) {
107 ss <<
"prototype '" << prototype() <<
"' has " << pref_change_values.size()
108 <<
" pref_change_values vals, expected " << n <<
"\n";
111 if (ss.str().size() > 0) {
112 throw ValueError(ss.str());
117bool Reactor::CheckDecommissionCondition() {
118 return core.count() == 0 && spent.count() == 0;
121void Reactor::Tick() {
130 Record(
"RETIRED",
"");
132 if (context()->time() == exit_time() + 1) {
133 if (decom_transmute_all ==
true) {
134 Transmute(ceil(
static_cast<double>(n_assem_core)));
137 Transmute(ceil(
static_cast<double>(n_assem_core) / 2.0));
140 while (core.count() > 0) {
148 while (fresh.count() > 0 && spent.space() >= assem_size) {
149 spent.Push(fresh.Pop());
151 if(CheckDecommissionCondition()) {
152 context()->SchedDecom(
this);
157 if (cycle_step == cycle_time) {
159 Record(
"CYCLE_END",
"");
162 if (cycle_step >= cycle_time && !discharged) {
163 discharged = Discharge();
165 if (cycle_step >= cycle_time) {
169 int t = context()->time();
172 for (
int i = 0; i < pref_change_times.size(); i++) {
173 int change_t = pref_change_times[i];
178 std::string incommod = pref_change_commods[i];
179 for (
int j = 0; j < fuel_incommods.size(); j++) {
180 if (fuel_incommods[j] == incommod) {
181 fuel_prefs[j] = pref_change_values[i];
188 for (
int i = 0; i < recipe_change_times.size(); i++) {
189 int change_t = recipe_change_times[i];
194 std::string incommod = recipe_change_commods[i];
195 for (
int j = 0; j < fuel_incommods.size(); j++) {
196 if (fuel_incommods[j] == incommod) {
197 fuel_inrecipes[j] = recipe_change_in[i];
198 fuel_outrecipes[j] = recipe_change_out[i];
205std::set<cyclus::RequestPortfolio<Material>::Ptr> Reactor::GetMatlRequests() {
206 using cyclus::RequestPortfolio;
208 std::set<RequestPortfolio<Material>::Ptr> ports;
213 int n_assem_order = n_assem_core - core.count() + n_assem_fresh - fresh.count();
215 if (exit_time() != -1) {
218 int t_left = exit_time() - context()->time() + 1;
219 int t_left_cycle = cycle_time + refuel_time - cycle_step;
220 double n_cycles_left =
static_cast<double>(t_left - t_left_cycle) /
221 static_cast<double>(cycle_time + refuel_time);
222 n_cycles_left = ceil(n_cycles_left);
223 int n_need = std::max(0.0, n_cycles_left * n_assem_batch - n_assem_fresh + n_assem_core - core.count());
224 n_assem_order = std::min(n_assem_order, n_need);
227 if (n_assem_order == 0) {
229 }
else if (retired()) {
233 for (
int i = 0; i < n_assem_order; i++) {
234 RequestPortfolio<Material>::Ptr port(
new RequestPortfolio<Material>());
235 std::vector<Request<Material>*> mreqs;
236 for (
int j = 0; j < fuel_incommods.size(); j++) {
237 std::string commod = fuel_incommods[j];
238 double pref = fuel_prefs[j];
239 cyclus::Composition::Ptr recipe = context()->GetRecipe(fuel_inrecipes[j]);
240 m = Material::CreateUntracked(assem_size, recipe);
242 Request<Material>* r = port->AddRequest(m,
this, commod, pref,
true);
246 std::vector<double>::iterator result;
247 result = std::max_element(fuel_prefs.begin(), fuel_prefs.end());
248 int max_index = std::distance(fuel_prefs.begin(), result);
250 cyclus::toolkit::RecordTimeSeries<double>(
"demand"+fuel_incommods[max_index],
this,
253 port->AddMutualReqs(mreqs);
260void Reactor::GetMatlTrades(
261 const std::vector<cyclus::Trade<Material> >& trades,
262 std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
266 std::map<std::string, MatVec> mats = PopSpent();
267 for (
int i = 0; i < trades.size(); i++) {
268 std::string commod = trades[i].request->commodity();
269 Material::Ptr m = mats[commod].back();
270 mats[commod].pop_back();
271 responses.push_back(std::make_pair(trades[i], m));
272 res_indexes.erase(m->obj_id());
277void Reactor::AcceptMatlTrades(
const std::vector<
278 std::pair<cyclus::Trade<Material>, Material::Ptr> >& responses) {
279 std::vector<std::pair<cyclus::Trade<Material>,
280 Material::Ptr> >::const_iterator trade;
282 std::stringstream ss;
283 int nload = std::min((
int)responses.size(), n_assem_core - core.count());
285 ss << nload <<
" assemblies";
286 Record(
"LOAD", ss.str());
289 for (trade = responses.begin(); trade != responses.end(); ++trade) {
290 std::string commod = trade->first.request->commodity();
291 Material::Ptr m = trade->second;
292 index_res(m, commod);
294 if (core.count() < n_assem_core) {
302std::set<cyclus::BidPortfolio<Material>::Ptr> Reactor::GetMatlBids(
303 cyclus::CommodMap<Material>::type& commod_requests) {
304 using cyclus::BidPortfolio;
305 std::set<BidPortfolio<Material>::Ptr> ports;
307 bool gotmats =
false;
308 std::map<std::string, MatVec> all_mats;
310 if (uniq_outcommods_.empty()) {
311 for (
int i = 0; i < fuel_outcommods.size(); i++) {
312 uniq_outcommods_.insert(fuel_outcommods[i]);
316 std::set<std::string>::iterator it;
317 for (it = uniq_outcommods_.begin(); it != uniq_outcommods_.end(); ++it) {
318 std::string commod = *it;
319 std::vector<Request<Material>*>& reqs = commod_requests[commod];
320 if (reqs.size() == 0) {
322 }
else if (!gotmats) {
323 all_mats = PeekSpent();
326 MatVec mats = all_mats[commod];
327 if (mats.size() == 0) {
331 BidPortfolio<Material>::Ptr port(
new BidPortfolio<Material>());
333 for (
int j = 0; j < reqs.size(); j++) {
334 Request<Material>* req = reqs[j];
336 for (
int k = 0; k < mats.size(); k++) {
337 Material::Ptr m = mats[k];
338 tot_bid += m->quantity();
339 port->AddBid(req, m,
this,
true);
340 if (tot_bid >= req->target()->quantity()) {
347 for (
int j = 0; j < mats.size(); j++) {
348 tot_qty += mats[j]->quantity();
351 cyclus::CapacityConstraint<Material> cc(tot_qty);
352 port->AddConstraint(cc);
359void Reactor::Tock() {
367 if (cycle_step >= cycle_time + refuel_time && core.count() == n_assem_core && discharged ==
true) {
372 if (cycle_step == 0 && core.count() == n_assem_core) {
373 Record(
"CYCLE_START",
"");
376 if (cycle_step >= 0 && cycle_step < cycle_time &&
377 core.count() == n_assem_core) {
378 cyclus::toolkit::RecordTimeSeries<cyclus::toolkit::POWER>(
this, power_cap);
379 cyclus::toolkit::RecordTimeSeries<double>(
"supplyPOWER",
this, power_cap);
380 RecordSideProduct(
true);
382 cyclus::toolkit::RecordTimeSeries<cyclus::toolkit::POWER>(
this, 0);
383 cyclus::toolkit::RecordTimeSeries<double>(
"supplyPOWER",
this, 0);
384 RecordSideProduct(
false);
389 if (cycle_step > 0 || core.count() == n_assem_core) {
394void Reactor::Transmute() { Transmute(n_assem_batch); }
396void Reactor::Transmute(
int n_assem) {
397 MatVec old = core.PopN(std::min(n_assem, core.count()));
399 if (core.count() > old.size()) {
401 core.Push(core.PopN(core.count() - old.size()));
404 std::stringstream ss;
405 ss << old.size() <<
" assemblies";
406 Record(
"TRANSMUTE", ss.str());
408 for (
int i = 0; i < old.size(); i++) {
409 old[i]->Transmute(context()->GetRecipe(fuel_outrecipe(old[i])));
413std::map<std::string, MatVec> Reactor::PeekSpent() {
414 std::map<std::string, MatVec> mapped;
415 MatVec mats = spent.PopN(spent.count());
417 for (
int i = 0; i < mats.size(); i++) {
418 std::string commod = fuel_outcommod(mats[i]);
419 mapped[commod].push_back(mats[i]);
424bool Reactor::Discharge() {
425 int npop = std::min(n_assem_batch, core.count());
426 if (n_assem_spent - spent.count() < npop) {
427 Record(
"DISCHARGE",
"failed");
431 std::stringstream ss;
432 ss << npop <<
" assemblies";
433 Record(
"DISCHARGE", ss.str());
434 spent.Push(core.PopN(npop));
436 std::map<std::string, MatVec> spent_mats;
437 for (
int i = 0; i < fuel_outcommods.size(); i++) {
438 spent_mats = PeekSpent();
439 MatVec mats = spent_mats[fuel_outcommods[i]];
440 double tot_spent = 0;
441 for (
int j = 0; j<mats.size(); j++){
442 Material::Ptr m = mats[j];
443 tot_spent += m->quantity();
445 cyclus::toolkit::RecordTimeSeries<double>(
"supply"+fuel_outcommods[i],
this, tot_spent);
451void Reactor::Load() {
452 int n = std::min(n_assem_core - core.count(), fresh.count());
457 std::stringstream ss;
458 ss << n <<
" assemblies";
459 Record(
"LOAD", ss.str());
460 core.Push(fresh.PopN(n));
463std::string Reactor::fuel_incommod(Material::Ptr m) {
464 int i = res_indexes[m->obj_id()];
465 if (i >= fuel_incommods.size()) {
466 throw KeyError(
"cycamore::Reactor - no incommod for material object");
468 return fuel_incommods[i];
471std::string Reactor::fuel_outcommod(Material::Ptr m) {
472 int i = res_indexes[m->obj_id()];
473 if (i >= fuel_outcommods.size()) {
474 throw KeyError(
"cycamore::Reactor - no outcommod for material object");
476 return fuel_outcommods[i];
479std::string Reactor::fuel_inrecipe(Material::Ptr m) {
480 int i = res_indexes[m->obj_id()];
481 if (i >= fuel_inrecipes.size()) {
482 throw KeyError(
"cycamore::Reactor - no inrecipe for material object");
484 return fuel_inrecipes[i];
487std::string Reactor::fuel_outrecipe(Material::Ptr m) {
488 int i = res_indexes[m->obj_id()];
489 if (i >= fuel_outrecipes.size()) {
490 throw KeyError(
"cycamore::Reactor - no outrecipe for material object");
492 return fuel_outrecipes[i];
495double Reactor::fuel_pref(Material::Ptr m) {
496 int i = res_indexes[m->obj_id()];
497 if (i >= fuel_prefs.size()) {
500 return fuel_prefs[i];
503void Reactor::index_res(cyclus::Resource::Ptr m, std::string incommod) {
504 for (
int i = 0; i < fuel_incommods.size(); i++) {
505 if (fuel_incommods[i] == incommod) {
506 res_indexes[m->obj_id()] = i;
511 "cycamore::Reactor - received unsupported incommod material");
514std::map<std::string, MatVec> Reactor::PopSpent() {
515 MatVec mats = spent.PopN(spent.count());
516 std::map<std::string, MatVec> mapped;
517 for (
int i = 0; i < mats.size(); i++) {
518 std::string commod = fuel_outcommod(mats[i]);
519 mapped[commod].push_back(mats[i]);
523 std::map<std::string, MatVec>::iterator it;
524 for (it = mapped.begin(); it != mapped.end(); ++it) {
525 std::reverse(it->second.begin(), it->second.end());
531void Reactor::PushSpent(std::map<std::string, MatVec> leftover) {
532 std::map<std::string, MatVec>::iterator it;
533 for (it = leftover.begin(); it != leftover.end(); ++it) {
535 std::reverse(it->second.begin(), it->second.end());
536 spent.Push(it->second);
540void Reactor::RecordSideProduct(
bool produce){
543 for (
int i = 0; i < side_products.size(); i++) {
545 value = side_product_quantity[i];
552 ->NewDatum(
"ReactorSideProducts")
553 ->AddVal(
"AgentId",
id())
554 ->AddVal(
"Time", context()->time())
555 ->AddVal(
"Product", side_products[i])
556 ->AddVal(
"Value", value)
562void Reactor::Record(std::string name, std::string val) {
564 ->NewDatum(
"ReactorEvents")
565 ->AddVal(
"AgentId",
id())
566 ->AddVal(
"Time", context()->time())
567 ->AddVal(
"Event", name)
568 ->AddVal(
"Value", val)
572void Reactor::RecordPosition() {
573 std::string specification = this->spec();
575 ->NewDatum(
"AgentPosition")
576 ->AddVal(
"Spec", specification)
577 ->AddVal(
"Prototype", this->prototype())
578 ->AddVal(
"AgentId",
id())
579 ->AddVal(
"Latitude", latitude)
580 ->AddVal(
"Longitude", longitude)
585 return new Reactor(ctx);
Reactor(cyclus::Context *ctx)
cyclus::Agent * ConstructReactor(cyclus::Context *ctx)
void RecordPosition()
Records an agent's latitude and longitude to the output db.
cyclus::toolkit::Position coordinates