CYCLUS
xml_file_loader.cc
Go to the documentation of this file.
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 "env.h"
17 #include "error.h"
18 #include "exchange_solver.h"
19 #include "greedy_preconditioner.h"
20 #include "greedy_solver.h"
21 #include "infile_tree.h"
22 #include "logger.h"
23 #include "sim_init.h"
25 
26 namespace cyclus {
27 
28 namespace fs = boost::filesystem;
29 
30 void LoadRawStringstreamFromFile(std::stringstream& stream, std::string file) {
31  std::ifstream file_stream(file.c_str());
32  if (!file_stream) {
33  throw IOError("The file '" + file + "' could not be loaded.");
34  }
35 
36  stream << file_stream.rdbuf();
37  file_stream.close();
38 }
39 
40 void LoadStringstreamFromFile(std::stringstream& stream, std::string file, std::string format) {
41  std::string inext;
42  if (format == "none") {
43  LoadRawStringstreamFromFile(stream, file);
44  inext = fs::path(file).extension().string();
45  } else {
46  stream << file;
47  }
48  if (inext == ".json" || format == "json") {
49  std::string inxml = cyclus::toolkit::JsonToXml(stream.str());
50  stream.str(inxml);
51  } else if (inext == ".py" || format == "py") {
52  std::string inxml = cyclus::toolkit::PyToXml(stream.str());
53  stream.str(inxml);
54  }
55 }
56 
58  std::stringstream input;
59  LoadStringstreamFromFile(input, file, format);
60  return input.str();
61 }
62 
63 std::vector<AgentSpec> ParseSpecs(std::string infile, std::string format) {
64  std::stringstream input;
65  LoadStringstreamFromFile(input, infile, format);
66  XMLParser parser_;
67  parser_.Init(input);
68  InfileTree xqe(parser_);
69 
70  std::vector<AgentSpec> specs;
71  std::set<std::string> unique;
72 
73  std::string p = "/simulation/archetypes/spec";
74  int n = xqe.NMatches(p);
75  for (int i = 0; i < n; ++i) {
76  AgentSpec spec(xqe.SubTree(p, i));
77  if (unique.count(spec.str()) == 0) {
78  specs.push_back(spec);
79  unique.insert(spec.str());
80  }
81  }
82 
83  if (specs.size() == 0) {
84  throw ValidationError("failed to parse archetype specs from input file");
85  }
86 
87  return specs;
88 }
89 
91  Timer ti;
92  Recorder rec;
93  Context ctx(&ti, &rec);
94 
95  std::stringstream schema("");
96  LoadStringstreamFromFile(schema, schema_path);
97  std::string master = schema.str();
98 
99  std::vector<AgentSpec> specs = ParseSpecs(infile, format);
100 
101  std::map<std::string, std::string> subschemas;
102 
103  // force element types to exist so we always replace the config string
104  subschemas["region"] = "";
105  subschemas["inst"] = "";
106  subschemas["facility"] = "";
107 
108  for (int i = 0; i < specs.size(); ++i) {
109  Agent* m = DynamicModule::Make(&ctx, specs[i]);
110  subschemas[m->kind()] += "<element name=\"" + specs[i].alias() + "\">\n";
111  subschemas[m->kind()] += m->schema() + "\n";
112  subschemas[m->kind()] += "</element>\n";
113  ctx.DelAgent(m);
114  }
115 
116  // replace refs in master rng template file
117  std::map<std::string, std::string>::iterator it;
118  for (it = subschemas.begin(); it != subschemas.end(); ++it) {
119  std::string search_str = std::string("@") + it->first + std::string("_REFS@");
120  size_t pos = master.find(search_str);
121  if (pos != std::string::npos) {
122  master.replace(pos, search_str.size(), it->second);
123  }
124  }
125 
126  return master;
127 }
128 
130  bool atom_basis;
131  std::string basis_str = qe->GetString("basis");
132  if (basis_str == "atom") {
133  atom_basis = true;
134  } else if (basis_str == "mass") {
135  atom_basis = false;
136  } else {
137  throw IOError(basis_str + " basis is not 'mass' or 'atom'.");
138  }
139 
140  double value;
141  int key;
142  std::string query = "nuclide";
143  int nnucs = qe->NMatches(query);
144  CompMap v;
145  for (int i = 0; i < nnucs; i++) {
146  InfileTree* nuclide = qe->SubTree(query, i);
147  key = pyne::nucname::id(nuclide->GetString("id"));
148  value = strtod(nuclide->GetString("comp").c_str(), NULL);
149  v[key] = value;
150  CLOG(LEV_DEBUG3) << " Nuclide: " << key << " Value: " << v[key];
151  }
152 
153  if (atom_basis) {
154  return Composition::CreateFromAtom(v);
155  } else {
156  return Composition::CreateFromMass(v);
157  }
158 }
159 
162  std::string schema_file,
163  const std::string input_file,
164  const std::string format, bool ms_print) : b_(b), rec_(r) {
165  ctx_ = new Context(&ti_, rec_);
166 
167  schema_path_ = schema_file;
168  file_ = input_file;
169  format_ = format;
170  std::stringstream input;
171  LoadStringstreamFromFile(input, file_, format);
172  parser_ = boost::shared_ptr<XMLParser>(new XMLParser());
173  parser_->Init(input);
174  ms_print_ = ms_print;
175  std::stringstream ss;
176  parser_->Document()->write_to_stream_formatted(ss);
177  ctx_->NewDatum("InputFiles")
178  ->AddVal("Data", Blob(ss.str()))
179  ->Record();
180 }
181 
183  delete ctx_;
184 }
185 
188 }
189 
191  std::stringstream ss(master_schema());
192  if(ms_print_){
193  std::cout << master_schema() << std::endl;
194  }
195  parser_->Validate(ss);
196  LoadControlParams(); // must be first
197  LoadSolver();
198  LoadRecipes();
199  LoadSpecs();
200  LoadInitialAgents(); // must be last
202  rec_->Flush();
203 }
204 
206  using std::string;
207  InfileTree xqe(*parser_);
208  InfileTree* qe;
209  std::string query = "/*/commodity";
210 
211  std::map<std::string, double> commod_priority;
213  double priority;
214  int num_commods = xqe.NMatches(query);
215  for (int i = 0; i < num_commods; i++) {
216  qe = xqe.SubTree(query, i);
217  name = qe->GetString("name");
218  priority = OptionalQuery<double>(qe, "solution_priority", -1);
219  commod_priority[name] = priority;
220  }
221 
222  ProcessCommodities(&commod_priority);
223  std::map<std::string, double>::iterator it;
224  for (it = commod_priority.begin(); it != commod_priority.end(); ++it) {
225  ctx_->NewDatum("CommodPriority")
226  ->AddVal("Commodity", it->first)
227  ->AddVal("SolutionPriority", it->second)
228  ->Record();
229  }
230 
231  // now load the solver info
232  string config = "config";
233  string greedy = "greedy";
234  string coinor = "coin-or";
235  string solver_name = greedy;
236  bool exclusive = ExchangeSolver::kDefaultExclusive;
237  if (xqe.NMatches("/*/control/solver") == 1) {
238  qe = xqe.SubTree("/*/control/solver");
239  if (qe->NMatches(config) == 1) {
240  solver_name = qe->SubTree(config)->GetElementName(0);
241  }
242  exclusive = cyclus::OptionalQuery<bool>(qe, "allow_exclusive_orders",
243  exclusive);
244 
245  // @TODO remove this after release 1.5
246  // check for deprecated input values
247  if (qe->NMatches(std::string("exclusive_orders_only")) != 0) {
248  std::stringstream ss;
249  ss << "Use of 'exclusive_orders_only' is deprecated."
250  << " Please see http://fuelcycle.org/user/input_specs/control.html";
251  Warn<DEPRECATION_WARNING>(ss.str());
252  }
253  }
254 
255  if (!exclusive) {
256  std::stringstream ss;
257  ss << "You have set allow_exclusive_orders to False."
258  << " Many archetypes (e.g., :cycamore:Reactor will not work"
259  << " as intended with this feature turned off.";
260  Warn<VALUE_WARNING>(ss.str());
261  }
262 
263  ctx_->NewDatum("SolverInfo")
264  ->AddVal("Solver", solver_name)
265  ->AddVal("ExclusiveOrders", exclusive)
266  ->Record();
267 
268  // now load the actual solver
269  if (solver_name == greedy) {
270  query = string("/*/control/solver/config/greedy/preconditioner");
271  string precon_name = cyclus::OptionalQuery<string>(&xqe, query, greedy);
272  ctx_->NewDatum("GreedySolverInfo")
273  ->AddVal("Preconditioner", precon_name)
274  ->Record();
275  } else if (solver_name == coinor) {
276  query = string("/*/control/solver/config/coin-or/timeout");
277  double timeout = cyclus::OptionalQuery<double>(&xqe, query, -1);
278  query = string("/*/control/solver/config/coin-or/verbose");
279  bool verbose = cyclus::OptionalQuery<bool>(&xqe, query, false);
280  query = string("/*/control/solver/config/coin-or/mps");
281  bool mps = cyclus::OptionalQuery<bool>(&xqe, query, false);
282  ctx_->NewDatum("CoinSolverInfo")
283  ->AddVal("Timeout", timeout)
284  ->AddVal("Verbose", verbose)
285  ->AddVal("Mps", mps)
286  ->Record();
287  } else {
288  throw ValueError("unknown solver name: " + solver_name);
289  }
290 }
291 
293  std::map<std::string, double>* commod_priority) {
294  double max = std::max_element(
295  commod_priority->begin(),
296  commod_priority->end(),
298  if (max < 1) {
299  max = 0; // in case no priorities are specified
300  }
301 
302  std::map<std::string, double>::iterator it;
303  for (it = commod_priority->begin();
304  it != commod_priority->end();
305  ++it) {
306  if (it->second < 1) {
307  it->second = max + 1;
308  }
309  CLOG(LEV_INFO1) << "Commodity priority for " << it->first
310  << " is " << it->second;
311  }
312 }
313 
315  InfileTree xqe(*parser_);
316 
317  std::string query = "/*/recipe";
318  int num_recipes = xqe.NMatches(query);
319  for (int i = 0; i < num_recipes; i++) {
320  InfileTree* qe = xqe.SubTree(query, i);
321  std::string name = qe->GetString("name");
322  CLOG(LEV_DEBUG3) << "loading recipe: " << name;
323  Composition::Ptr comp = ReadRecipe(qe);
324  comp->Record(ctx_);
325  ctx_->AddRecipe(name, comp);
326  }
327 }
328 
330  std::vector<AgentSpec> specs = ParseSpecs(file_, format_);
331  for (int i = 0; i < specs.size(); ++i) {
332  specs_[specs[i].alias()] = specs[i];
333  }
334 }
335 
337  std::map<std::string, std::string> schema_paths;
338  schema_paths["Region"] = "/*/region";
339  schema_paths["Inst"] = "/*/region/institution";
340  schema_paths["Facility"] = "/*/facility";
341 
342  InfileTree xqe(*parser_);
343 
344  // create prototypes
345  std::string prototype; // defined here for force-create AgentExit tbl
346  std::map<std::string, std::string>::iterator it;
347  for (it = schema_paths.begin(); it != schema_paths.end(); it++) {
348  int num_agents = xqe.NMatches(it->second);
349  for (int i = 0; i < num_agents; i++) {
350  InfileTree* qe = xqe.SubTree(it->second, i);
351  prototype = qe->GetString("name");
352  std::string alias = qe->SubTree("config")->GetElementName(0);
353  AgentSpec spec = specs_[alias];
354 
355  Agent* agent = DynamicModule::Make(ctx_, spec);
356 
357  // call manually without agent impl injected to keep all Agent state in a
358  // single, consolidated db table
359  agent->Agent::InfileToDb(qe, DbInit(agent, true));
360 
361  agent->InfileToDb(qe, DbInit(agent));
362  rec_->Flush();
363 
364  std::vector<Cond> conds;
365  conds.push_back(Cond("SimId", "==", rec_->sim_id()));
366  conds.push_back(Cond("SimTime", "==", static_cast<int>(0)));
367  conds.push_back(Cond("AgentId", "==", agent->id()));
368  CondInjector ci(b_, conds);
369  PrefixInjector pi(&ci, "AgentState");
370 
371  // call manually without agent impl injected
372  agent->Agent::InitFrom(&pi);
373 
374  pi = PrefixInjector(&ci, "AgentState" + spec.Sanitize());
375  agent->InitFrom(&pi);
376  ctx_->AddPrototype(prototype, agent);
377  }
378  }
379 
380  // build initial agent instances
381  int nregions = xqe.NMatches(schema_paths["Region"]);
382  for (int i = 0; i < nregions; ++i) {
383  InfileTree* qe = xqe.SubTree(schema_paths["Region"], i);
384  std::string region_proto = qe->GetString("name");
385  Agent* reg = BuildAgent(region_proto, NULL);
386 
387  int ninsts = qe->NMatches("institution");
388  for (int j = 0; j < ninsts; ++j) {
389  InfileTree* qe2 = qe->SubTree("institution", j);
390  std::string inst_proto = qe2->GetString("name");
391  Agent* inst = BuildAgent(inst_proto, reg);
392 
393  int nfac = qe2->NMatches("initialfacilitylist/entry");
394  for (int k = 0; k < nfac; ++k) {
395  InfileTree* qe3 = qe2->SubTree("initialfacilitylist/entry", k);
396  std::string fac_proto = qe3->GetString("prototype");
397 
398  int number = atoi(qe3->GetString("number").c_str());
399  for (int z = 0; z < number; ++z) {
400  Agent* fac = BuildAgent(fac_proto, inst);
401  }
402  }
403  }
404  }
405 }
406 
408  Agent* m = ctx_->CreateAgent<Agent>(proto);
409  m->Build(parent);
410  if (parent != NULL) {
411  parent->BuildNotify(m);
412  }
413  return m;
414 }
415 
417  InfileTree xqe(*parser_);
418  std::string query = "/*/control";
419  InfileTree* qe = xqe.SubTree(query);
420 
421  std::string handle;
422  if (qe->NMatches("simhandle") > 0) {
423  handle = qe->GetString("simhandle");
424  }
425 
426  // get duration
427  std::string dur_str = qe->GetString("duration");
428  int dur = strtol(dur_str.c_str(), NULL, 10);
429  // get start month
430  std::string m0_str = qe->GetString("startmonth");
431  int m0 = strtol(m0_str.c_str(), NULL, 10);
432  // get start year
433  std::string y0_str = qe->GetString("startyear");
434  int y0 = strtol(y0_str.c_str(), NULL, 10);
435  // get decay mode
436  std::string d = OptionalQuery<std::string>(qe, "decay", "manual");
437 
438  SimInfo si(dur, y0, m0, handle, d);
439 
440  si.explicit_inventory = OptionalQuery<bool>(qe, "explicit_inventory", false);
441  si.explicit_inventory_compact = OptionalQuery<bool>(qe, "explicit_inventory_compact", false);
442 
443  // get time step duration
444  si.dt = OptionalQuery<int>(qe, "dt", kDefaultTimeStepDur);
445 
446  // get epsilon
447  double eps_ = OptionalQuery<double>(qe, "tolerance_generic", 1e-6);
448  cy_eps = si.eps = eps_;
449 
450  // get epsilon resources
451  double eps_rsrc_ = OptionalQuery<double>(qe, "tolerance_resource", 1e-6);
452  cy_eps_rsrc = si.eps_rsrc = eps_rsrc_;
453 
454 
455  ctx_->InitSim(si);
456 }
457 
458 } // namespace cyclus
XMLFileLoader(Recorder *r, QueryableBackend *b, std::string schema_file, const std::string input_file="", const std::string format="none", bool ms_print=false)
Create a new loader reading from the xml simulation input file and writing to and initializing the ba...
virtual std::string master_schema()
std::string BuildMasterSchema(std::string schema_path, std::string infile, std::string format)
Builds and returns a master cyclus input xml schema that includes the sub-schemas defined by all inst...
std::string PyToXml(std::string s)
Converts a Python string into an equivalent XML string.
boost::shared_ptr< XMLParser > parser_
the parser
boost::uuids::uuid sim_id()
returns the unique id associated with this cyclus simulation.
Definition: recorder.cc:49
boost::shared_ptr< Composition > Ptr
Definition: composition.h:43
std::string schema_path_
filepath to the schema
double b(int nuc)
Computes the scattering length [cm] from the coherent and incoherent components.
Definition: pyne.cc:11180
std::string file_
the input file name
void AddRecipe(std::string name, Composition::Ptr c)
Adds a composition recipe to a simulation-wide accessible list.
Definition: context.cc:166
void LoadRawStringstreamFromFile(std::stringstream &stream, std::string file)
Reads the given file path into the passed stream without modification.
void LoadRecipes()
Method to load recipes from either the primary input file or a recipeBook catalog.
virtual int NMatches(std::string query)
investigates the current status and returns the number of elements matching a query ...
Definition: infile_tree.cc:49
std::string JsonToXml(std::string s)
Converts a JSON string into an equivalent XML string.
virtual void InfileToDb(InfileTree *qe, DbInit di)
Translates info for the agent from an input file to the database by reading parameters from the passe...
Definition: agent.cc:36
virtual void LoadInitialAgents()
Creates all initial agent instances from the input file.
debugging information
Definition: logger.h:60
double cy_eps
generic epsilon values
Definition: context.cc:16
Agent * BuildAgent(std::string proto, Agent *parent)
Creates and builds an agent, notifying its parent.
std::string Sanitize()
a less-than comparison for pairs
Definition: cyc_std.h:11
For values that are too big, too small, etc.
Definition: error.h:41
A class for extracting information from a given XML parser.
Definition: infile_tree.h:22
std::string format_
the input file format
For validating files received via IO.
Definition: error.h:71
static const bool kDefaultExclusive
default value to allow exclusive orders or not
virtual const int id() const
The agent instance&#39;s unique ID within a simulation.
Definition: agent.h:354
std::string name(int nuc)
Definition: pyne.cc:2940
void LoadControlParams()
Method to load the simulation control parameters.
virtual std::string GetElementName(int index=0)
investigates the current status and returns a string representing the name of a given index ...
Definition: infile_tree.cc:93
virtual void BuildNotify(Agent *m)
Called when a new child of this agent has just been built.
Definition: agent.h:315
std::map< Nuc, double > CompMap
a raw definition of nuclides and corresponding (dimensionless quantities).
Definition: composition.h:17
#define CLOG(level)
Definition: logger.h:39
A helper class to hold xml file data and provide automatic validation.
Definition: xml_parser.h:16
QueryableBackend * b_
virtual std::string schema()
Returns an agent&#39;s xml rng schema for initializing from input files.
Definition: agent.h:335
virtual void Build(Agent *parent)
Called when the agent enters the smiulation as an active participant and is only ever called once...
Definition: agent.cc:153
virtual std::string GetString(std::string query, int index=0)
investigates the current status and returns a string representing the content of a query at a given i...
Definition: infile_tree.cc:54
void InitSim(SimInfo si)
Initializes the simulation time parameters.
Definition: context.cc:181
const uint64_t kDefaultTimeStepDur
Definition: context.h:22
for failed reading/writing to files, network connections, etc..
Definition: error.h:59
const std::string kind() const
Returns a string that describes the agent subclass (e.g.
Definition: agent.h:366
int parent(int nuc, unsigned int rx, std::string z="n")
Definition: pyne.cc:6621
Wrapper class for QueryableBackends that injects a set of Cond&#39;s into every query before being execut...
std::map< std::string, AgentSpec > specs_
Information helpful for simulation users and developers alike - least verbose.
Definition: logger.h:53
T * CreateAgent(std::string proto_name)
Create a new agent by cloning the named prototype.
Definition: context.h:180
Datum * AddVal(const char *field, boost::spirit::hold_any val, std::vector< int > *shape=NULL)
Add an arbitrary field-value pair to the datum.
Definition: datum.cc:22
Composition::Ptr ReadRecipe(InfileTree *qe)
Creates a composition from the recipe in the query engine.
void AddPrototype(std::string name, Agent *m)
Adds a prototype to a simulation-wide accessible list, a prototype can not be added more than once...
Definition: context.cc:137
DbInit provides an interface for agents to record data to the output db that automatically injects th...
Definition: db_init.h:14
void Flush()
Flushes all buffered Datum objects and flushes all registered backends.
Definition: recorder.cc:92
bool ms_print_
flag to indicate printing master schema
static void Snapshot(Context *ctx)
Records a snapshot of the current state of the simulation being managed by ctx into the simulation&#39;s ...
Definition: sim_init.cc:74
Collects and manages output data generation for the cyclus core and agents during a simulation...
Definition: recorder.h:45
double cy_eps_rsrc
epsilon values to be used by resources
Definition: context.cc:17
Wrapper class for QueryableBackends that injects prefix in front of the title/table for every query b...
InfileTree * SubTree(std::string query, int index=0)
populates a child infile based on a query and index
Definition: infile_tree.cc:132
Container for a static simulation-global parameters that both describe the simulation and affect its ...
Definition: context.h:39
Code providing rudimentary logging capability for the Cyclus core.
A simulation context provides access to necessary simulation-global functions and state...
Definition: context.h:130
The abstract base class used by all types of agents that live and interact in a simulation.
Definition: agent.h:51
taken directly from OsiSolverInterface.cpp on 2/17/14 from https://projects.coin-or.org/Osi/browser/trunk.
Definition: agent.cc:14
A type to represent variable-length array of bytes for dumping to a cyclus output database...
Definition: blob.h:9
void LoadSolver()
Method to load the simulation exchange solver.
const double pi
pi = 3.14159265359
Definition: pyne.cc:10356
std::vector< AgentSpec > ParseSpecs(std::string infile, std::string format)
Returns a list of the full module+agent spec for all agents in the given input file.
void ProcessCommodities(std::map< std::string, double > *commodity_priority)
Processes commodity priorities, such that any without a defined priority (i.e., are nonpositive)...
int id(int nuc)
Definition: pyne.cc:2716
virtual void InitFrom(QueryableBackend *b)
Intializes an agent&#39;s internal state from the database.
Definition: agent.cc:45
Represents a condition used to filter rows returned by a query.
void LoadStringstreamFromFile(std::stringstream &stream, std::string file, std::string format)
Reads the given file path as XML into the passed stream.
virtual void LoadSim()
Load an entire simulation from the inputfile.
void Record()
Record this datum to its Recorder.
Definition: datum.cc:35
std::string LoadStringFromFile(std::string file, std::string format)
Reads the given file path and returns an XML string.
void LoadSpecs()
Load agent specs from the input file to a map by alias.
static Agent * Make(Context *ctx, AgentSpec spec)
Returns a newly constructed agent for the given module spec.
Interface implemented by backends that support rudimentary querying.
void Init(const std::stringstream &input)
initializes a parser with an xml snippet
Definition: xml_parser.cc:41
static Ptr CreateFromAtom(CompMap v)
Creates a new composition from v with its components having appropriate atom-based ratios...
Definition: composition.cc:17
Datum * NewDatum(std::string title)
See Recorder::NewDatum documentation.
Definition: context.cc:239
static Ptr CreateFromMass(CompMap v)
Creates a new composition from v with its components having appropriate mass-based ratios...
Definition: composition.cc:29
void DelAgent(Agent *m)
Destructs and cleans up m (and it&#39;s children recursively).
Definition: context.cc:98
Controls simulation timestepping and inter-timestep phases.
Definition: timer.h:22