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