4using cyclus::toolkit::MatVec;
6using cyclus::ValueError;
12 : cyclus::Facility(ctx),
24 keep_packaging(true) {}
27#pragma cyclus def clone cycamore::Reactor
29#pragma cyclus def schema cycamore::Reactor
31#pragma cyclus def annotations cycamore::Reactor
33#pragma cyclus def infiletodb cycamore::Reactor
35#pragma cyclus def snapshot cycamore::Reactor
37#pragma cyclus def snapshotinv cycamore::Reactor
39#pragma cyclus def initinv cycamore::Reactor
41void Reactor::InitFrom(Reactor* m) {
42 #pragma cyclus impl initfromcopy cycamore::Reactor
43 cyclus::toolkit::CommodityProducer::Copy(m);
46void Reactor::InitFrom(cyclus::QueryableBackend* b) {
47 #pragma cyclus impl initfromdb cycamore::Reactor
49 namespace tk = cyclus::toolkit;
50 tk::CommodityProducer::Add(tk::Commodity(power_name),
51 tk::CommodInfo(power_cap, power_cap));
53 for (
int i = 0; i < side_products.size(); i++) {
54 tk::CommodityProducer::Add(tk::Commodity(side_products[i]),
55 tk::CommodInfo(side_product_quantity[i],
56 side_product_quantity[i]));
60void Reactor::EnterNotify() {
61 cyclus::Facility::EnterNotify();
64 fresh.keep_packaging(keep_packaging);
65 core.keep_packaging(keep_packaging);
66 spent.keep_packaging(keep_packaging);
70 if (fuel_prefs.size() == 0) {
71 for (
int i = 0; i < fuel_outcommods.size(); i++) {
72 fuel_prefs.push_back(cyclus::kDefaultPref);
77 if (side_products.size() == 0){
82 int n = recipe_change_times.size();
84 if (recipe_change_commods.size() != n) {
85 ss <<
"prototype '" << prototype() <<
"' has "
86 << recipe_change_commods.size()
87 <<
" recipe_change_commods vals, expected " << n <<
"\n";
89 if (recipe_change_in.size() != n) {
90 ss <<
"prototype '" << prototype() <<
"' has " << recipe_change_in.size()
91 <<
" recipe_change_in vals, expected " << n <<
"\n";
93 if (recipe_change_out.size() != n) {
94 ss <<
"prototype '" << prototype() <<
"' has " << recipe_change_out.size()
95 <<
" recipe_change_out vals, expected " << n <<
"\n";
98 n = pref_change_times.size();
99 if (pref_change_commods.size() != n) {
100 ss <<
"prototype '" << prototype() <<
"' has " << pref_change_commods.size()
101 <<
" pref_change_commods vals, expected " << n <<
"\n";
103 if (pref_change_values.size() != n) {
104 ss <<
"prototype '" << prototype() <<
"' has " << pref_change_values.size()
105 <<
" pref_change_values vals, expected " << n <<
"\n";
108 if (ss.str().size() > 0) {
109 throw ValueError(ss.str());
112 InitializePosition();
115bool Reactor::CheckDecommissionCondition() {
116 return core.count() == 0 && spent.count() == 0;
119void Reactor::Tick() {
128 Record(
"RETIRED",
"");
130 if (context()->time() == exit_time() + 1) {
131 if (decom_transmute_all ==
true) {
132 Transmute(ceil(
static_cast<double>(n_assem_core)));
135 Transmute(ceil(
static_cast<double>(n_assem_core) / 2.0));
138 while (core.count() > 0) {
146 while (fresh.count() > 0 && spent.space() >= assem_size) {
147 spent.Push(fresh.Pop());
149 if(CheckDecommissionCondition()) {
150 context()->SchedDecom(
this);
155 if (cycle_step == cycle_time) {
157 Record(
"CYCLE_END",
"");
160 if (cycle_step >= cycle_time && !discharged) {
161 discharged = Discharge();
163 if (cycle_step >= cycle_time) {
167 int t = context()->time();
170 for (
int i = 0; i < pref_change_times.size(); i++) {
171 int change_t = pref_change_times[i];
176 std::string incommod = pref_change_commods[i];
177 for (
int j = 0; j < fuel_incommods.size(); j++) {
178 if (fuel_incommods[j] == incommod) {
179 fuel_prefs[j] = pref_change_values[i];
186 for (
int i = 0; i < recipe_change_times.size(); i++) {
187 int change_t = recipe_change_times[i];
192 std::string incommod = recipe_change_commods[i];
193 for (
int j = 0; j < fuel_incommods.size(); j++) {
194 if (fuel_incommods[j] == incommod) {
195 fuel_inrecipes[j] = recipe_change_in[i];
196 fuel_outrecipes[j] = recipe_change_out[i];
203std::set<cyclus::RequestPortfolio<Material>::Ptr> Reactor::GetMatlRequests() {
204 using cyclus::RequestPortfolio;
206 std::set<RequestPortfolio<Material>::Ptr> ports;
211 int n_assem_order = n_assem_core - core.count() + n_assem_fresh - fresh.count();
213 if (exit_time() != -1) {
216 int t_left = exit_time() - context()->time() + 1;
217 int t_left_cycle = cycle_time + refuel_time - cycle_step;
218 double n_cycles_left =
static_cast<double>(t_left - t_left_cycle) /
219 static_cast<double>(cycle_time + refuel_time);
220 n_cycles_left = ceil(n_cycles_left);
221 int n_need = std::max(0.0, n_cycles_left * n_assem_batch - n_assem_fresh + n_assem_core - core.count());
222 n_assem_order = std::min(n_assem_order, n_need);
225 if (n_assem_order == 0) {
227 }
else if (retired()) {
231 for (
int i = 0; i < n_assem_order; i++) {
232 RequestPortfolio<Material>::Ptr port(
new RequestPortfolio<Material>());
233 std::vector<Request<Material>*> mreqs;
234 for (
int j = 0; j < fuel_incommods.size(); j++) {
235 std::string commod = fuel_incommods[j];
236 double pref = fuel_prefs[j];
237 cyclus::Composition::Ptr recipe = context()->GetRecipe(fuel_inrecipes[j]);
238 m = Material::CreateUntracked(assem_size, recipe);
240 Request<Material>* r = port->AddRequest(m,
this, commod, pref,
true);
244 std::vector<double>::iterator result;
245 result = std::max_element(fuel_prefs.begin(), fuel_prefs.end());
246 int max_index = std::distance(fuel_prefs.begin(), result);
248 cyclus::toolkit::RecordTimeSeries<double>(
"demand"+fuel_incommods[max_index],
this,
251 port->AddMutualReqs(mreqs);
258void Reactor::GetMatlTrades(
259 const std::vector<cyclus::Trade<Material> >& trades,
260 std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
264 std::map<std::string, MatVec> mats = PopSpent();
265 for (
int i = 0; i < trades.size(); i++) {
266 std::string commod = trades[i].request->commodity();
267 Material::Ptr m = mats[commod].back();
268 mats[commod].pop_back();
269 responses.push_back(std::make_pair(trades[i], m));
270 res_indexes.erase(m->obj_id());
275void Reactor::AcceptMatlTrades(
const std::vector<
276 std::pair<cyclus::Trade<Material>, Material::Ptr> >& responses) {
277 std::vector<std::pair<cyclus::Trade<Material>,
278 Material::Ptr> >::const_iterator trade;
280 std::stringstream ss;
281 int nload = std::min((
int)responses.size(), n_assem_core - core.count());
283 ss << nload <<
" assemblies";
284 Record(
"LOAD", ss.str());
287 for (trade = responses.begin(); trade != responses.end(); ++trade) {
288 std::string commod = trade->first.request->commodity();
289 Material::Ptr m = trade->second;
290 index_res(m, commod);
292 if (core.count() < n_assem_core) {
300std::set<cyclus::BidPortfolio<Material>::Ptr> Reactor::GetMatlBids(
301 cyclus::CommodMap<Material>::type& commod_requests) {
302 using cyclus::BidPortfolio;
303 std::set<BidPortfolio<Material>::Ptr> ports;
305 bool gotmats =
false;
306 std::map<std::string, MatVec> all_mats;
308 if (uniq_outcommods_.empty()) {
309 for (
int i = 0; i < fuel_outcommods.size(); i++) {
310 uniq_outcommods_.insert(fuel_outcommods[i]);
314 std::set<std::string>::iterator it;
315 for (it = uniq_outcommods_.begin(); it != uniq_outcommods_.end(); ++it) {
316 std::string commod = *it;
317 std::vector<Request<Material>*>& reqs = commod_requests[commod];
318 if (reqs.size() == 0) {
320 }
else if (!gotmats) {
321 all_mats = PeekSpent();
324 MatVec mats = all_mats[commod];
325 if (mats.size() == 0) {
329 BidPortfolio<Material>::Ptr port(
new BidPortfolio<Material>());
331 for (
int j = 0; j < reqs.size(); j++) {
332 Request<Material>* req = reqs[j];
334 for (
int k = 0; k < mats.size(); k++) {
335 Material::Ptr m = mats[k];
336 tot_bid += m->quantity();
337 port->AddBid(req, m,
this,
true);
338 if (tot_bid >= req->target()->quantity()) {
345 for (
int j = 0; j < mats.size(); j++) {
346 tot_qty += mats[j]->quantity();
349 cyclus::CapacityConstraint<Material> cc(tot_qty);
350 port->AddConstraint(cc);
357void Reactor::Tock() {
365 if (cycle_step >= cycle_time + refuel_time && core.count() == n_assem_core && discharged ==
true) {
370 if (cycle_step == 0 && core.count() == n_assem_core) {
371 Record(
"CYCLE_START",
"");
374 if (cycle_step >= 0 && cycle_step < cycle_time &&
375 core.count() == n_assem_core) {
376 cyclus::toolkit::RecordTimeSeries<cyclus::toolkit::POWER>(
this, power_cap);
377 cyclus::toolkit::RecordTimeSeries<double>(
"supplyPOWER",
this, power_cap);
378 RecordSideProduct(
true);
380 cyclus::toolkit::RecordTimeSeries<cyclus::toolkit::POWER>(
this, 0);
381 cyclus::toolkit::RecordTimeSeries<double>(
"supplyPOWER",
this, 0);
382 RecordSideProduct(
false);
387 if (cycle_step > 0 || core.count() == n_assem_core) {
392void Reactor::Transmute() { Transmute(n_assem_batch); }
394void Reactor::Transmute(
int n_assem) {
395 MatVec old = core.PopN(std::min(n_assem, core.count()));
397 if (core.count() > old.size()) {
399 core.Push(core.PopN(core.count() - old.size()));
402 std::stringstream ss;
403 ss << old.size() <<
" assemblies";
404 Record(
"TRANSMUTE", ss.str());
406 for (
int i = 0; i < old.size(); i++) {
407 old[i]->Transmute(context()->GetRecipe(fuel_outrecipe(old[i])));
411std::map<std::string, MatVec> Reactor::PeekSpent() {
412 std::map<std::string, MatVec> mapped;
413 MatVec mats = spent.PopN(spent.count());
415 for (
int i = 0; i < mats.size(); i++) {
416 std::string commod = fuel_outcommod(mats[i]);
417 mapped[commod].push_back(mats[i]);
422bool Reactor::Discharge() {
423 int npop = std::min(n_assem_batch, core.count());
424 if (n_assem_spent - spent.count() < npop) {
425 Record(
"DISCHARGE",
"failed");
429 std::stringstream ss;
430 ss << npop <<
" assemblies";
431 Record(
"DISCHARGE", ss.str());
432 spent.Push(core.PopN(npop));
434 std::map<std::string, MatVec> spent_mats;
435 for (
int i = 0; i < fuel_outcommods.size(); i++) {
436 spent_mats = PeekSpent();
437 MatVec mats = spent_mats[fuel_outcommods[i]];
438 double tot_spent = 0;
439 for (
int j = 0; j<mats.size(); j++){
440 Material::Ptr m = mats[j];
441 tot_spent += m->quantity();
443 cyclus::toolkit::RecordTimeSeries<double>(
"supply"+fuel_outcommods[i],
this, tot_spent);
449void Reactor::Load() {
450 int n = std::min(n_assem_core - core.count(), fresh.count());
455 std::stringstream ss;
456 ss << n <<
" assemblies";
457 Record(
"LOAD", ss.str());
458 core.Push(fresh.PopN(n));
461std::string Reactor::fuel_incommod(Material::Ptr m) {
462 int i = res_indexes[m->obj_id()];
463 if (i >= fuel_incommods.size()) {
464 throw KeyError(
"cycamore::Reactor - no incommod for material object");
466 return fuel_incommods[i];
469std::string Reactor::fuel_outcommod(Material::Ptr m) {
470 int i = res_indexes[m->obj_id()];
471 if (i >= fuel_outcommods.size()) {
472 throw KeyError(
"cycamore::Reactor - no outcommod for material object");
474 return fuel_outcommods[i];
477std::string Reactor::fuel_inrecipe(Material::Ptr m) {
478 int i = res_indexes[m->obj_id()];
479 if (i >= fuel_inrecipes.size()) {
480 throw KeyError(
"cycamore::Reactor - no inrecipe for material object");
482 return fuel_inrecipes[i];
485std::string Reactor::fuel_outrecipe(Material::Ptr m) {
486 int i = res_indexes[m->obj_id()];
487 if (i >= fuel_outrecipes.size()) {
488 throw KeyError(
"cycamore::Reactor - no outrecipe for material object");
490 return fuel_outrecipes[i];
493double Reactor::fuel_pref(Material::Ptr m) {
494 int i = res_indexes[m->obj_id()];
495 if (i >= fuel_prefs.size()) {
498 return fuel_prefs[i];
501void Reactor::index_res(cyclus::Resource::Ptr m, std::string incommod) {
502 for (
int i = 0; i < fuel_incommods.size(); i++) {
503 if (fuel_incommods[i] == incommod) {
504 res_indexes[m->obj_id()] = i;
509 "cycamore::Reactor - received unsupported incommod material");
512std::map<std::string, MatVec> Reactor::PopSpent() {
513 MatVec mats = spent.PopN(spent.count());
514 std::map<std::string, MatVec> mapped;
515 for (
int i = 0; i < mats.size(); i++) {
516 std::string commod = fuel_outcommod(mats[i]);
517 mapped[commod].push_back(mats[i]);
521 std::map<std::string, MatVec>::iterator it;
522 for (it = mapped.begin(); it != mapped.end(); ++it) {
523 std::reverse(it->second.begin(), it->second.end());
529void Reactor::PushSpent(std::map<std::string, MatVec> leftover) {
530 std::map<std::string, MatVec>::iterator it;
531 for (it = leftover.begin(); it != leftover.end(); ++it) {
533 std::reverse(it->second.begin(), it->second.end());
534 spent.Push(it->second);
538void Reactor::RecordSideProduct(
bool produce){
541 for (
int i = 0; i < side_products.size(); i++) {
543 value = side_product_quantity[i];
550 ->NewDatum(
"ReactorSideProducts")
551 ->AddVal(
"AgentId",
id())
552 ->AddVal(
"Time", context()->time())
553 ->AddVal(
"Product", side_products[i])
554 ->AddVal(
"Value", value)
560void Reactor::Record(std::string name, std::string val) {
562 ->NewDatum(
"ReactorEvents")
563 ->AddVal(
"AgentId",
id())
564 ->AddVal(
"Time", context()->time())
565 ->AddVal(
"Event", name)
566 ->AddVal(
"Value", val)
571 return new Reactor(ctx);
Reactor(cyclus::Context *ctx)
cyclus::Agent * ConstructReactor(cyclus::Context *ctx)