CYCAMORE
Loading...
Searching...
No Matches
build/cycamore/separations.cc
Go to the documentation of this file.
1
2#line 1 "/cycamore/src/separations.cc"
3#include "separations.h"
4
5using cyclus::Material;
6using cyclus::Composition;
7using cyclus::toolkit::ResBuf;
8using cyclus::toolkit::MatVec;
9using cyclus::Request;
10
11namespace cycamore {
12
13Separations::Separations(cyclus::Context* ctx)
14 : cyclus::Facility(ctx),
15 latitude(0.0),
16 longitude(0.0),
18
19cyclus::Inventories Separations::SnapshotInv() {
20 cyclus::Inventories invs;
21
22 // these inventory names are intentionally convoluted so as to not clash
23 // with the user-specified stream commods that are used as the separations
24 // streams inventory names.
25 invs["leftover-inv-name"] = leftover.PopNRes(leftover.count());
26 leftover.Push(invs["leftover-inv-name"]);
27 invs["feed-inv-name"] = feed.PopNRes(feed.count());
28 feed.Push(invs["feed-inv-name"]);
29
30 std::map<std::string, ResBuf<Material> >::iterator it;
31 for (it = streambufs.begin(); it != streambufs.end(); ++it) {
32 invs[it->first] = it->second.PopNRes(it->second.count());
33 it->second.Push(invs[it->first]);
34 }
35
36 return invs;
37}
38
39void Separations::InitInv(cyclus::Inventories& inv) {
40 leftover.Push(inv["leftover-inv-name"]);
41 feed.Push(inv["feed-inv-name"]);
42
43 cyclus::Inventories::iterator it;
44 for (it = inv.begin(); it != inv.end(); ++it) {
45 streambufs[it->first].Push(it->second);
46 }
47}
48
49typedef std::pair<double, std::map<int, double> > Stream;
50typedef std::map<std::string, Stream> StreamSet;
51
53 cyclus::Facility::EnterNotify();
54 std::map<int, double> efficiency_;
55
56 StreamSet::iterator it;
57 std::map<int, double>::iterator it2;
58
59 for (it = streams_.begin(); it != streams_.end(); ++it) {
60 std::string name = it->first;
61 Stream stream = it->second;
62 double cap = stream.first;
63 if (cap >= 0) {
64 streambufs[name].capacity(cap);
65 }
66
67 for (it2 = stream.second.begin(); it2 != stream.second.end(); it2++) {
68 efficiency_[it2->first] += it2->second;
69 }
71 }
72
73 std::vector<int> eff_pb_;
74 for (it2 = efficiency_.begin(); it2 != efficiency_.end(); it2++) {
75 if (it2->second > 1) {
76 eff_pb_.push_back(it2->first);
77 }
78 }
79
80 if (eff_pb_.size() > 0) {
81 std::stringstream ss;
82 ss << "In " << prototype() << ", ";
83 ss << "the following nuclide(s) have a cumulative separation efficiency "
84 "greater than 1:";
85 for (int i = 0; i < eff_pb_.size(); i++) {
86 ss << "\n " << eff_pb_[i];
87 if (i < eff_pb_.size() - 1) {
88 ss << ",";
89 } else {
90 ss << ".";
91 }
92 }
93
94 throw cyclus::ValueError(ss.str());
95 }
96
97 if (feed_commod_prefs.size() == 0) {
98 for (int i = 0; i < feed_commods.size(); i++) {
99 feed_commod_prefs.push_back(cyclus::kDefaultPref);
100 }
101 }
102}
103
105 using cyclus::toolkit::RecordTimeSeries;
106 if (feed.count() == 0) {
107 return;
108 }
109 double pop_qty = std::min(throughput, feed.quantity());
110 Material::Ptr mat = feed.Pop(pop_qty, cyclus::eps_rsrc());
111 double orig_qty = mat->quantity();
112
113 StreamSet::iterator it;
114 double maxfrac = 1;
115 std::map<std::string, Material::Ptr> stagedsep;
116 Record("Separating", orig_qty, "feed");
117 for (it = streams_.begin(); it != streams_.end(); ++it) {
118 Stream info = it->second;
119 std::string name = it->first;
120 stagedsep[name] = SepMaterial(info.second, mat);
121 double frac = streambufs[name].space() / stagedsep[name]->quantity();
122 if (frac < maxfrac) {
123 maxfrac = frac;
124 }
125 }
126
127 std::map<std::string, Material::Ptr>::iterator itf;
128 for (itf = stagedsep.begin(); itf != stagedsep.end(); ++itf) {
129 std::string name = itf->first;
130 Material::Ptr m = itf->second;
131 if (m->quantity() > 0) {
132 double qty = m->quantity();
133 if (m->quantity() > mat->quantity()) {
134 qty = mat->quantity();
135 }
136 streambufs[name].Push(
137 mat->ExtractComp(qty * maxfrac, m->comp()));
138 Record("Separated", qty * maxfrac, name);
139 }
140 cyclus::toolkit::RecordTimeSeries<double>("supply"+name, this,
141 streambufs[name].quantity());
142 }
143
144 if (maxfrac == 1) {
145 if (mat->quantity() > 0) {
146 // unspecified separations fractions go to leftovers
147 leftover.Push(mat);
148 }
149 } else { // maxfrac is < 1
150 // push back any leftover feed due to separated stream inv size constraints
151
152 feed.Push(mat->ExtractQty((1 - maxfrac) * orig_qty));
153 if (mat->quantity() > 0) {
154 // unspecified separations fractions go to leftovers
155 leftover.Push(mat);
156 }
157 }
158 cyclus::toolkit::RecordTimeSeries<double>("supply"+leftover_commod, this,
159 leftover.quantity());
160
161}
162
163// Note that this returns an untracked material that should just be used for
164// its composition and qty - not in any real inventories, etc.
165Material::Ptr SepMaterial(std::map<int, double> effs, Material::Ptr mat) {
166 using cyclus::CompMap;
167
168 CompMap cm = mat->comp()->mass();
169 cyclus::compmath::Normalize(&cm, mat->quantity());
170 double tot_qty = 0;
171 CompMap sepcomp;
172
173 CompMap::iterator it;
174 for (it = cm.begin(); it != cm.end(); ++it) {
175 int nuc = it->first;
176 int elem = (nuc / 10000000) * 10000000;
177 double eff = 0;
178 if (effs.count(nuc) > 0) {
179 eff = effs[nuc];
180 } else if (effs.count(elem) > 0) {
181 eff = effs[elem];
182 } else {
183 continue;
184 }
185
186 double qty = it->second;
187 double sepqty = qty * eff;
188 sepcomp[nuc] = sepqty;
189 tot_qty += sepqty;
190 }
191
192 Composition::Ptr c = Composition::CreateFromMass(sepcomp);
193 return Material::CreateUntracked(tot_qty, c);
194};
195
196std::set<cyclus::RequestPortfolio<Material>::Ptr>
198 using cyclus::RequestPortfolio;
199 using cyclus::toolkit::RecordTimeSeries;
200 std::set<RequestPortfolio<Material>::Ptr> ports;
201
202 int t = context()->time();
203 int t_exit = exit_time();
204
205 // record demand of highest-preferred commodity
206 std::vector<double>::iterator result;
207 result = std::max_element(feed_commod_prefs.begin(), feed_commod_prefs.end());
208 int maxindx = std::distance(feed_commod_prefs.begin(), result);
209 cyclus::toolkit::RecordTimeSeries<double>("demand"+feed_commods[maxindx],
210 this, feed.space());
211 if (t_exit >= 0 && (feed.quantity() >= (t_exit - t) * throughput)) {
212 return ports; // already have enough feed for remainder of life
213 } else if (feed.space() < cyclus::eps_rsrc()) {
214 return ports;
215 }
216
217 bool exclusive = false;
218 RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
219
220 Material::Ptr m = cyclus::NewBlankMaterial(feed.space());
221 if (!feed_recipe.empty()) {
222 Composition::Ptr c = context()->GetRecipe(feed_recipe);
223 m = Material::CreateUntracked(feed.space(), c);
224 }
225
226 std::vector<Request<Material>*> reqs;
227 for (int i = 0; i < feed_commods.size(); i++) {
228 std::string commod = feed_commods[i];
229 double pref = feed_commod_prefs[i];
230 reqs.push_back(port->AddRequest(m, this, commod, pref, exclusive));
231 }
232 port->AddMutualReqs(reqs);
233 ports.insert(port);
234
235 return ports;
236}
237
239 const std::vector<cyclus::Trade<Material> >& trades,
240 std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
241 responses) {
242 using cyclus::Trade;
243
244 std::vector<Trade<Material> >::const_iterator it;
245 for (int i = 0; i < trades.size(); i++) {
246 std::string commod = trades[i].request->commodity();
247 if (commod == leftover_commod) {
248 double amt = std::min(leftover.quantity(), trades[i].amt);
249 Material::Ptr m = leftover.Pop(amt, cyclus::eps_rsrc());
250 responses.push_back(std::make_pair(trades[i], m));
251 } else if (streambufs.count(commod) > 0) {
252 double amt = std::min(streambufs[commod].quantity(), trades[i].amt);
253 Material::Ptr m = streambufs[commod].Pop(amt, cyclus::eps_rsrc());
254 responses.push_back(std::make_pair(trades[i], m));
255 } else {
256 throw cyclus::ValueError("invalid commodity " + commod +
257 " on trade matched to prototype " + prototype());
258 }
259 }
260}
261
263 const std::vector<std::pair<cyclus::Trade<Material>, Material::Ptr> >&
264 responses) {
265 std::vector<std::pair<cyclus::Trade<Material>,
266 Material::Ptr> >::const_iterator trade;
267
268 for (trade = responses.begin(); trade != responses.end(); ++trade) {
269 feed.Push(trade->second);
270 }
271}
272
273std::set<cyclus::BidPortfolio<Material>::Ptr> Separations::GetMatlBids(
274 cyclus::CommodMap<Material>::type& commod_requests) {
275 using cyclus::BidPortfolio;
276 bool exclusive = false;
277 std::set<BidPortfolio<Material>::Ptr> ports;
278
279 // bid streams
280 std::map<std::string, ResBuf<Material> >::iterator it;
281 for (it = streambufs.begin(); it != streambufs.end(); ++it) {
282 std::string commod = it->first;
283 std::vector<Request<Material>*>& reqs = commod_requests[commod];
284 if (reqs.size() == 0) {
285 continue;
286 } else if (streambufs[commod].quantity() < cyclus::eps_rsrc()) {
287 continue;
288 }
289
290 MatVec mats = streambufs[commod].PopN(streambufs[commod].count());
291 streambufs[commod].Push(mats);
292
293 BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());
294
295 for (int j = 0; j < reqs.size(); j++) {
296 Request<Material>* req = reqs[j];
297 double tot_bid = 0;
298 for (int k = 0; k < mats.size(); k++) {
299 Material::Ptr m = mats[k];
300 tot_bid += m->quantity();
301
302 // this fix the problem of the cyclus exchange manager which crashes
303 // when a bid with a quantity <=0 is offered.
304 if (m->quantity() > cyclus::eps_rsrc()) {
305 port->AddBid(req, m, this, exclusive);
306 }
307
308 if (tot_bid >= req->target()->quantity()) {
309 break;
310 }
311 }
312 }
313
314 double tot_qty = streambufs[commod].quantity();
315 cyclus::CapacityConstraint<Material> cc(tot_qty);
316 port->AddConstraint(cc);
317 ports.insert(port);
318 }
319
320 // bid leftovers
321 std::vector<Request<Material>*>& reqs = commod_requests[leftover_commod];
322 if (reqs.size() > 0 && leftover.quantity() >= cyclus::eps_rsrc()) {
323 MatVec mats = leftover.PopN(leftover.count());
324 leftover.Push(mats);
325
326 BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());
327
328 for (int j = 0; j < reqs.size(); j++) {
329 Request<Material>* req = reqs[j];
330 double tot_bid = 0;
331 for (int k = 0; k < mats.size(); k++) {
332 Material::Ptr m = mats[k];
333 tot_bid += m->quantity();
334
335 // this fix the problem of the cyclus exchange manager which crashes
336 // when a bid with a quantity <=0 is offered.
337 if (m->quantity() > cyclus::eps_rsrc()) {
338 port->AddBid(req, m, this, exclusive);
339 }
340
341 if (tot_bid >= req->target()->quantity()) {
342 break;
343 }
344 }
345 }
346
347 cyclus::CapacityConstraint<Material> cc(leftover.quantity());
348 port->AddConstraint(cc);
349 ports.insert(port);
350 }
351
352 return ports;
353}
354
356
358 if (leftover.count() > 0) {
359 return false;
360 }
361
362 std::map<std::string, ResBuf<Material> >::iterator it;
363 for (it = streambufs.begin(); it != streambufs.end(); ++it) {
364 if (it->second.count() > 0) {
365 return false;
366 }
367 }
368
369 return true;
370}
371
373 std::string specification = this->spec();
374 context()
375 ->NewDatum("AgentPosition")
376 ->AddVal("Spec", specification)
377 ->AddVal("Prototype", this->prototype())
378 ->AddVal("AgentId", id())
379 ->AddVal("Latitude", latitude)
380 ->AddVal("Longitude", longitude)
381 ->Record();
382}
383
384void Separations::Record(std::string name, double val, std::string type) {
385 context()
386 ->NewDatum("SeparationEvents")
387 ->AddVal("AgentId", id())
388 ->AddVal("Time", context()->time())
389 ->AddVal("Event", name)
390 ->AddVal("Value", val)
391 ->AddVal("Type", type)
392 ->Record();
393}
394
395extern "C" cyclus::Agent* ConstructSeparations(cyclus::Context* ctx) {
396 return new Separations(ctx);
397}
398
399} // namespace cycamore
Separations processes feed material into one or more streams containing specific elements and/or nucl...
std::map< std::string, std::pair< double, std::map< int, double > > > streams_
virtual void GetMatlTrades(const std::vector< cyclus::Trade< cyclus::Material > > &trades, std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
virtual void AcceptMatlTrades(const std::vector< std::pair< cyclus::Trade< cyclus::Material >, cyclus::Material::Ptr > > &responses)
cyclus::toolkit::ResBuf< cyclus::Material > feed
virtual std::set< cyclus::RequestPortfolio< cyclus::Material >::Ptr > GetMatlRequests()
virtual cyclus::Inventories SnapshotInv()
virtual void InitInv(cyclus::Inventories &inv)
cyclus::toolkit::ResBuf< cyclus::Material > leftover
std::map< std::string, cyclus::toolkit::ResBuf< cyclus::Material > > streambufs
void Record(std::string name, double val, std::string type)
std::vector< double > feed_commod_prefs
void RecordPosition()
Records an agent's latitude and longitude to the output db.
virtual std::set< cyclus::BidPortfolio< cyclus::Material >::Ptr > GetMatlBids(cyclus::CommodMap< cyclus::Material >::type &commod_requests)
std::vector< std::string > feed_commods
Separations(cyclus::Context *ctx)
Material::Ptr SepMaterial(std::map< int, double > effs, Material::Ptr mat)
std::pair< double, std::map< int, double > > Stream
std::map< std::string, Stream > StreamSet
cyclus::toolkit::Position coordinates
cyclus::Agent * ConstructSeparations(cyclus::Context *ctx)