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

cyclus / cyclus / 16384544356

19 Jul 2025 03:38AM UTC coverage: 36.53% (-4.7%) from 41.231%
16384544356

push

github

web-flow
Merge pull request #1881 from dean-krueger/clang-format

Clang Format Cyclus src

1517 of 26176 new or added lines in 94 files covered. (5.8%)

309 existing lines in 19 files now uncovered.

51830 of 141883 relevant lines covered (36.53%)

14764.59 hits per line

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

86.49
/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) {
956✔
32
  std::ifstream file_stream(file.c_str());
956✔
33
  if (!file_stream) {
956✔
34
    throw IOError("The file '" + file + "' could not be loaded.");
2✔
35
  }
36

37
  stream << file_stream.rdbuf();
955✔
38
  file_stream.close();
955✔
39
}
956✔
40

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

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

65
std::vector<AgentSpec> ParseSpecs(std::set<std::string> agent_set) {
380✔
66
  std::vector<AgentSpec> specs;
67

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

72
  return specs;
380✔
73
}
×
74

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

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

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

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

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

97
  return specs;
380✔
98
}
380✔
99

100
std::string BuildMasterSchema(std::string schema_path,
186✔
101
                              std::vector<AgentSpec> specs) {
102
  Timer ti;
186✔
103
  Recorder rec;
186✔
104
  Context ctx(&ti, &rec);
186✔
105

106
  std::stringstream schema("");
186✔
107
  LoadStringstreamFromFile(schema, schema_path);
558✔
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"] = "";
186✔
114
  subschemas["inst"] = "";
186✔
115
  subschemas["facility"] = "";
186✔
116

117
  for (int i = 0; i < specs.size(); ++i) {
785✔
118
    Agent* m = DynamicModule::Make(&ctx, specs[i]);
599✔
119
    subschemas[m->kind()] += "<element name=\"" + specs[i].alias() + "\">\n";
2,396✔
120
    subschemas[m->kind()] += m->schema() + "\n";
2,194✔
121
    subschemas[m->kind()] += "</element>\n";
599✔
122
    ctx.DelAgent(m);
599✔
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,302✔
128
    std::string search_str =
129
        std::string("@") + it->first + std::string("_REFS@");
2,232✔
130
    size_t pos = master.find(search_str);
131
    if (pos != std::string::npos) {
1,116✔
132
      master.replace(pos, search_str.size(), it->second);
133
    }
134
  }
135

136
  return master;
186✔
137
}
186✔
138

139
std::string BuildMasterSchema(std::string schema_path) {
×
140
  std::vector<AgentSpec> specs =
NEW
141
      ParseSpecs(cyclus::DiscoverSpecsInCyclusPath());
×
142

143
  return BuildMasterSchema(schema_path, specs);
×
UNCOV
144
}
×
145

146
std::string BuildMasterSchema(std::string schema_path, std::string infile,
186✔
147
                              std::string format) {
148
  std::vector<AgentSpec> specs = ParseSpecs(infile, format);
372✔
149

150
  return BuildMasterSchema(schema_path, specs);
744✔
151
}
186✔
152

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

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

177
  if (atom_basis) {
142✔
178
    return Composition::CreateFromAtom(v);
×
179
  } else {
180
    return Composition::CreateFromMass(v);
284✔
181
  }
182
}
183

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

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

204
XMLFileLoader::~XMLFileLoader() {
195✔
205
  delete ctx_;
195✔
206
}
195✔
207

208
std::string XMLFileLoader::master_schema() {
186✔
209
  return BuildMasterSchema(schema_path_, file_, format_);
549✔
210
}
211

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

229
void XMLFileLoader::LoadSolver() {
190✔
230
  using std::string;
231
  InfileTree xqe(*parser_);
190✔
232
  InfileTree* qe;
233
  std::string query = "/*/commodity";
190✔
234

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

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

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

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

278
  ctx_->NewDatum("SolverInfo")
190✔
279
      ->AddVal("Solver", solver_name)
280
      ->AddVal("ExclusiveOrders", exclusive)
281
      ->Record();
570✔
282

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

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

317
  std::map<std::string, double>::iterator it;
318
  for (it = commod_priority->begin(); it != commod_priority->end(); ++it) {
190✔
UNCOV
319
    if (it->second < 1) {
×
320
      it->second = max + 1;
×
321
    }
NEW
322
    CLOG(LEV_INFO1) << "Commodity priority for " << it->first << " is "
×
NEW
323
                    << it->second;
×
324
  }
325
}
190✔
326

327
void XMLFileLoader::LoadRecipes() {
190✔
328
  InfileTree xqe(*parser_);
190✔
329

330
  std::string query = "/*/recipe";
190✔
331
  int num_recipes = xqe.NMatches(query);
190✔
332
  for (int i = 0; i < num_recipes; i++) {
332✔
333
    InfileTree* qe = xqe.SubTree(query, i);
142✔
334
    std::string name = qe->GetString("name");
142✔
335
    CLOG(LEV_DEBUG3) << "loading recipe: " << name;
142✔
336
    Composition::Ptr comp = ReadRecipe(qe);
142✔
337
    comp->Record(ctx_);
142✔
338
    ctx_->AddRecipe(name, comp);
568✔
339
  }
340
}
190✔
341

342
void XMLFileLoader::LoadPackages() {
190✔
343
  InfileTree xqe(*parser_);
190✔
344

345
  ctx_->RecordPackage(Package::unpackaged());
380✔
346

347
  std::string query = "/*/package";
190✔
348
  int num_packages = xqe.NMatches(query);
190✔
349
  for (int i = 0; i < num_packages; i++) {
190✔
350
    InfileTree* qe = xqe.SubTree(query, i);
×
351
    std::string name =
NEW
352
        cyclus::OptionalQuery<std::string>(qe, "name", "default");
×
UNCOV
353
    CLOG(LEV_DEBUG3) << "loading package: " << name;
×
354

355
    double fill_min = cyclus::OptionalQuery<double>(qe, "fill_min", eps());
×
NEW
356
    double fill_max = cyclus::OptionalQuery<double>(
×
357
        qe, "fill_max", std::numeric_limits<double>::max());
358

359
    std::string strategy =
NEW
360
        cyclus::OptionalQuery<std::string>(qe, "strategy", "first");
×
361

362
    ctx_->AddPackage(name, fill_min, fill_max, strategy);
×
363
  }
364
}
190✔
365

366
void XMLFileLoader::LoadTransportUnits() {
190✔
367
  InfileTree xqe(*parser_);
190✔
368

369
  std::string query = "/*/transportunit";
190✔
370
  int num_transport_units = xqe.NMatches(query);
190✔
371
  for (int i = 0; i < num_transport_units; i++) {
190✔
372
    InfileTree* qe = xqe.SubTree(query, i);
×
373
    std::string name =
NEW
374
        cyclus::OptionalQuery<std::string>(qe, "name", "default");
×
UNCOV
375
    CLOG(LEV_DEBUG3) << "loading transport unit: " << name;
×
376

377
    double fill_min = cyclus::OptionalQuery<double>(qe, "fill_min", eps());
×
NEW
378
    double fill_max = cyclus::OptionalQuery<double>(
×
379
        qe, "fill_max", std::numeric_limits<double>::max());
380

381
    std::string strategy =
NEW
382
        cyclus::OptionalQuery<std::string>(qe, "strategy", "first");
×
383

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

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

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

401
  InfileTree xqe(*parser_);
186✔
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++) {
744✔
407
    int num_agents = xqe.NMatches(it->second);
558✔
408
    for (int i = 0; i < num_agents; i++) {
1,197✔
409
      InfileTree* qe = xqe.SubTree(it->second, i);
639✔
410
      prototype = qe->GetString("name");
1,278✔
411
      std::string alias = qe->SubTree("config")->GetElementName(0);
639✔
412
      AgentSpec spec = specs_[alias];
639✔
413

414
      Agent* agent = DynamicModule::Make(ctx_, spec);
639✔
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));
639✔
419

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

520
  ctx_->InitSim(si);
190✔
521
}
380✔
522

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

© 2026 Coveralls, Inc