• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cyclus / cyclus / 15572793570

11 Jun 2025 12:02AM UTC coverage: 41.172% (-0.001%) from 41.173%
15572793570

push

github

web-flow
Merge pull request #1858 from gonuke/fix_rng_print

Fix rng print

51779 of 125762 relevant lines covered (41.17%)

16949.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.53
/src/xml_file_loader.cc
1
// Implements file reader for an XML format
2
#include "xml_file_loader.h"
3

4
#include <algorithm>
5
#include <fstream>
6
#include <set>
7
#include <streambuf>
8

9
#include <boost/filesystem.hpp>
10
#include <libxml++/libxml++.h>
11

12
#include "agent.h"
13
#include "blob.h"
14
#include "context.h"
15
#include "cyc_std.h"
16
#include "discovery.h"
17
#include "env.h"
18
#include "error.h"
19
#include "exchange_solver.h"
20
#include "greedy_preconditioner.h"
21
#include "greedy_solver.h"
22
#include "infile_tree.h"
23
#include "logger.h"
24
#include "sim_init.h"
25
#include "toolkit/infile_converters.h"
26

27
namespace cyclus {
28

29
namespace fs = boost::filesystem;
30

31
void LoadRawStringstreamFromFile(std::stringstream& stream, std::string file) {
936✔
32
  std::ifstream file_stream(file.c_str());
936✔
33
  if (!file_stream) {
936✔
34
    throw IOError("The file '" + file + "' could not be loaded.");
2✔
35
  }
36

37
  stream << file_stream.rdbuf();
935✔
38
  file_stream.close();
935✔
39
}
936✔
40

41
void LoadStringstreamFromFile(std::stringstream& stream, std::string file, std::string format) {
937✔
42
  std::string inext;
43
  if (format == "none") {
937✔
44
    LoadRawStringstreamFromFile(stream, file);
1,871✔
45
    inext = fs::path(file).extension().string();
2,768✔
46
  } else {
47
    stream << file;
1✔
48
  }
49
  if (inext == ".json" || format == "json") {
1,776✔
50
    std::string inxml = cyclus::toolkit::JsonToXml(stream.str());
192✔
51
    stream.str(inxml);
52
  } else if (inext == ".py" || format == "py") {
1,648✔
53
    std::string inxml = cyclus::toolkit::PyToXml(stream.str());
65✔
54
    stream.str(inxml);
55
  }
56
}
936✔
57

58
std::string LoadStringFromFile(std::string file, std::string format) {
2✔
59
  std::stringstream input;
2✔
60
  LoadStringstreamFromFile(input, file, format);
4✔
61
  return input.str();
2✔
62
}
2✔
63

64
std::vector<AgentSpec> ParseSpecs(std::set<std::string> agent_set) {
372✔
65

66
  std::vector<AgentSpec> specs;
67

68
  for (const std::string& spec_str : agent_set) {
1,554✔
69
    specs.push_back(AgentSpec(spec_str));
3,374✔
70
  }
71

72
  return specs;
372✔
73
}
×
74

75
std::vector<AgentSpec> ParseSpecs(std::string infile, std::string format) {
372✔
76
  std::stringstream input;
372✔
77
  LoadStringstreamFromFile(input, infile, format);
744✔
78
  XMLParser parser_;
372✔
79
  parser_.Init(input);
372✔
80
  InfileTree xqe(parser_);
372✔
81

82
  std::set<std::string> unique;
83

84
  std::string p = "/simulation/archetypes/spec";
372✔
85
  int n = xqe.NMatches(p);
372✔
86
  for (int i = 0; i < n; ++i) {
1,554✔
87
    AgentSpec spec(xqe.SubTree(p, i));
1,182✔
88
    unique.insert(spec.str());
1,182✔
89
  }
1,182✔
90

91
  if (unique.size() == 0) {
372✔
92
    throw ValidationError("failed to parse archetype specs from input file");
×
93
  }
94

95
  std::vector<AgentSpec> specs = ParseSpecs(unique);
744✔
96

97
  return specs;
372✔
98
}
372✔
99

100
std::string BuildMasterSchema(std::string schema_path, std::vector<AgentSpec> specs) {
182✔
101

102
  Timer ti;
182✔
103
  Recorder rec;
182✔
104
  Context ctx(&ti, &rec);
182✔
105

106
  std::stringstream schema("");
182✔
107
  LoadStringstreamFromFile(schema, schema_path);
546✔
108
  std::string master = schema.str();
109

110
  std::map<std::string, std::string> subschemas;
111

112
  // force element types to exist so we always replace the config string
113
  subschemas["region"] = "";
182✔
114
  subschemas["inst"] = "";
182✔
115
  subschemas["facility"] = "";
182✔
116

117
  for (int i = 0; i < specs.size(); ++i) {
765✔
118
    Agent* m = DynamicModule::Make(&ctx, specs[i]);
583✔
119
    subschemas[m->kind()] += "<element name=\"" + specs[i].alias() + "\">\n";
2,332✔
120
    subschemas[m->kind()] += m->schema() + "\n";
1,964✔
121
    subschemas[m->kind()] += "</element>\n";
583✔
122
    ctx.DelAgent(m);
583✔
123
  }
124

125
  // replace refs in master rng template file
126
  std::map<std::string, std::string>::iterator it;
127
  for (it = subschemas.begin(); it != subschemas.end(); ++it) {
1,274✔
128
    std::string search_str = std::string("@") + it->first + std::string("_REFS@");
2,184✔
129
    size_t pos = master.find(search_str);
130
    if (pos != std::string::npos) {
1,092✔
131
      master.replace(pos, search_str.size(), it->second);
132
    }
133
  }
134

135
  return master;
182✔
136
}
182✔
137

138
std::string BuildMasterSchema(std::string schema_path) {
×
139

140
  std::vector<AgentSpec> specs = ParseSpecs(cyclus::DiscoverSpecsInCyclusPath());
×
141

142
  return BuildMasterSchema(schema_path, specs);
×
143

144
}
×
145

146
std::string BuildMasterSchema(std::string schema_path, std::string infile, std::string format) {
182✔
147

148
  std::vector<AgentSpec> specs = ParseSpecs(infile, format);
364✔
149

150
  return BuildMasterSchema(schema_path, specs);
728✔
151

152
}
182✔
153

154
Composition::Ptr ReadRecipe(InfileTree* qe) {
138✔
155
  bool atom_basis;
156
  std::string basis_str = qe->GetString("basis");
276✔
157
  if (basis_str == "atom") {
138✔
158
    atom_basis = true;
159
  } else if (basis_str == "mass") {
138✔
160
    atom_basis = false;
161
  } else {
162
    throw IOError(basis_str + " basis is not 'mass' or 'atom'.");
×
163
  }
164

165
  double value;
166
  int key;
167
  std::string query = "nuclide";
138✔
168
  int nnucs = qe->NMatches(query);
414✔
169
  CompMap v;
170
  for (int i = 0; i < nnucs; i++) {
309✔
171
    InfileTree* nuclide = qe->SubTree(query, i);
171✔
172
    key = pyne::nucname::id(nuclide->GetString("id"));
171✔
173
    value = strtod(nuclide->GetString("comp").c_str(), NULL);
342✔
174
    v[key] = value;
171✔
175
    CLOG(LEV_DEBUG3) << "  Nuclide: " << key << " Value: " << v[key];
171✔
176
  }
177

178
  if (atom_basis) {
138✔
179
    return Composition::CreateFromAtom(v);
×
180
  } else {
181
    return Composition::CreateFromMass(v);
276✔
182
  }
183
}
184

185
XMLFileLoader::XMLFileLoader(Recorder* r,
192✔
186
                             QueryableBackend* b,
187
                             std::string schema_file,
188
                             const std::string input_file,
189
                             const std::string format, bool ms_print) : b_(b), rec_(r) {
192✔
190
  ctx_ = new Context(&ti_, rec_);
192✔
191

192
  schema_path_ = schema_file;
193
  file_ = input_file;
194
  format_ = format;
195
  std::stringstream input;
192✔
196
  LoadStringstreamFromFile(input, file_, format);
384✔
197
  parser_ = boost::shared_ptr<XMLParser>(new XMLParser());
573✔
198
  parser_->Init(input);
191✔
199
  ms_print_ = ms_print;
191✔
200
  std::stringstream ss;
191✔
201
  parser_->Document()->write_to_stream_formatted(ss);
191✔
202
  ctx_->NewDatum("InputFiles")
191✔
203
      ->AddVal("Data", Blob(ss.str()))
382✔
204
      ->Record();
573✔
205
}
193✔
206

207
XMLFileLoader::~XMLFileLoader() {
191✔
208
  delete ctx_;
191✔
209
}
191✔
210

211
std::string XMLFileLoader::master_schema() {
182✔
212
  return BuildMasterSchema(schema_path_, file_, format_);
537✔
213
}
214

215
void XMLFileLoader::LoadSim() {
186✔
216
  std::stringstream ss(master_schema());
186✔
217
  if(ms_print_){
186✔
218
    std::cout << master_schema() << std::endl;
×
219
  }
220
  parser_->Validate(ss);
186✔
221
  LoadControlParams();  // must be first
186✔
222
  LoadSolver();
186✔
223
  LoadRecipes();
186✔
224
  LoadPackages();
186✔
225
  LoadTransportUnits();
186✔
226
  LoadSpecs();
186✔
227
  LoadInitialAgents();  // must be last
186✔
228
  SimInit::Snapshot(ctx_);
186✔
229
  rec_->Flush();
186✔
230
}
186✔
231

232
void XMLFileLoader::LoadSolver() {
186✔
233
  using std::string;
234
  InfileTree xqe(*parser_);
186✔
235
  InfileTree* qe;
236
  std::string query = "/*/commodity";
186✔
237

238
  std::map<std::string, double> commod_priority;
239
  std::string name;
240
  double priority;
241
  int num_commods = xqe.NMatches(query);
186✔
242
  for (int i = 0; i < num_commods; i++) {
186✔
243
    qe = xqe.SubTree(query, i);
×
244
    name = qe->GetString("name");
×
245
    priority = OptionalQuery<double>(qe, "solution_priority", -1);
×
246
    commod_priority[name] = priority;
×
247
  }
248

249
  ProcessCommodities(&commod_priority);
186✔
250
  std::map<std::string, double>::iterator it;
251
  for (it = commod_priority.begin(); it != commod_priority.end(); ++it) {
186✔
252
    ctx_->NewDatum("CommodPriority")
×
253
        ->AddVal("Commodity", it->first)
×
254
        ->AddVal("SolutionPriority", it->second)
255
        ->Record();
×
256
  }
257

258
  // now load the solver info
259
  string config = "config";
186✔
260
  string greedy = "greedy";
186✔
261
  string coinor = "coin-or";
186✔
262
  string solver_name = greedy;
263
  bool exclusive = ExchangeSolver::kDefaultExclusive;
264
  if (xqe.NMatches("/*/control/solver") == 1) {
372✔
265
    qe = xqe.SubTree("/*/control/solver");
80✔
266
    if (qe->NMatches(config) == 1) {
240✔
267
      solver_name = qe->SubTree(config)->GetElementName(0);
160✔
268
    }
269
    exclusive = cyclus::OptionalQuery<bool>(qe, "allow_exclusive_orders",
80✔
270
                                            exclusive);
271

272
  }
273

274
  if (!exclusive) {
80✔
275
    std::stringstream ss;
×
276
    ss << "You have set allow_exclusive_orders to False."
277
       << " Many archetypes (e.g., :cycamore:Reactor) will not work"
278
       << " as intended with this feature turned off.";
×
279
    Warn<VALUE_WARNING>(ss.str());
×
280
  }
×
281

282
  ctx_->NewDatum("SolverInfo")
186✔
283
      ->AddVal("Solver", solver_name)
284
      ->AddVal("ExclusiveOrders", exclusive)
285
      ->Record();
558✔
286

287
  // now load the actual solver
288
  if (solver_name == greedy) {
186✔
289
    query = string("/*/control/solver/config/greedy/preconditioner");
212✔
290
    string precon_name = cyclus::OptionalQuery<string>(&xqe, query, greedy);
212✔
291
    ctx_->NewDatum("GreedySolverInfo")
106✔
292
      ->AddVal("Preconditioner", precon_name)
293
      ->Record();
424✔
294
  } else if (solver_name == coinor) {
80✔
295
    query = string("/*/control/solver/config/coin-or/timeout");
160✔
296
    double timeout = cyclus::OptionalQuery<double>(&xqe, query, -1);
80✔
297
    query = string("/*/control/solver/config/coin-or/verbose");
160✔
298
    bool verbose = cyclus::OptionalQuery<bool>(&xqe, query, false);
80✔
299
    query = string("/*/control/solver/config/coin-or/mps");
160✔
300
    bool mps = cyclus::OptionalQuery<bool>(&xqe, query, false);
80✔
301
    ctx_->NewDatum("CoinSolverInfo")
80✔
302
      ->AddVal("Timeout", timeout)
303
      ->AddVal("Verbose", verbose)
304
      ->AddVal("Mps", mps)
305
      ->Record();
160✔
306
  } else {
307
    throw ValueError("unknown solver name: " + solver_name);
×
308
  }
309
}
186✔
310

311
void XMLFileLoader::ProcessCommodities(
186✔
312
  std::map<std::string, double>* commod_priority) {
313
  double max = std::max_element(
186✔
314
                 commod_priority->begin(),
315
                 commod_priority->end(),
316
                 SecondLT< std::pair<std::string, double> >())->second;
186✔
317
  if (max < 1) {
186✔
318
    max = 0;  // in case no priorities are specified
319
  }
320

321
  std::map<std::string, double>::iterator it;
322
  for (it = commod_priority->begin();
186✔
323
       it != commod_priority->end();
186✔
324
       ++it) {
325
    if (it->second < 1) {
×
326
      it->second = max + 1;
×
327
    }
328
    CLOG(LEV_INFO1) << "Commodity priority for " << it->first
×
329
                    << " is " << it->second;
×
330
  }
331
}
186✔
332

333
void XMLFileLoader::LoadRecipes() {
186✔
334
  InfileTree xqe(*parser_);
186✔
335

336
  std::string query = "/*/recipe";
186✔
337
  int num_recipes = xqe.NMatches(query);
186✔
338
  for (int i = 0; i < num_recipes; i++) {
324✔
339
    InfileTree* qe = xqe.SubTree(query, i);
138✔
340
    std::string name = qe->GetString("name");
138✔
341
    CLOG(LEV_DEBUG3) << "loading recipe: " << name;
138✔
342
    Composition::Ptr comp = ReadRecipe(qe);
138✔
343
    comp->Record(ctx_);
138✔
344
    ctx_->AddRecipe(name, comp);
552✔
345
  }
346
}
186✔
347

348
void XMLFileLoader::LoadPackages() {
186✔
349
  InfileTree xqe(*parser_);
186✔
350

351
  ctx_->RecordPackage(Package::unpackaged());
372✔
352

353
  std::string query = "/*/package";
186✔
354
  int num_packages = xqe.NMatches(query);
186✔
355
  for (int i = 0; i < num_packages; i++) {
186✔
356
    InfileTree* qe = xqe.SubTree(query, i);
×
357
    std::string name = cyclus::OptionalQuery<std::string>(qe, "name", "default");
×
358
    CLOG(LEV_DEBUG3) << "loading package: " << name;
×
359
    
360
    double fill_min = cyclus::OptionalQuery<double>(qe, "fill_min", eps());
×
361
    double fill_max = cyclus::OptionalQuery<double>(qe, "fill_max", std::numeric_limits<double>::max());
×
362
    
363
    std::string strategy = cyclus::OptionalQuery<std::string>(qe, "strategy", "first");
×
364

365
    ctx_->AddPackage(name, fill_min, fill_max, strategy);
×
366
  }
367
}
186✔
368

369
void XMLFileLoader::LoadTransportUnits() {
186✔
370
  InfileTree xqe(*parser_);
186✔
371

372
  std::string query = "/*/transportunit";
186✔
373
  int num_transport_units = xqe.NMatches(query);
186✔
374
  for (int i = 0; i < num_transport_units; i++) {
186✔
375
    InfileTree* qe = xqe.SubTree(query, i);
×
376
    std::string name = cyclus::OptionalQuery<std::string>(qe, "name", "default");
×
377
    CLOG(LEV_DEBUG3) << "loading transport unit: " << name;
×
378
    
379
    double fill_min = cyclus::OptionalQuery<double>(qe, "fill_min", eps());
×
380
    double fill_max = cyclus::OptionalQuery<double>(qe, "fill_max", std::numeric_limits<double>::max());
×
381
    
382
    std::string strategy = cyclus::OptionalQuery<std::string>(qe, "strategy", "first");
×
383

384
    ctx_->AddTransportUnit(name, fill_min, fill_max, strategy);
×
385
  }
386
}
186✔
387

388
void XMLFileLoader::LoadSpecs() {
186✔
389
  std::vector<AgentSpec> specs = ParseSpecs(file_, format_);
372✔
390
  for (int i = 0; i < specs.size(); ++i) {
777✔
391
    specs_[specs[i].alias()] = specs[i];
1,773✔
392
  }
393
}
186✔
394

395
void XMLFileLoader::LoadInitialAgents() {
182✔
396
  std::map<std::string, std::string> schema_paths;
397
  schema_paths["Region"] = "/*/region";
182✔
398
  schema_paths["Inst"] = "/*/region/institution";
182✔
399
  schema_paths["Facility"] = "/*/facility";
364✔
400

401
  InfileTree xqe(*parser_);
182✔
402

403
  // create prototypes
404
  std::string prototype;  // defined here for force-create AgentExit tbl
405
  std::map<std::string, std::string>::iterator it;
406
  for (it = schema_paths.begin(); it != schema_paths.end(); it++) {
728✔
407
    int num_agents = xqe.NMatches(it->second);
546✔
408
    for (int i = 0; i < num_agents; i++) {
1,169✔
409
      InfileTree* qe = xqe.SubTree(it->second, i);
623✔
410
      prototype = qe->GetString("name");
1,246✔
411
      std::string alias = qe->SubTree("config")->GetElementName(0);
623✔
412
      AgentSpec spec = specs_[alias];
623✔
413

414
      Agent* agent = DynamicModule::Make(ctx_, spec);
623✔
415

416
      // call manually without agent impl injected to keep all Agent state in a
417
      // single, consolidated db table
418
      agent->Agent::InfileToDb(qe, DbInit(agent, true));
623✔
419

420
      agent->InfileToDb(qe, DbInit(agent));
623✔
421
      rec_->Flush();
623✔
422

423
      std::vector<Cond> conds;
424
      conds.push_back(Cond("SimId", "==", rec_->sim_id()));
1,869✔
425
      conds.push_back(Cond("SimTime", "==", static_cast<int>(0)));
1,246✔
426
      conds.push_back(Cond("AgentId", "==", agent->id()));
1,246✔
427
      CondInjector ci(b_, conds);
623✔
428
      PrefixInjector pi(&ci, "AgentState");
623✔
429

430
      // call manually without agent impl injected
431
      agent->Agent::InitFrom(&pi);
623✔
432

433
      pi = PrefixInjector(&ci, "AgentState" + spec.Sanitize());
1,869✔
434
      agent->InitFrom(&pi);
623✔
435
      ctx_->AddPrototype(prototype, agent);
1,869✔
436
    }
623✔
437
  }
438

439
  // build initial agent instances
440
  int nregions = xqe.NMatches(schema_paths["Region"]);
546✔
441
  for (int i = 0; i < nregions; ++i) {
364✔
442
    InfileTree* qe = xqe.SubTree(schema_paths["Region"], i);
546✔
443
    std::string region_proto = qe->GetString("name");
364✔
444
    Agent* reg = BuildAgent(region_proto, NULL);
182✔
445

446
    int ninsts = qe->NMatches("institution");
182✔
447
    for (int j = 0; j < ninsts; ++j) {
364✔
448
      InfileTree* qe2 = qe->SubTree("institution", j);
182✔
449
      std::string inst_proto = qe2->GetString("name");
364✔
450
      Agent* inst = BuildAgent(inst_proto, reg);
182✔
451

452
      int nfac = qe2->NMatches("initialfacilitylist/entry");
182✔
453
      for (int k = 0; k < nfac; ++k) {
441✔
454
        InfileTree* qe3 = qe2->SubTree("initialfacilitylist/entry", k);
259✔
455
        std::string fac_proto = qe3->GetString("prototype");
259✔
456

457
        int number = atoi(qe3->GetString("number").c_str());
518✔
458
        for (int z = 0; z < number; ++z) {
1,426✔
459
          Agent* fac = BuildAgent(fac_proto, inst);
2,334✔
460
        }
461
      }
462
    }
463
  }
464
}
364✔
465

466
Agent* XMLFileLoader::BuildAgent(std::string proto, Agent* parent) {
1,539✔
467
  Agent* m = ctx_->CreateAgent<Agent>(proto);
1,539✔
468
  m->Build(parent);
1,539✔
469
  if (parent != NULL) {
1,539✔
470
    parent->BuildNotify(m);
1,349✔
471
  }
472
  return m;
1,539✔
473
}
474

475
void XMLFileLoader::LoadControlParams() {
186✔
476
  InfileTree xqe(*parser_);
186✔
477
  std::string query = "/*/control";
186✔
478
  InfileTree* qe = xqe.SubTree(query);
372✔
479

480
  std::string handle;
481
  if (qe->NMatches("simhandle") > 0) {
372✔
482
    handle = qe->GetString("simhandle");
×
483
  }
484

485
  // get duration
486
  std::string dur_str = qe->GetString("duration");
372✔
487
  int dur = strtol(dur_str.c_str(), NULL, 10);
186✔
488
  // get start month
489
  std::string m0_str = qe->GetString("startmonth");
372✔
490
  int m0 = strtol(m0_str.c_str(), NULL, 10);
186✔
491
  // get start year
492
  std::string y0_str = qe->GetString("startyear");
372✔
493
  int y0 = strtol(y0_str.c_str(), NULL, 10);
186✔
494
  // get decay mode
495
  std::string d = OptionalQuery<std::string>(qe, "decay", "manual");
372✔
496

497
  SimInfo si(dur, y0, m0, handle, d);
372✔
498

499
  si.explicit_inventory = OptionalQuery<bool>(qe, "explicit_inventory", false);
186✔
500
  si.explicit_inventory_compact = OptionalQuery<bool>(qe, "explicit_inventory_compact", false);
186✔
501

502
  // get time step duration
503
  si.dt = OptionalQuery<int>(qe, "dt", kDefaultTimeStepDur);
186✔
504

505
  // get epsilon
506
  double eps_ = OptionalQuery<double>(qe, "tolerance_generic", 1e-6);
186✔
507
  cy_eps = si.eps = eps_;
186✔
508

509
  // get epsilon resources
510
  double eps_rsrc_ = OptionalQuery<double>(qe, "tolerance_resource", 1e-6);
186✔
511
  cy_eps_rsrc = si.eps_rsrc = eps_rsrc_;
186✔
512

513
    // get seed
514
  si.seed = OptionalQuery<int>(qe, "seed", kDefaultSeed);
186✔
515

516
  // get stride
517
  si.stride = OptionalQuery<int>(qe, "stride", kDefaultStride);
186✔
518

519
  ctx_->InitSim(si);
186✔
520
}
372✔
521

522
}  // namespace cyclus
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc