CYCAMORE
Loading...
Searching...
No Matches
build/cycamore/fuel_fab.cc
Go to the documentation of this file.
1
2#line 1 "/cycamore/src/fuel_fab.cc"
3#include "fuel_fab.h"
4
5#include <sstream>
6
7using cyclus::Material;
8using cyclus::Composition;
9using pyne::simple_xs;
10
11#define SHOW(X) std::cout << std::setprecision(17) << __FILE__ << ":" << __LINE__ << ": " #X " = " << X << "\n"
12#line 12 "/cycamore/src/fuel_fab.cc"
13
14namespace cycamore {
15
16class FissConverter : public cyclus::Converter<Material> {
17 public:
18 FissConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss,
19 Composition::Ptr c_topup, std::string spectrum)
20 : c_fiss_(c_fiss), c_topup_(c_topup), c_fill_(c_fill), spec_(spectrum) {
21 w_fiss_ = CosiWeight(c_fiss, spectrum);
22 w_fill_ = CosiWeight(c_fill, spectrum);
23 w_topup_ = CosiWeight(c_topup, spectrum);
24 }
25
26 virtual ~FissConverter() {}
27
28 virtual double convert(
29 Material::Ptr m, cyclus::Arc const* a = NULL,
30 cyclus::ExchangeTranslationContext<Material> const* ctx =
31 NULL) const {
32 double w_tgt = CosiWeight(m->comp(), spec_);
33 if (ValidWeights(w_fill_, w_tgt, w_fiss_)) {
34 double frac = HighFrac(w_fill_, w_tgt, w_fiss_);
35 return AtomToMassFrac(frac, c_fiss_, c_fill_) * m->quantity();
36 } else if (ValidWeights(w_fiss_, w_tgt, w_topup_)) {
37 // use fiss inventory as filler, and topup as fissile
38 double frac = LowFrac(w_fiss_, w_tgt, w_topup_);
39 return AtomToMassFrac(frac, c_fiss_, c_topup_) * m->quantity();
40 } else {
41 // don't bid at all
42 return cyclus::CY_LARGE_DOUBLE;
43 }
44 }
45
46 private:
47 std::string spec_;
48 double w_fiss_;
49 double w_topup_;
50 double w_fill_;
51 Composition::Ptr c_fiss_;
52 Composition::Ptr c_fill_;
53 Composition::Ptr c_topup_;
54};
55
56class FillConverter : public cyclus::Converter<Material> {
57 public:
58 FillConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss,
59 Composition::Ptr c_topup, std::string spectrum)
60 : c_fiss_(c_fiss), c_topup_(c_topup), c_fill_(c_fill), spec_(spectrum) {
61 w_fiss_ = CosiWeight(c_fiss, spectrum);
62 w_fill_ = CosiWeight(c_fill, spectrum);
63 w_topup_ = CosiWeight(c_topup, spectrum);
64 }
65
66 virtual ~FillConverter() {}
67
68 virtual double convert(
69 Material::Ptr m, cyclus::Arc const* a = NULL,
70 cyclus::ExchangeTranslationContext<Material> const* ctx =
71 NULL) const {
72 double w_tgt = CosiWeight(m->comp(), spec_);
73 if (ValidWeights(w_fill_, w_tgt, w_fiss_)) {
74 double frac = LowFrac(w_fill_, w_tgt, w_fiss_);
75 return AtomToMassFrac(frac, c_fill_, c_fiss_) * m->quantity();
76 } else if (ValidWeights(w_fiss_, w_tgt, w_topup_)) {
77 // switched fissile inventory to filler so don't need any filler inventory
78 return 0;
79 } else {
80 // don't bid at all
81 return cyclus::CY_LARGE_DOUBLE;
82 }
83 }
84
85 private:
86 std::string spec_;
87 double w_fiss_;
88 double w_topup_;
89 double w_fill_;
90 Composition::Ptr c_fiss_;
91 Composition::Ptr c_fill_;
92 Composition::Ptr c_topup_;
93};
94
95class TopupConverter : public cyclus::Converter<Material> {
96 public:
97 TopupConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss,
98 Composition::Ptr c_topup, std::string spectrum)
99 : c_fiss_(c_fiss), c_topup_(c_topup), c_fill_(c_fill), spec_(spectrum) {
100 w_fiss_ = CosiWeight(c_fiss, spectrum);
101 w_fill_ = CosiWeight(c_fill, spectrum);
102 w_topup_ = CosiWeight(c_topup, spectrum);
103 }
104
105 virtual ~TopupConverter() {}
106
107 virtual double convert(
108 Material::Ptr m, cyclus::Arc const* a = NULL,
109 cyclus::ExchangeTranslationContext<Material> const* ctx =
110 NULL) const {
111 double w_tgt = CosiWeight(m->comp(), spec_);
112 if (ValidWeights(w_fill_, w_tgt, w_fiss_)) {
113 return 0;
114 } else if (ValidWeights(w_fiss_, w_tgt, w_topup_)) {
115 // switched fissile inventory to filler and topup as fissile
116 double frac = HighFrac(w_fiss_, w_tgt, w_topup_);
117 return AtomToMassFrac(frac, c_topup_, c_fiss_) * m->quantity();
118 } else {
119 // don't bid at all
120 return cyclus::CY_LARGE_DOUBLE;
121 }
122 }
123
124 private:
125 std::string spec_;
126 double w_fiss_;
127 double w_topup_;
128 double w_fill_;
129 Composition::Ptr c_fiss_;
130 Composition::Ptr c_fill_;
131 Composition::Ptr c_topup_;
132};
133
134FuelFab::FuelFab(cyclus::Context* ctx)
135 : cyclus::Facility(ctx),
136 fill_size(0),
137 fiss_size(0),
138 throughput(0) {}
139
141 cyclus::Facility::EnterNotify();
142
143 if (fiss_commod_prefs.empty()) {
144 for (int i = 0; i < fiss_commods.size(); i++) {
145 fiss_commod_prefs.push_back(cyclus::kDefaultPref);
146 }
147 } else if (fiss_commod_prefs.size() != fiss_commods.size()) {
148 std::stringstream ss;
149 ss << "prototype '" << prototype() << "' has " << fiss_commod_prefs.size()
150 << " fiss_commod_prefs vals, expected " << fiss_commods.size();
151 throw cyclus::ValidationError(ss.str());
152 }
153
154 if (fill_commod_prefs.empty()) {
155 for (int i = 0; i < fill_commods.size(); i++) {
156 fill_commod_prefs.push_back(cyclus::kDefaultPref);
157 }
158 } else if (fill_commod_prefs.size() != fill_commods.size()) {
159 std::stringstream ss;
160 ss << "prototype '" << prototype() << "' has " << fill_commod_prefs.size()
161 << " fill_commod_prefs vals, expected " << fill_commods.size();
162 throw cyclus::ValidationError(ss.str());
163 }
164
165 InitializePosition();
166}
167
168std::set<cyclus::RequestPortfolio<Material>::Ptr> FuelFab::GetMatlRequests() {
169 using cyclus::RequestPortfolio;
170
171 std::set<RequestPortfolio<Material>::Ptr> ports;
172
173 bool exclusive = false;
174
175 if (fiss.space() > cyclus::eps_rsrc()) {
176 RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
177
178 Material::Ptr m = cyclus::NewBlankMaterial(fiss.space());
179 if (!fiss_recipe.empty()) {
180 Composition::Ptr c = context()->GetRecipe(fiss_recipe);
181 m = Material::CreateUntracked(fiss.space(), c);
182 }
183
184 std::vector<cyclus::Request<Material>*> reqs;
185 for (int i = 0; i < fiss_commods.size(); i++) {
186 std::string commod = fiss_commods[i];
187 double pref = fiss_commod_prefs[i];
188 reqs.push_back(port->AddRequest(m, this, commod, pref, exclusive));
189 req_inventories_[reqs.back()] = "fiss";
190 }
191 port->AddMutualReqs(reqs);
192 ports.insert(port);
193 }
194
195 if (fill.space() > cyclus::eps_rsrc()) {
196 RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
197
198 Material::Ptr m = cyclus::NewBlankMaterial(fill.space());
199 if (!fill_recipe.empty()) {
200 Composition::Ptr c = context()->GetRecipe(fill_recipe);
201 m = Material::CreateUntracked(fill.space(), c);
202 }
203
204 std::vector<cyclus::Request<Material>*> reqs;
205 for (int i = 0; i < fill_commods.size(); i++) {
206 std::string commod = fill_commods[i];
207 double pref = fill_commod_prefs[i];
208 reqs.push_back(port->AddRequest(m, this, commod, pref, exclusive));
209 req_inventories_[reqs.back()] = "fill";
210 }
211 port->AddMutualReqs(reqs);
212 ports.insert(port);
213 }
214
215 if (topup.space() > cyclus::eps_rsrc()) {
216 RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
217
218 Material::Ptr m = cyclus::NewBlankMaterial(topup.space());
219 if (!topup_recipe.empty()) {
220 Composition::Ptr c = context()->GetRecipe(topup_recipe);
221 m = Material::CreateUntracked(topup.space(), c);
222 }
223 cyclus::Request<Material>* r =
224 port->AddRequest(m, this, topup_commod, topup_pref, exclusive);
225 req_inventories_[r] = "topup";
226 ports.insert(port);
227 }
228
229 return ports;
230}
231
232bool Contains(std::vector<std::string> vec, std::string s) {
233 for (int i = 0; i < vec.size(); i++) {
234 if (vec[i] == s) {
235 return true;
236 }
237 }
238 return false;
239}
240
242 const std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
243 responses) {
244 std::vector<std::pair<cyclus::Trade<Material>,
245 Material::Ptr> >::const_iterator trade;
246
247 for (trade = responses.begin(); trade != responses.end(); ++trade) {
248 std::string commod = trade->first.request->commodity();
249 double req_qty = trade->first.request->target()->quantity();
250 cyclus::Request<Material>* req = trade->first.request;
251 Material::Ptr m = trade->second;
252 if (req_inventories_[req] == "fill") {
253 fill.Push(m);
254 } else if (req_inventories_[req] == "topup") {
255 topup.Push(m);
256 } else if (req_inventories_[req] == "fiss") {
257 fiss.Push(m);
258 } else {
259 throw cyclus::ValueError("cycamore::FuelFab was overmatched on requests");
260 }
261 }
262
263 req_inventories_.clear();
264
265 // IMPORTANT - each buffer needs to be a single homogenous composition or
266 // the inventory mixing constraints for bids don't work
267 if (fill.count() > 1) {
268 fill.Push(cyclus::toolkit::Squash(fill.PopN(fill.count())));
269 }
270 if (fiss.count() > 1) {
271 fiss.Push(cyclus::toolkit::Squash(fiss.PopN(fiss.count())));
272 }
273 if (topup.count() > 1) {
274 topup.Push(cyclus::toolkit::Squash(topup.PopN(topup.count())));
275 }
276}
277
278std::set<cyclus::BidPortfolio<Material>::Ptr> FuelFab::GetMatlBids(
279 cyclus::CommodMap<Material>::type& commod_requests) {
280 using cyclus::BidPortfolio;
281
282 std::set<BidPortfolio<Material>::Ptr> ports;
283 std::vector<cyclus::Request<Material>*>& reqs = commod_requests[outcommod];
284
285 if (throughput == 0) {
286 return ports;
287 } else if (reqs.size() == 0) {
288 return ports;
289 }
290
291 double w_fill = 0;
292 Composition::Ptr
293 c_fill; // no default needed - this is non-optional parameter
294 if (fill.count() > 0) {
295 c_fill = fill.Peek()->comp();
296 w_fill = CosiWeight(c_fill, spectrum);
297 } else {
298 c_fill = context()->GetRecipe(fill_recipe);
299 w_fill = CosiWeight(c_fill, spectrum);
300 }
301
302 double w_topup = 0;
303 Composition::Ptr c_topup = c_fill;
304 if (topup.count() > 0) {
305 c_topup = topup.Peek()->comp();
306 w_topup = CosiWeight(c_topup, spectrum);
307 } else if (!topup_recipe.empty()) {
308 c_topup = context()->GetRecipe(topup_recipe);
309 w_topup = CosiWeight(c_topup, spectrum);
310 }
311
312 double w_fiss =
313 w_fill; // this allows trading just fill with no fiss inventory
314 Composition::Ptr c_fiss = c_fill;
315 if (fiss.count() > 0) {
316 c_fiss = fiss.Peek()->comp();
317 w_fiss = CosiWeight(c_fiss, spectrum);
318 } else if (!fiss_recipe.empty()) {
319 c_fiss = context()->GetRecipe(fiss_recipe);
320 w_fiss = CosiWeight(c_fiss, spectrum);
321 }
322
323 BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());
324 for (int j = 0; j < reqs.size(); j++) {
325 cyclus::Request<Material>* req = reqs[j];
326
327 Composition::Ptr tgt = req->target()->comp();
328 double w_tgt = CosiWeight(tgt, spectrum);
329 double tgt_qty = req->target()->quantity();
330 if (ValidWeights(w_fill, w_tgt, w_fiss)) {
331 double fiss_frac = HighFrac(w_fill, w_tgt, w_fiss);
332 double fill_frac = 1 - fiss_frac;
333 fiss_frac = AtomToMassFrac(fiss_frac, c_fiss, c_fill);
334 fill_frac = AtomToMassFrac(fill_frac, c_fill, c_fiss);
335 Material::Ptr m1 = Material::CreateUntracked(fiss_frac * tgt_qty, c_fiss);
336 Material::Ptr m2 = Material::CreateUntracked(fill_frac * tgt_qty, c_fill);
337 m1->Absorb(m2);
338
339 bool exclusive = false;
340 port->AddBid(req, m1, this, exclusive);
341 } else if (topup.count() > 0 && ValidWeights(w_fiss, w_tgt, w_topup)) {
342 // only bid with topup if we have filler - otherwise we might be able to
343 // meet target with filler when we get it. we should only use topup
344 // when the fissile has too poor neutronics.
345 double topup_frac = HighFrac(w_fiss, w_tgt, w_topup);
346 double fiss_frac = 1 - topup_frac;
347 fiss_frac = AtomToMassFrac(fiss_frac, c_fiss, c_topup);
348 topup_frac = AtomToMassFrac(topup_frac, c_topup, c_fiss);
349 Material::Ptr m1 =
350 Material::CreateUntracked(topup_frac * tgt_qty, c_topup);
351 Material::Ptr m2 = Material::CreateUntracked(fiss_frac * tgt_qty, c_fiss);
352 m1->Absorb(m2);
353
354 bool exclusive = false;
355 port->AddBid(req, m1, this, exclusive);
356 } else if (fiss.count() > 0 && fill.count() > 0 ||
357 fiss.count() > 0 && topup.count() > 0) {
358 // else can't meet the target weight - don't bid. Just a plain else
359 // doesn't work because we set w_fiss = w_fill if we don't have any fiss
360 // or fill inventory.
361 std::stringstream ss;
362 ss << "prototype '" << prototype()
363 << "': Input stream weights/reactivity do not span "
364 "the requested material weight.";
365 cyclus::Warn<cyclus::VALUE_WARNING>(ss.str());
366 }
367 }
368
369 cyclus::Converter<Material>::Ptr fissconv(
370 new FissConverter(c_fill, c_fiss, c_topup, spectrum));
371 cyclus::Converter<Material>::Ptr fillconv(
372 new FillConverter(c_fill, c_fiss, c_topup, spectrum));
373 cyclus::Converter<Material>::Ptr topupconv(
374 new TopupConverter(c_fill, c_fiss, c_topup, spectrum));
375 // important! - the std::max calls prevent CapacityConstraint throwing a zero
376 // cap exception
377 cyclus::CapacityConstraint<Material> fissc(std::max(fiss.quantity(), cyclus::CY_NEAR_ZERO),
378 fissconv);
379 cyclus::CapacityConstraint<Material> fillc(std::max(fill.quantity(), cyclus::CY_NEAR_ZERO),
380 fillconv);
381 cyclus::CapacityConstraint<Material> topupc(std::max(topup.quantity(), cyclus::CY_NEAR_ZERO),
382 topupconv);
383 port->AddConstraint(fillc);
384 port->AddConstraint(fissc);
385 port->AddConstraint(topupc);
386
387 cyclus::CapacityConstraint<Material> cc(throughput);
388 port->AddConstraint(cc);
389 ports.insert(port);
390 return ports;
391}
392
394 const std::vector<cyclus::Trade<Material> >& trades,
395 std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
396 responses) {
397 using cyclus::Trade;
398
399 // guard against cases where a buffer is empty - this is okay because some
400 // trades may not need that particular buffer.
401 double w_fill = 0;
402 if (fill.count() > 0) {
403 w_fill = CosiWeight(fill.Peek()->comp(), spectrum);
404 }
405 double w_topup = 0;
406 if (topup.count() > 0) {
407 w_topup = CosiWeight(topup.Peek()->comp(), spectrum);
408 }
409 double w_fiss = 0;
410 if (fiss.count() > 0) {
411 w_fiss = CosiWeight(fiss.Peek()->comp(), spectrum);
412 }
413
414 std::vector<cyclus::Trade<Material> >::const_iterator it;
415 double tot = 0;
416 for (int i = 0; i < trades.size(); i++) {
417 Material::Ptr tgt = trades[i].request->target();
418
419 double w_tgt = CosiWeight(tgt->comp(), spectrum);
420 double qty = trades[i].amt;
421 double wfiss = w_fiss;
422
423 tot += qty;
424 if (tot > throughput + cyclus::eps_rsrc()) {
425 std::stringstream ss;
426 ss << "FuelFab was matched above throughput limit: " << tot << " > "
427 << throughput;
428 throw cyclus::ValueError(ss.str());
429 }
430
431 if (fiss.count() == 0) {
432 // use straight filler to satisfy this request
433 double fillqty = qty;
434 if (std::abs(fillqty - fill.quantity()) < cyclus::eps_rsrc()) {
435 fillqty = std::min(fill.quantity(), qty);
436 }
437 responses.push_back(
438 std::make_pair(trades[i], fill.Pop(fillqty, cyclus::eps_rsrc())));
439 } else if (fill.count() == 0 && ValidWeights(w_fill, w_tgt, w_fiss)) {
440 // use straight fissile to satisfy this request
441 double fissqty = qty;
442 if (std::abs(fissqty - fiss.quantity()) < cyclus::eps_rsrc()) {
443 fissqty = std::min(fiss.quantity(), qty);
444 }
445 responses.push_back(
446 std::make_pair(trades[i], fiss.Pop(fissqty, cyclus::eps_rsrc())));
447 } else if (ValidWeights(w_fill, w_tgt, w_fiss)) {
448 double fiss_frac = HighFrac(w_fill, w_tgt, w_fiss);
449 double fill_frac = LowFrac(w_fill, w_tgt, w_fiss);
450 fiss_frac =
451 AtomToMassFrac(fiss_frac, fiss.Peek()->comp(), fill.Peek()->comp());
452 fill_frac =
453 AtomToMassFrac(fill_frac, fill.Peek()->comp(), fiss.Peek()->comp());
454
455 double fissqty = fiss_frac * qty;
456 if (std::abs(fissqty - fiss.quantity()) < cyclus::eps_rsrc()) {
457 fissqty = std::min(fiss.quantity(), fiss_frac * qty);
458 }
459 double fillqty = fill_frac * qty;
460 if (std::abs(fillqty - fill.quantity()) < cyclus::eps_rsrc()) {
461 fillqty = std::min(fill.quantity(), fill_frac * qty);
462 }
463
464 Material::Ptr m = fiss.Pop(fissqty, cyclus::eps_rsrc());
465 // this if block prevents zero qty ResBuf pop exceptions
466 if (fill_frac > 0) {
467 m->Absorb(fill.Pop(fillqty, cyclus::eps_rsrc()));
468 }
469 responses.push_back(std::make_pair(trades[i], m));
470 } else {
471 double topup_frac = HighFrac(w_fiss, w_tgt, w_topup);
472 double fiss_frac = 1 - topup_frac;
473 topup_frac =
474 AtomToMassFrac(topup_frac, topup.Peek()->comp(), fiss.Peek()->comp());
475 fiss_frac =
476 AtomToMassFrac(fiss_frac, fiss.Peek()->comp(), topup.Peek()->comp());
477
478 double fissqty = fiss_frac * qty;
479 if (std::abs(fissqty - fiss.quantity()) < cyclus::eps_rsrc()) {
480 fissqty = std::min(fiss.quantity(), fiss_frac * qty);
481 }
482 double topupqty = topup_frac * qty;
483 if (std::abs(topupqty - topup.quantity()) < cyclus::eps_rsrc()) {
484 topupqty = std::min(topup.quantity(), topup_frac * qty);
485 }
486
487 Material::Ptr m = fiss.Pop(fissqty, cyclus::eps_rsrc());
488 // this if block prevents zero qty ResBuf pop exceptions
489 if (topup_frac > 0) {
490 m->Absorb(topup.Pop(topupqty, cyclus::eps_rsrc()));
491 }
492 responses.push_back(std::make_pair(trades[i], m));
493 }
494 }
495}
496
497extern "C" cyclus::Agent* ConstructFuelFab(cyclus::Context* ctx) {
498 return new FuelFab(ctx);
499}
500
501// Returns the weight of c using 1 group cross sections of type spectrum
502// which must be one of:
503//
504// * thermal
505// * thermal_maxwell_ave
506// * fission_spectrum_ave
507// * resonance_integral
508// * fourteen_MeV
509//
510// The weight is calculated as "(nu*sigma_f - sigma_a) * N". Since weights
511// are computed based on nuclide atom fractions, corresponding computed
512// material/mixing fractions will also be atom-based naturally and will need
513// to be converted to mass-based for actual material object mixing.
514double CosiWeight(Composition::Ptr c, const std::string& spectrum) {
515 cyclus::CompMap cm = c->atom();
516 cyclus::compmath::Normalize(&cm);
517
518 if (spectrum == "thermal") {
519 double nu_pu239 = 2.85;
520 double nu_u233 = 2.5;
521 double nu_u235 = 2.43;
522 double nu_u238 = 0;
523 double nu_pu241 = nu_pu239;
524
525 static std::map<int, double> absorb_xs;
526 static std::map<int, double> fiss_xs;
527 static double p_u238 = 0;
528 static double p_pu239 = 0;
529 if (p_u238 == 0) {
530 double fiss_u238 = simple_xs(922380000, "fission", "thermal");
531 double absorb_u238 = simple_xs(922380000, "absorption", "thermal");
532 p_u238 = nu_u238 * fiss_u238 - absorb_u238;
533
534 double fiss_pu239 = simple_xs(942390000, "fission", "thermal");
535 double absorb_pu239 = simple_xs(942390000, "absorption", "thermal");
536 p_pu239 = nu_pu239 * fiss_pu239 - absorb_pu239;
537 }
538
539 cyclus::CompMap::iterator it;
540 double w = 0;
541 for (it = cm.begin(); it != cm.end(); ++it) {
542 cyclus::Nuc nuc = it->first;
543 double nu = 0;
544 if (nuc == 922350000) {
545 nu = nu_u235;
546 } else if (nuc == 922330000) {
547 nu = nu_u233;
548 } else if (nuc == 942390000) {
549 nu = nu_pu239;
550 } else if (nuc == 942410000) {
551 nu = nu_pu241;
552 }
553
554 double fiss = 0;
555 double absorb = 0;
556 if (absorb_xs.count(nuc) == 0) {
557 try {
558 fiss = simple_xs(nuc, "fission", "thermal");
559 absorb = simple_xs(nuc, "absorption", "thermal");
560 absorb_xs[nuc] = absorb;
561 fiss_xs[nuc] = fiss;
562 } catch (pyne::InvalidSimpleXS err) {
563 fiss = 0;
564 absorb = 0;
565 }
566 } else {
567 fiss = fiss_xs[nuc];
568 absorb = absorb_xs[nuc];
569 }
570
571 double p = nu * fiss - absorb;
572 w += it->second * (p - p_u238) / (p_pu239 - p_u238);
573 }
574 return w;
575 } else if (spectrum == "fission_spectrum_ave") {
576 double nu_pu239 = 3.1;
577 double nu_u233 = 2.63;
578 double nu_u235 = 2.58;
579 double nu_u238 = 0;
580 double nu_pu241 = nu_pu239;
581
582 static std::map<int, double> absorb_xs;
583 static std::map<int, double> fiss_xs;
584 static double p_u238 = 0;
585 static double p_pu239 = 0;
586 if (p_u238 == 0) {
587 double fiss_u238 =
588 simple_xs(922380000, "fission", "fission_spectrum_ave");
589 double absorb_u238 =
590 simple_xs(922380000, "absorption", "fission_spectrum_ave");
591 p_u238 = nu_u238 * fiss_u238 - absorb_u238;
592
593 double fiss_pu239 =
594 simple_xs(942390000, "fission", "fission_spectrum_ave");
595 double absorb_pu239 =
596 simple_xs(942390000, "absorption", "fission_spectrum_ave");
597 p_pu239 = nu_pu239 * fiss_pu239 - absorb_pu239;
598 }
599
600 cyclus::CompMap::iterator it;
601 double w = 0;
602 for (it = cm.begin(); it != cm.end(); ++it) {
603 cyclus::Nuc nuc = it->first;
604 double nu = 0;
605 if (nuc == 922350000) {
606 nu = nu_u235;
607 } else if (nuc == 922330000) {
608 nu = nu_u233;
609 } else if (nuc == 942390000) {
610 nu = nu_pu239;
611 } else if (nuc == 942410000) {
612 nu = nu_pu241;
613 }
614
615 double fiss = 0;
616 double absorb = 0;
617 if (absorb_xs.count(nuc) == 0) {
618 try {
619 fiss = simple_xs(nuc, "fission", "fission_spectrum_ave");
620 absorb = simple_xs(nuc, "absorption", "fission_spectrum_ave");
621 absorb_xs[nuc] = absorb;
622 fiss_xs[nuc] = fiss;
623 } catch (pyne::InvalidSimpleXS err) {
624 fiss = 0;
625 absorb = 0;
626 }
627 } else {
628 fiss = fiss_xs[nuc];
629 absorb = absorb_xs[nuc];
630 }
631
632 double p = nu * fiss - absorb;
633 w += it->second * (p - p_u238) / (p_pu239 - p_u238);
634 }
635 return w;
636 } else {
637 double nu_pu239 = 3.1;
638 double nu_u233 = 2.63;
639 double nu_u235 = 2.58;
640 double nu_u238 = 0;
641 double nu_pu241 = nu_pu239;
642
643 double fiss_u238 = simple_xs(922380000, "fission", spectrum);
644 double absorb_u238 = simple_xs(922380000, "absorption", spectrum);
645 double p_u238 = nu_u238 * fiss_u238 - absorb_u238;
646
647 double fiss_pu239 = simple_xs(942390000, "fission", spectrum);
648 double absorb_pu239 = simple_xs(942390000, "absorption", spectrum);
649 double p_pu239 = nu_pu239 * fiss_pu239 - absorb_pu239;
650
651 cyclus::CompMap::iterator it;
652 double w = 0;
653 for (it = cm.begin(); it != cm.end(); ++it) {
654 cyclus::Nuc nuc = it->first;
655 double nu = 0;
656 if (nuc == 922350000) {
657 nu = nu_u235;
658 } else if (nuc == 922330000) {
659 nu = nu_u233;
660 } else if (nuc == 942390000) {
661 nu = nu_pu239;
662 } else if (nuc == 942410000) {
663 nu = nu_pu241;
664 }
665
666 double fiss = 0;
667 double absorb = 0;
668 try {
669 fiss = simple_xs(nuc, "fission", spectrum);
670 absorb = simple_xs(nuc, "absorption", spectrum);
671 } catch (pyne::InvalidSimpleXS err) {
672 fiss = 0;
673 absorb = 0;
674 }
675
676 double p = nu * fiss - absorb;
677 w += it->second * (p - p_u238) / (p_pu239 - p_u238);
678 }
679 return w;
680 }
681}
682
683// Convert an atom frac (n1/(n1+n2) to a mass frac (m1/(m1+m2) given
684// corresponding compositions c1 and c2.
685double AtomToMassFrac(double atomfrac, Composition::Ptr c1,
686 Composition::Ptr c2) {
687 cyclus::CompMap n1 = c1->atom();
688 cyclus::CompMap n2 = c2->atom();
689 cyclus::compmath::Normalize(&n1, atomfrac);
690 cyclus::compmath::Normalize(&n2, 1 - atomfrac);
691
692 cyclus::CompMap::iterator it;
693
694 double mass1 = 0;
695 for (it = n1.begin(); it != n1.end(); ++it) {
696 mass1 += it->second * pyne::atomic_mass(it->first);
697 }
698
699 double mass2 = 0;
700 for (it = n2.begin(); it != n2.end(); ++it) {
701 mass2 += it->second * pyne::atomic_mass(it->first);
702 }
703
704 return mass1 / (mass1 + mass2);
705}
706
707double HighFrac(double w_low, double w_target, double w_high, double eps) {
708 if (!ValidWeights(w_low, w_target, w_high)) {
709 throw cyclus::ValueError("low and high weights cannot meet target");
710 } else if (w_low == w_high && w_target == w_low) {
711 return 1;
712 }
713 double f = std::abs((w_target - w_low) / (w_high - w_low));
714 if (1 - f < eps) {
715 return 1;
716 } else if (f < eps) {
717 return 0;
718 }
719 return f;
720}
721
722double LowFrac(double w_low, double w_target, double w_high, double eps) {
723 return 1 - HighFrac(w_low, w_target, w_high, eps);
724}
725
726// Returns true if the given weights can be used to linearly interpolate valid
727// mixing fractions of the filler and fissile streams to hit the target.
728bool ValidWeights(double w_low, double w_target, double w_high) {
729 // w_tgt must be in between w_fill and w_fiss for the equivalence
730 // interpolation to work.
731 return w_low <= w_target && w_target <= w_high;
732}
733
734} // namespace cycamore
FillConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
virtual double convert(Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< Material > const *ctx=NULL) const
FissConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
virtual double convert(Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< Material > const *ctx=NULL) const
FuelFab takes in 2 streams of material and mixes them in ratios in order to supply material that matc...
FuelFab(cyclus::Context *ctx)
virtual void AcceptMatlTrades(const std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
cyclus::toolkit::ResBuf< cyclus::Material > fill
std::map< cyclus::Request< cyclus::Material > *, std::string > req_inventories_
virtual void GetMatlTrades(const std::vector< cyclus::Trade< cyclus::Material > > &trades, std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
virtual std::set< cyclus::RequestPortfolio< cyclus::Material >::Ptr > GetMatlRequests()
std::vector< double > fill_commod_prefs
virtual std::set< cyclus::BidPortfolio< cyclus::Material >::Ptr > GetMatlBids(cyclus::CommodMap< cyclus::Material >::type &commod_requests)
cyclus::toolkit::ResBuf< cyclus::Material > topup
cyclus::toolkit::ResBuf< cyclus::Material > fiss
std::vector< std::string > fiss_commods
std::vector< std::string > fill_commods
std::vector< double > fiss_commod_prefs
virtual double convert(Material::Ptr m, cyclus::Arc const *a=NULL, cyclus::ExchangeTranslationContext< Material > const *ctx=NULL) const
TopupConverter(Composition::Ptr c_fill, Composition::Ptr c_fiss, Composition::Ptr c_topup, std::string spectrum)
double HighFrac(double w_low, double w_target, double w_high, double eps)
double CosiWeight(Composition::Ptr c, const std::string &spectrum)
cyclus::Agent * ConstructFuelFab(cyclus::Context *ctx)
bool ValidWeights(double w_low, double w_target, double w_high)
double AtomToMassFrac(double atomfrac, Composition::Ptr c1, Composition::Ptr c2)
bool Contains(std::vector< std::string > vec, std::string s)
double LowFrac(double w_low, double w_target, double w_high, double eps)