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) {
41  LoadRawStringstreamFromFile(stream, file);
42  std::string inext = fs::path(file).extension().string();
43  if (inext == ".json") {
44  std::string inxml = cyclus::toolkit::JsonToXml(stream.str());
45  stream.str(inxml);
46  }
47 }
48 
49 std::vector<AgentSpec> ParseSpecs(std::string infile) {
50  std::stringstream input;
51  LoadStringstreamFromFile(input, infile);
52  XMLParser parser_;
53  parser_.Init(input);
54  InfileTree xqe(parser_);
55 
56  std::vector<AgentSpec> specs;
57  std::set<std::string> unique;
58 
59  std::string p = "/simulation/archetypes/spec";
60  int n = xqe.NMatches(p);
61  for (int i = 0; i < n; ++i) {
62  AgentSpec spec(xqe.SubTree(p, i));
63  if (unique.count(spec.str()) == 0) {
64  specs.push_back(spec);
65  unique.insert(spec.str());
66  }
67  }
68 
69  if (specs.size() == 0) {
70  throw ValidationError("failed to parse archetype specs from input file");
71  }
72 
73  return specs;
74 }
75 
76 std::string BuildMasterSchema(std::string schema_path, std::string infile) {
77  Timer ti;
78  Recorder rec;
79  Context ctx(&ti, &rec);
80 
81  std::stringstream schema("");
82  LoadStringstreamFromFile(schema, schema_path);
83  std::string master = schema.str();
84 
85  std::vector<AgentSpec> specs = ParseSpecs(infile);
86 
87  std::map<std::string, std::string> subschemas;
88 
89  // force element types to exist so we always replace the config string
90  subschemas["region"] = "";
91  subschemas["inst"] = "";
92  subschemas["facility"] = "";
93 
94  for (int i = 0; i < specs.size(); ++i) {
95  Agent* m = DynamicModule::Make(&ctx, specs[i]);
96  subschemas[m->kind()] += "<element name=\"" + specs[i].alias() + "\">\n";
97  subschemas[m->kind()] += m->schema() + "\n";
98  subschemas[m->kind()] += "</element>\n";
99  ctx.DelAgent(m);
100  }
101 
102  // replace refs in master rng template file
103  std::map<std::string, std::string>::iterator it;
104  for (it = subschemas.begin(); it != subschemas.end(); ++it) {
105  std::string search_str = std::string("@") + it->first + std::string("_REFS@");
106  size_t pos = master.find(search_str);
107  if (pos != std::string::npos) {
108  master.replace(pos, search_str.size(), it->second);
109  }
110  }
111 
112  return master;
113 }
114 
116  bool atom_basis;
117  std::string basis_str = qe->GetString("basis");
118  if (basis_str == "atom") {
119  atom_basis = true;
120  } else if (basis_str == "mass") {
121  atom_basis = false;
122  } else {
123  throw IOError(basis_str + " basis is not 'mass' or 'atom'.");
124  }
125 
126  double value;
127  int key;
128  std::string query = "nuclide";
129  int nnucs = qe->NMatches(query);
130  CompMap v;
131  for (int i = 0; i < nnucs; i++) {
132  InfileTree* nuclide = qe->SubTree(query, i);
133  key = pyne::nucname::id(nuclide->GetString("id"));
134  value = strtod(nuclide->GetString("comp").c_str(), NULL);
135  v[key] = value;
136  CLOG(LEV_DEBUG3) << " Nuclide: " << key << " Value: " << v[key];
137  }
138 
139  if (atom_basis) {
140  return Composition::CreateFromAtom(v);
141  } else {
142  return Composition::CreateFromMass(v);
143  }
144 }
145 
148  std::string schema_file,
149  const std::string input_file) : b_(b), rec_(r) {
150  ctx_ = new Context(&ti_, rec_);
151 
152  schema_path_ = schema_file;
153  file_ = input_file;
154  std::stringstream input;
156  parser_ = boost::shared_ptr<XMLParser>(new XMLParser());
157  parser_->Init(input);
158 
159  std::stringstream ss;
160  parser_->Document()->write_to_stream_formatted(ss);
161 
162  std::stringstream orig_input;
163  LoadRawStringstreamFromFile(orig_input, file_);
164  ctx_->NewDatum("InputFiles")
165  ->AddVal("Data", Blob(ss.str()))
166  ->Record();
167 }
168 
170  delete ctx_;
171 }
172 
175 }
176 
178  std::stringstream ss(master_schema());
179  parser_->Validate(ss);
180  LoadControlParams(); // must be first
181  LoadSolver();
182  LoadRecipes();
183  LoadSpecs();
184  LoadInitialAgents(); // must be last
186  rec_->Flush();
187 }
188 
190  using std::string;
191  InfileTree xqe(*parser_);
192  InfileTree* qe;
193  std::string query = "/*/commodity";
194 
195  std::map<std::string, double> commod_priority;
196  std::string name;
197  double priority;
198  int num_commods = xqe.NMatches(query);
199  for (int i = 0; i < num_commods; i++) {
200  qe = xqe.SubTree(query, i);
201  name = qe->GetString("name");
202  priority = OptionalQuery<double>(qe, "solution_priority", -1);
203  commod_priority[name] = priority;
204  }
205 
206  ProcessCommodities(&commod_priority);
207  std::map<std::string, double>::iterator it;
208  for (it = commod_priority.begin(); it != commod_priority.end(); ++it) {
209  ctx_->NewDatum("CommodPriority")
210  ->AddVal("Commodity", it->first)
211  ->AddVal("SolutionPriority", it->second)
212  ->Record();
213  }
214 
215  // now load the solver info
216  string config = "config";
217  string greedy = "greedy";
218  string coinor = "coin-or";
219  string solver_name = greedy;
220  bool exclusive = ExchangeSolver::kDefaultExclusive;
221  if (xqe.NMatches("/*/control/solver") == 1) {
222  qe = xqe.SubTree("/*/control/solver");
223  if (qe->NMatches(config) == 1) {
224  solver_name = qe->SubTree(config)->GetElementName(0);
225  }
226  exclusive = cyclus::OptionalQuery<bool>(qe, "allow_exclusive_orders",
227  exclusive);
228 
229  // @TODO remove this after release 1.5
230  // check for deprecated input values
231  if (qe->NMatches(std::string("exclusive_orders_only")) != 0) {
232  std::stringstream ss;
233  ss << "Use of 'exclusive_orders_only' is deprecated."
234  << " Please see http://fuelcycle.org/user/input_specs/control.html";
235  Warn<DEPRECATION_WARNING>(ss.str());
236  }
237  }
238 
239  if (!exclusive) {
240  std::stringstream ss;
241  ss << "You have set allow_exclusive_orders to False."
242  << " Many archetypes (e.g., :cycamore:Reactor will not work"
243  << " as intended with this feature turned off.";
244  Warn<VALUE_WARNING>(ss.str());
245  }
246 
247  ctx_->NewDatum("SolverInfo")
248  ->AddVal("Solver", solver_name)
249  ->AddVal("ExclusiveOrders", exclusive)
250  ->Record();
251 
252  // now load the actual solver
253  if (solver_name == greedy) {
254  query = string("/*/control/solver/config/greedy/preconditioner");
255  string precon_name = cyclus::OptionalQuery<string>(&xqe, query, greedy);
256  ctx_->NewDatum("GreedySolverInfo")
257  ->AddVal("Preconditioner", precon_name)
258  ->Record();
259  } else if (solver_name == coinor) {
260  query = string("/*/control/solver/config/coin-or/timeout");
261  double timeout = cyclus::OptionalQuery<double>(&xqe, query, -1);
262  query = string("/*/control/solver/config/coin-or/verbose");
263  bool verbose = cyclus::OptionalQuery<bool>(&xqe, query, false);
264  query = string("/*/control/solver/config/coin-or/mps");
265  bool mps = cyclus::OptionalQuery<bool>(&xqe, query, false);
266  ctx_->NewDatum("CoinSolverInfo")
267  ->AddVal("Timeout", timeout)
268  ->AddVal("Verbose", verbose)
269  ->AddVal("Mps", mps)
270  ->Record();
271  } else {
272  throw ValueError("unknown solver name: " + solver_name);
273  }
274 }
275 
277  std::map<std::string, double>* commod_priority) {
278  double max = std::max_element(
279  commod_priority->begin(),
280  commod_priority->end(),
282  if (max < 1) {
283  max = 0; // in case no priorities are specified
284  }
285 
286  std::map<std::string, double>::iterator it;
287  for (it = commod_priority->begin();
288  it != commod_priority->end();
289  ++it) {
290  if (it->second < 1) {
291  it->second = max + 1;
292  }
293  CLOG(LEV_INFO1) << "Commodity priority for " << it->first
294  << " is " << it->second;
295  }
296 }
297 
299  InfileTree xqe(*parser_);
300 
301  std::string query = "/*/recipe";
302  int num_recipes = xqe.NMatches(query);
303  for (int i = 0; i < num_recipes; i++) {
304  InfileTree* qe = xqe.SubTree(query, i);
305  std::string name = qe->GetString("name");
306  CLOG(LEV_DEBUG3) << "loading recipe: " << name;
307  Composition::Ptr comp = ReadRecipe(qe);
308  comp->Record(ctx_);
309  ctx_->AddRecipe(name, comp);
310  }
311 }
312 
314  std::vector<AgentSpec> specs = ParseSpecs(file_);
315  for (int i = 0; i < specs.size(); ++i) {
316  specs_[specs[i].alias()] = specs[i];
317  }
318 }
319 
321  std::map<std::string, std::string> schema_paths;
322  schema_paths["Region"] = "/*/region";
323  schema_paths["Inst"] = "/*/region/institution";
324  schema_paths["Facility"] = "/*/facility";
325 
326  InfileTree xqe(*parser_);
327 
328  // create prototypes
329  std::string prototype; // defined here for force-create AgentExit tbl
330  std::map<std::string, std::string>::iterator it;
331  for (it = schema_paths.begin(); it != schema_paths.end(); it++) {
332  int num_agents = xqe.NMatches(it->second);
333  for (int i = 0; i < num_agents; i++) {
334  InfileTree* qe = xqe.SubTree(it->second, i);
335  prototype = qe->GetString("name");
336  std::string alias = qe->SubTree("config")->GetElementName(0);
337  AgentSpec spec = specs_[alias];
338 
339  Agent* agent = DynamicModule::Make(ctx_, spec);
340 
341  // call manually without agent impl injected to keep all Agent state in a
342  // single, consolidated db table
343  agent->Agent::InfileToDb(qe, DbInit(agent, true));
344 
345  agent->InfileToDb(qe, DbInit(agent));
346  rec_->Flush();
347 
348  std::vector<Cond> conds;
349  conds.push_back(Cond("SimId", "==", rec_->sim_id()));
350  conds.push_back(Cond("SimTime", "==", static_cast<int>(0)));
351  conds.push_back(Cond("AgentId", "==", agent->id()));
352  CondInjector ci(b_, conds);
353  PrefixInjector pi(&ci, "AgentState");
354 
355  // call manually without agent impl injected
356  agent->Agent::InitFrom(&pi);
357 
358  pi = PrefixInjector(&ci, "AgentState" + spec.Sanitize());
359  agent->InitFrom(&pi);
360  ctx_->AddPrototype(prototype, agent);
361  }
362  }
363 
364  // build initial agent instances
365  int nregions = xqe.NMatches(schema_paths["Region"]);
366  for (int i = 0; i < nregions; ++i) {
367  InfileTree* qe = xqe.SubTree(schema_paths["Region"], i);
368  std::string region_proto = qe->GetString("name");
369  Agent* reg = BuildAgent(region_proto, NULL);
370 
371  int ninsts = qe->NMatches("institution");
372  for (int j = 0; j < ninsts; ++j) {
373  InfileTree* qe2 = qe->SubTree("institution", j);
374  std::string inst_proto = qe2->GetString("name");
375  Agent* inst = BuildAgent(inst_proto, reg);
376 
377  int nfac = qe2->NMatches("initialfacilitylist/entry");
378  for (int k = 0; k < nfac; ++k) {
379  InfileTree* qe3 = qe2->SubTree("initialfacilitylist/entry", k);
380  std::string fac_proto = qe3->GetString("prototype");
381 
382  int number = atoi(qe3->GetString("number").c_str());
383  for (int z = 0; z < number; ++z) {
384  Agent* fac = BuildAgent(fac_proto, inst);
385  }
386  }
387  }
388  }
389 }
390 
392  Agent* m = ctx_->CreateAgent<Agent>(proto);
393  m->Build(parent);
394  if (parent != NULL) {
395  parent->BuildNotify(m);
396  }
397  return m;
398 }
399 
401  InfileTree xqe(*parser_);
402  std::string query = "/*/control";
403  InfileTree* qe = xqe.SubTree(query);
404 
405  std::string handle;
406  if (qe->NMatches("simhandle") > 0) {
407  handle = qe->GetString("simhandle");
408  }
409 
410  // get duration
411  std::string dur_str = qe->GetString("duration");
412  int dur = strtol(dur_str.c_str(), NULL, 10);
413  // get start month
414  std::string m0_str = qe->GetString("startmonth");
415  int m0 = strtol(m0_str.c_str(), NULL, 10);
416  // get start year
417  std::string y0_str = qe->GetString("startyear");
418  int y0 = strtol(y0_str.c_str(), NULL, 10);
419  // get decay mode
420  std::string d = OptionalQuery<std::string>(qe, "decay", "manual");
421 
422  SimInfo si(dur, y0, m0, handle, d);
423 
424  si.explicit_inventory = OptionalQuery<bool>(qe, "explicit_inventory", false);
425  si.explicit_inventory_compact = OptionalQuery<bool>(qe, "explicit_inventory_compact", false);
426 
427  // get time step duration
428  si.dt = OptionalQuery<int>(qe, "dt", kDefaultTimeStepDur);
429 
430  // get epsilon
431  double eps_ = OptionalQuery<double>(qe, "tolerance_generic", 1e-6);
432  cy_eps = si.eps = eps_;
433 
434  // get epsilon resources
435  double eps_rsrc_ = OptionalQuery<double>(qe, "tolerance_resource", 1e-6);
436  cy_eps_rsrc = si.eps_rsrc = eps_rsrc_;
437 
438 
439  ctx_->InitSim(si);
440 }
441 
442 } // namespace cyclus
virtual std::string master_schema()
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
std::string BuildMasterSchema(std::string schema_path, std::string infile)
Builds and returns a master cyclus input xml schema that includes the sub-schemas defined by all inst...
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:164
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:15
Agent * BuildAgent(std::string proto, Agent *parent)
Creates and builds an agent, notifying its parent.
std::string Sanitize()
const std::string kind() const
Returns a string that describes the agent subclass (e.g.
Definition: agent.h:366
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
For validating files received via IO.
Definition: error.h:71
static const bool kDefaultExclusive
default value to allow exclusive orders or not
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:139
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:179
void LoadStringstreamFromFile(std::stringstream &stream, std::string file)
Reads the given file path as XML into the passed stream.
const uint64_t kDefaultTimeStepDur
Definition: context.h:21
for failed reading/writing to files, network connections, etc..
Definition: error.h:59
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_
std::vector< AgentSpec > ParseSpecs(std::string infile)
Returns a list of the full module+agent spec for all agents in the given input file.
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:178
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:12
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:135
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:90
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:73
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:16
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:37
Code providing rudimentary logging capability for the Cyclus core.
A simulation context provides access to necessary simulation-global functions and state...
Definition: context.h:128
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
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.
virtual void LoadSim()
Load an entire simulation from the inputfile.
void Record()
Record this datum to its Recorder.
Definition: datum.cc:24
void LoadSpecs()
Load agent specs from the input file to a map by alias.
virtual const int id() const
The agent instance&#39;s unique ID within a simulation.
Definition: agent.h:354
static Agent * Make(Context *ctx, AgentSpec spec)
Returns a newly constructed agent for the given module spec.
XMLFileLoader(Recorder *r, QueryableBackend *b, std::string schema_file, const std::string input_file="")
Create a new loader reading from the xml simulation input file and writing to and initializing the ba...
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:24
static Ptr CreateFromAtom(CompMap v)
Creates a new composition from v with its components having appropriate atom-based ratios...
Definition: composition.cc:14
Datum * NewDatum(std::string title)
See Recorder::NewDatum documentation.
Definition: context.cc:237
static Ptr CreateFromMass(CompMap v)
Creates a new composition from v with its components having appropriate mass-based ratios...
Definition: composition.cc:26
void DelAgent(Agent *m)
Destructs and cleans up m (and it&#39;s children recursively).
Definition: context.cc:97
Controls simulation timestepping and inter-timestep phases.
Definition: timer.h:22