CYCAMORE
Loading...
Searching...
No Matches
src/enrichment.cc
Go to the documentation of this file.
1// Implements the Enrichment class
2#include "enrichment.h"
3
4#include <algorithm>
5#include <cmath>
6#include <limits>
7#include <sstream>
8#include <vector>
9
10#include <boost/lexical_cast.hpp>
11
12using cyclus::Material;
13
14namespace cycamore {
15
16// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
17Enrichment::Enrichment(cyclus::Context* ctx)
18 : cyclus::Facility(ctx),
19 tails_assay(0),
20 swu_capacity(0),
21 max_enrich(1),
22 initial_feed(0),
23 feed_commod(""),
24 feed_recipe(""),
25 product_commod(""),
26 tails_commod(""),
27 order_prefs(true),
28 latitude(0.0),
29 longitude(0.0),
31
32// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33Enrichment::~Enrichment() {}
34
35// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36std::string Enrichment::str() {
37 std::stringstream ss;
38 ss << cyclus::Facility::str() << " with enrichment facility parameters:"
39 << " * SWU capacity: " << SwuCapacity()
40 << " * Tails assay: " << tails_assay << " * Feed assay: " << FeedAssay()
41 << " * Input cyclus::Commodity: " << feed_commod
42 << " * Output cyclus::Commodity: " << product_commod
43 << " * Tails cyclus::Commodity: " << tails_commod;
44 return ss.str();
45}
46
47// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
48void Enrichment::Build(cyclus::Agent* parent) {
49 Facility::Build(parent);
50 if (initial_feed > 0) {
51 inventory.Push(Material::Create(this, initial_feed,
52 context()->GetRecipe(feed_recipe)));
53 }
54
55 LOG(cyclus::LEV_DEBUG2, "EnrFac") << "Enrichment "
56 << " entering the simuluation: ";
57 LOG(cyclus::LEV_DEBUG2, "EnrFac") << str();
59}
60
61// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62void Enrichment::Tick() {
63 current_swu_capacity = SwuCapacity();
64
65}
66
67// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68void Enrichment::Tock() {
69 using cyclus::toolkit::RecordTimeSeries;
70 LOG(cyclus::LEV_INFO4, "EnrFac") << prototype() << " used "
71 << intra_timestep_swu_ << " SWU";
72 RecordTimeSeries<cyclus::toolkit::ENRICH_SWU>(this, intra_timestep_swu_);
73 LOG(cyclus::LEV_INFO4, "EnrFac") << prototype() << " used "
74 << intra_timestep_feed_ << " feed";
75 RecordTimeSeries<cyclus::toolkit::ENRICH_FEED>(this, intra_timestep_feed_);
76 RecordTimeSeries<double>("demand"+feed_commod, this, intra_timestep_feed_);
77}
78
79// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
80std::set<cyclus::RequestPortfolio<Material>::Ptr>
81Enrichment::GetMatlRequests() {
82 using cyclus::RequestPortfolio;
83
84 std::set<RequestPortfolio<Material>::Ptr> ports;
85 RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
86 Material::Ptr mat = Request_();
87 double amt = mat->quantity();
88
89 if (amt > cyclus::eps_rsrc()) {
90 port->AddRequest(mat, this, feed_commod);
91 ports.insert(port);
92 }
93
94 return ports;
95}
96
97// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98bool SortBids(cyclus::Bid<Material>* i,
99 cyclus::Bid<Material>* j) {
100 Material::Ptr mat_i = i->offer();
101 Material::Ptr mat_j = j->offer();
102
103 cyclus::toolkit::MatQuery mq_i(mat_i);
104 cyclus::toolkit::MatQuery mq_j(mat_j);
105
106 return ((mq_i.mass(922350000) / mq_i.qty()) <=
107 (mq_j.mass(922350000) / mq_j.qty()));
108}
109// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110// Sort offers of input material to have higher preference for more
111// U-235 content
112void Enrichment::AdjustMatlPrefs(
113 cyclus::PrefMap<Material>::type& prefs) {
114 using cyclus::Bid;
115
116 if (order_prefs == false) {
117 return;
118 }
119
120 cyclus::PrefMap<Material>::type::iterator reqit;
121
122 // Loop over all requests
123 for (reqit = prefs.begin(); reqit != prefs.end(); ++reqit) {
124 std::vector<Bid<Material>*> bids_vector;
125 std::map<Bid<Material>*, double>::iterator mit;
126 for (mit = reqit->second.begin(); mit != reqit->second.end(); ++mit) {
127 Bid<Material>* bid = mit->first;
128 bids_vector.push_back(bid);
129 }
130 std::sort(bids_vector.begin(), bids_vector.end(), SortBids);
131
132 // Assign preferences to the sorted vector
133 double n_bids = bids_vector.size();
134 bool u235_mass = 0;
135
136 for (int bidit = 0; bidit < bids_vector.size(); bidit++) {
137 int new_pref = bidit + 1;
138
139 // For any bids with U-235 qty=0, set pref to zero.
140 if (!u235_mass) {
141 Material::Ptr mat = bids_vector[bidit]->offer();
142 cyclus::toolkit::MatQuery mq(mat);
143 if (mq.mass(922350000) == 0) {
144 new_pref = -1;
145 } else {
146 u235_mass = true;
147 }
148 }
149 (reqit->second)[bids_vector[bidit]] = new_pref;
150 } // each bid
151 } // each Material Request
152}
153
154// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155void Enrichment::AcceptMatlTrades(
156 const std::vector<std::pair<cyclus::Trade<Material>,
157 Material::Ptr> >& responses) {
158 // see
159 // http://stackoverflow.com/questions/5181183/boostshared-ptr-and-inheritance
160 std::vector<std::pair<cyclus::Trade<Material>,
161 Material::Ptr> >::const_iterator it;
162 for (it = responses.begin(); it != responses.end(); ++it) {
163 AddMat_(it->second);
164 }
165}
166
167// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
168std::set<cyclus::BidPortfolio<Material>::Ptr> Enrichment::GetMatlBids(
169 cyclus::CommodMap<Material>::type& out_requests) {
170 using cyclus::BidPortfolio;
171 using cyclus::CapacityConstraint;
172 using cyclus::Converter;
173 using cyclus::Request;
174 using cyclus::toolkit::MatVec;
175 using cyclus::toolkit::RecordTimeSeries;
176
177 std::set<BidPortfolio<Material>::Ptr> ports;
178
179 RecordTimeSeries<double>("supply" + tails_commod, this, tails.quantity());
180 RecordTimeSeries<double>("supply" + product_commod, this, inventory.quantity());
181 if ((out_requests.count(tails_commod) > 0) && (tails.quantity() > 0)) {
182 BidPortfolio<Material>::Ptr tails_port(new BidPortfolio<Material>());
183
184 std::vector<Request<Material>*>& tails_requests =
185 out_requests[tails_commod];
186 std::vector<Request<Material>*>::iterator it;
187 for (it = tails_requests.begin(); it != tails_requests.end(); ++it) {
188 // offer bids for all tails material, keeping discrete quantities
189 // to preserve possible variation in composition
190 MatVec mats = tails.PopN(tails.count());
191 tails.Push(mats);
192 for (int k = 0; k < mats.size(); k++) {
193 Material::Ptr m = mats[k];
194 Request<Material>* req = *it;
195 tails_port->AddBid(req, m, this);
196 }
197 }
198 // overbidding (bidding on every offer)
199 // add an overall capacity constraint
200 CapacityConstraint<Material> tails_constraint(tails.quantity());
201 tails_port->AddConstraint(tails_constraint);
202 LOG(cyclus::LEV_INFO5, "EnrFac") << prototype()
203 << " adding tails capacity constraint of "
204 << tails.capacity();
205 ports.insert(tails_port);
206 }
207
208 if ((out_requests.count(product_commod) > 0) && (inventory.quantity() > 0)) {
209 BidPortfolio<Material>::Ptr commod_port(new BidPortfolio<Material>());
210
211 std::vector<Request<Material>*>& commod_requests =
212 out_requests[product_commod];
213 std::vector<Request<Material>*>::iterator it;
214 for (it = commod_requests.begin(); it != commod_requests.end(); ++it) {
215 Request<Material>* req = *it;
216 Material::Ptr mat = req->target();
217 double request_enrich = cyclus::toolkit::UraniumAssayMass(mat);
218 if (ValidReq(req->target()) &&
219 ((request_enrich < max_enrich) ||
220 (cyclus::AlmostEq(request_enrich, max_enrich)))) {
221 Material::Ptr offer = Offer_(req->target());
222 commod_port->AddBid(req, offer, this);
223 }
224 }
225
226 Converter<Material>::Ptr sc(new SWUConverter(FeedAssay(), tails_assay));
227 Converter<Material>::Ptr nc(new NatUConverter(FeedAssay(), tails_assay));
228 CapacityConstraint<Material> swu(swu_capacity, sc);
229 CapacityConstraint<Material> natu(inventory.quantity(), nc);
230 commod_port->AddConstraint(swu);
231 commod_port->AddConstraint(natu);
232
233 LOG(cyclus::LEV_INFO5, "EnrFac")
234 << prototype() << " adding a swu constraint of " << swu.capacity();
235 LOG(cyclus::LEV_INFO5, "EnrFac")
236 << prototype() << " adding a natu constraint of " << natu.capacity();
237 ports.insert(commod_port);
238 }
239 return ports;
240}
241
242// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
243bool Enrichment::ValidReq(const Material::Ptr mat) {
244 cyclus::toolkit::MatQuery q(mat);
245 double u235 = q.atom_frac(922350000);
246 double u238 = q.atom_frac(922380000);
247 return (u238 > 0 && u235 / (u235 + u238) > tails_assay);
248}
249
250// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
251void Enrichment::GetMatlTrades(
252 const std::vector<cyclus::Trade<Material> >& trades,
253 std::vector<std::pair<cyclus::Trade<Material>,
254 Material::Ptr> >& responses) {
255 using cyclus::Trade;
256
257 intra_timestep_swu_ = 0;
258 intra_timestep_feed_ = 0;
259
260 std::vector<Trade<Material>>::const_iterator it;
261 for (it = trades.begin(); it != trades.end(); ++it) {
262 double qty = it->amt;
263 std::string commod_type = it->bid->request()->commodity();
264 Material::Ptr response;
265 // Figure out whether material is tails or enriched,
266 // if tails then make transfer of material
267 if (commod_type == tails_commod) {
268 LOG(cyclus::LEV_INFO5, "EnrFac")
269 << prototype() << " just received an order"
270 << " for " << it->amt << " of " << tails_commod;
271 double pop_qty = std::min(qty, tails.quantity());
272 response = tails.Pop(pop_qty, cyclus::eps_rsrc());
273 } else {
274 LOG(cyclus::LEV_INFO5, "EnrFac")
275 << prototype() << " just received an order"
276 << " for " << it->amt << " of " << product_commod;
277 response = Enrich_(it->bid->offer(), qty);
278 }
279 responses.push_back(std::make_pair(*it, response));
280 }
281
282 if (cyclus::IsNegative(tails.quantity())) {
283 std::stringstream ss;
284 ss << "is being asked to provide more than its current inventory.";
285 throw cyclus::ValueError(Agent::InformErrorMsg(ss.str()));
286 }
287 if (cyclus::IsNegative(current_swu_capacity)) {
288 throw cyclus::ValueError("EnrFac " + prototype() +
289 " is being asked to provide more than" +
290 " its SWU capacity.");
291 }
292
293}
294// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
295void Enrichment::AddMat_(Material::Ptr mat) {
296 // Elements and isotopes other than U-235, U-238 are sent directly to tails
297 cyclus::CompMap cm = mat->comp()->atom();
298 bool extra_u = false;
299 bool other_elem = false;
300 for (cyclus::CompMap::const_iterator it = cm.begin(); it != cm.end(); ++it) {
301 if (pyne::nucname::znum(it->first) == 92) {
302 if (pyne::nucname::anum(it->first) != 235 &&
303 pyne::nucname::anum(it->first) != 238 && it->second > 0) {
304 extra_u = true;
305 }
306 } else if (it->second > 0) {
307 other_elem = true;
308 }
309 }
310 if (extra_u) {
311 cyclus::Warn<cyclus::VALUE_WARNING>(
312 "More than 2 isotopes of U. "
313 "Istopes other than U-235, U-238 are sent directly to tails.");
314 }
315 if (other_elem) {
316 cyclus::Warn<cyclus::VALUE_WARNING>(
317 "Non-uranium elements are "
318 "sent directly to tails.");
319 }
320
321 LOG(cyclus::LEV_INFO5, "EnrFac") << prototype() << " is initially holding "
322 << inventory.quantity() << " total.";
323
324 try {
325 inventory.Push(mat);
326 } catch (cyclus::Error& e) {
327 e.msg(Agent::InformErrorMsg(e.msg()));
328 throw e;
329 }
330
331 LOG(cyclus::LEV_INFO5, "EnrFac")
332 << prototype() << " added " << mat->quantity() << " of " << feed_commod
333 << " to its inventory, which is holding " << inventory.quantity()
334 << " total.";
335}
336
337// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
338Material::Ptr Enrichment::Request_() {
339 double qty = std::max(0.0, inventory.capacity() - inventory.quantity());
340 return Material::CreateUntracked(qty,
341 context()->GetRecipe(feed_recipe));
342}
343
344// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
345Material::Ptr Enrichment::Offer_(Material::Ptr mat) {
346 cyclus::toolkit::MatQuery q(mat);
347 cyclus::CompMap comp;
348 comp[922350000] = q.atom_frac(922350000);
349 comp[922380000] = q.atom_frac(922380000);
350 return Material::CreateUntracked(
351 mat->quantity(), cyclus::Composition::CreateFromAtom(comp));
352}
353// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
354Material::Ptr Enrichment::Enrich_(Material::Ptr mat,
355 double qty) {
356 using cyclus::toolkit::Assays;
357 using cyclus::toolkit::UraniumAssayMass;
358 using cyclus::toolkit::SwuRequired;
359 using cyclus::toolkit::FeedQty;
360 using cyclus::toolkit::TailsQty;
361
362 // get enrichment parameters
363 Assays assays(FeedAssay(), UraniumAssayMass(mat), tails_assay);
364 double swu_req = SwuRequired(qty, assays);
365 double natu_req = FeedQty(qty, assays);
366
367 // Determine the composition of the natural uranium
368 // (ie. U-235+U-238/TotalMass)
369 double pop_qty = inventory.quantity();
370 Material::Ptr natu_matl = inventory.Pop(pop_qty, cyclus::eps_rsrc());
371 inventory.Push(natu_matl);
372
373 cyclus::toolkit::MatQuery mq(natu_matl);
374 std::set<cyclus::Nuc> nucs;
375 nucs.insert(922350000);
376 nucs.insert(922380000);
377 double natu_frac = mq.mass_frac(nucs);
378 double feed_req = natu_req / natu_frac;
379
380 // pop amount from inventory and blob it into one material
381 Material::Ptr r;
382 try {
383 // required so popping doesn't take out too much
384 if (cyclus::AlmostEq(feed_req, inventory.quantity())) {
385 r = cyclus::toolkit::Squash(inventory.PopN(inventory.count()));
386 } else {
387 r = inventory.Pop(feed_req, cyclus::eps_rsrc());
388 }
389 } catch (cyclus::Error& e) {
390 NatUConverter nc(FeedAssay(), tails_assay);
391 std::stringstream ss;
392 ss << " tried to remove " << feed_req << " from its inventory of size "
393 << inventory.quantity()
394 << " and the conversion of the material into natu is "
395 << nc.convert(mat);
396 throw cyclus::ValueError(Agent::InformErrorMsg(ss.str()));
397 }
398
399 // "enrich" it, but pull out the composition and quantity we require from the
400 // blob
401 cyclus::Composition::Ptr comp = mat->comp();
402 Material::Ptr response = r->ExtractComp(qty, comp);
403 tails.Push(r);
404
405 current_swu_capacity -= swu_req;
406
407 intra_timestep_swu_ += swu_req;
408 intra_timestep_feed_ += feed_req;
409 RecordEnrichment_(feed_req, swu_req);
410
411 LOG(cyclus::LEV_INFO5, "EnrFac") << prototype()
412 << " has performed an enrichment: ";
413 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Feed Qty: " << feed_req;
414 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Feed Assay: "
415 << assays.Feed() * 100;
416 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Product Qty: " << qty;
417 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Product Assay: "
418 << assays.Product() * 100;
419 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Tails Qty: "
420 << TailsQty(qty, assays);
421 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Tails Assay: "
422 << assays.Tails() * 100;
423 LOG(cyclus::LEV_INFO5, "EnrFac") << " * SWU: " << swu_req;
424 LOG(cyclus::LEV_INFO5, "EnrFac") << " * Current SWU capacity: "
425 << current_swu_capacity;
426
427 return response;
428}
429
430// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
431void Enrichment::RecordEnrichment_(double natural_u, double swu) {
432 using cyclus::Context;
433 using cyclus::Agent;
434
435 LOG(cyclus::LEV_DEBUG1, "EnrFac") << prototype()
436 << " has enriched a material:";
437 LOG(cyclus::LEV_DEBUG1, "EnrFac") << " * Amount: " << natural_u;
438 LOG(cyclus::LEV_DEBUG1, "EnrFac") << " * SWU: " << swu;
439
440 Context* ctx = Agent::context();
441 ctx->NewDatum("Enrichments")
442 ->AddVal("AgentId", id())
443 ->AddVal("Time", ctx->time())
444 ->AddVal("Natural_Uranium", natural_u)
445 ->AddVal("SWU", swu)
446 ->Record();
447}
448// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
449double Enrichment::FeedAssay() {
450 if (inventory.empty()) {
451 return 0;
452 }
453 double pop_qty = inventory.quantity();
454 Material::Ptr fission_matl =
455 inventory.Pop(pop_qty, cyclus::eps_rsrc());
456 inventory.Push(fission_matl);
457 return cyclus::toolkit::UraniumAssayMass(fission_matl);
458}
459
460// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
461void Enrichment::RecordPosition() {
462 std::string specification = this->spec();
463 context()
464 ->NewDatum("AgentPosition")
465 ->AddVal("Spec", specification)
466 ->AddVal("Prototype", this->prototype())
467 ->AddVal("AgentId", id())
468 ->AddVal("Latitude", latitude)
469 ->AddVal("Longitude", longitude)
470 ->Record();
471}
472
473// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
474extern "C" cyclus::Agent* ConstructEnrichment(cyclus::Context* ctx) {
475 return new Enrichment(ctx);
476}
477
478} // namespace cycamore
Enrichment(cyclus::Context *ctx)
Constructor for the Enrichment class.
void RecordPosition()
Records an agent's latitude and longitude to the output db.
cyclus::Agent * ConstructEnrichment(cyclus::Context *ctx)
cyclus::toolkit::Position coordinates
bool SortBids(cyclus::Bid< Material > *i, cyclus::Bid< Material > *j)