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