From 4d1506be0dcd1499e02344f3db224f03d7b1e59f Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Tue, 26 May 2026 12:56:47 -0500 Subject: [PATCH 01/13] updating .gitignore to storp traking cyclus simulation outputs --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2a54233..a80d255 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ cmake-build-*/ example/ #cyclus outputs -.sqlite +*.sqlite # CMake files CMakeCache.txt @@ -29,10 +29,11 @@ __pycache__/ # macOS .DS_Store +*.DS_Store # VSCode .vscode/ # Conda .env -.conda \ No newline at end of file +.conda From 3038269f0947ef86803637ed319f85226ea006f0 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Tue, 26 May 2026 15:52:36 -0500 Subject: [PATCH 02/13] updating .gitignore to include data files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index a80d255..e8c7778 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,11 @@ example/ #cyclus outputs *.sqlite +#data files +*.csv +*.json +*.jsonl + # CMake files CMakeCache.txt CMakeFiles/ From 5e2babab47176108f6ca8eaec12be82f4aef9bad Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Tue, 26 May 2026 15:53:17 -0500 Subject: [PATCH 03/13] adding my code for us_inventory module --- src/us_inventory.cc | 543 ++++++++++++++++++++++++++++++++++++++++++-- src/us_inventory.h | 207 +++++++++++++---- 2 files changed, 690 insertions(+), 60 deletions(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 46e610e..3b1f274 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -1,26 +1,541 @@ #include "us_inventory.h" +#include +#include +#include +#include +#include +#include + +//#include "pyne/nucname.h" + namespace einstein { -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -us_inventory::us_inventory(cyclus::Context* ctx) : cyclus::Facility(ctx) {} +USInventory::USInventory(cyclus::Context* ctx) + : cyclus::Facility(ctx), + total_inventory_kg_(0.0) {} + +USInventory::~USInventory() {} + +void USInventory::InitFrom(USInventory* m) { + #pragma cyclus impl initfromcopy einstein::USInventory + cyclus::toolkit::CommodityProducer::Copy(m); +} + +void USInventory::InitFrom(cyclus::QueryableBackend* b) { + #pragma cyclus impl initfromdb einstein::USInventory + namespace tk = cyclus::toolkit; + tk::CommodityProducer::Add(tk::Commodity(outcommod), + tk::CommodInfo(throughput_kg, throughput_kg)); +} + +std::string USInventory::str() { + std::stringstream ss; + ss << cyclus::Facility::str() + << " USInventory(outcommod=" << outcommod + << ", bins=" << bins_.size() + << ", total_inventory_kg=" << total_inventory_kg_ + << ", throughput_kg=" << throughput_kg + << ", selection_policy=" << selection_policy + << ")"; + return ss.str(); +} + +void USInventory::EnterNotify() { + cyclus::Facility::EnterNotify(); + + if (outcommod.empty()) { + throw cyclus::ValueError("USInventory: outcommod is required."); + } + if (assemblies_file.empty() || composition_file.empty()) { + throw cyclus::ValueError( + "USInventory: assemblies_file and composition_file are required."); + } + + // Validating the selection_policy early so the user gets a clear error. + static const char* valid_policies[] = { + "first", "older", "newer", + "highest_burnup", "lowest_burnup", + "highest_enrichment", "lowest_enrichment"}; + bool policy_ok = false; + for (size_t i = 0; i < 7; ++i) { + if (selection_policy == valid_policies[i]) { policy_ok = true; break; } + } + if (!policy_ok) { + throw cyclus::ValueError( + "USInventory: unknown selection_policy '" + selection_policy + "'. " + "Valid options: first, older, newer, highest_burnup, lowest_burnup, " + "highest_enrichment, lowest_enrichment."); + } + + bins_.clear(); + idx_.clear(); + total_inventory_kg_ = 0.0; + + LoadAssembliesCSV_(assemblies_file); + LoadCompositionCSV_(composition_file); + + + if (!remaining_kg_.empty()) { + if (remaining_kg_.size() != bins_.size()) { + throw cyclus::ValueError( + "USInventory: persisted remaining_kg_ length does not match " + "the number of rows in assemblies_file. Did the CSV change " + "after a checkpoint?"); + } + total_inventory_kg_ = 0.0; + for (size_t i = 0; i < bins_.size(); ++i) { + bins_[i].available_kg = remaining_kg_[i]; + total_inventory_kg_ += remaining_kg_[i]; + } + } else { + // First build: snapshot the initial CSV masses. + remaining_kg_.resize(bins_.size()); + for (size_t i = 0; i < bins_.size(); ++i) { + remaining_kg_[i] = bins_[i].available_kg; + } + } + + for (size_t i = 0; i < bins_.size(); ++i) { + if (bins_[i].comp == NULL) { + throw cyclus::ValueError( + "USInventory: missing composition for assembly_id=" + + bins_[i].assembly_id); + } + } +} + +std::set::Ptr> +USInventory::GetMatlBids( + cyclus::CommodMap::type& commod_requests) { + using cyclus::BidPortfolio; + using cyclus::CapacityConstraint; + using cyclus::Material; + using cyclus::Request; + + std::set::Ptr> ports; + + if (commod_requests.count(outcommod) == 0) { + return ports; + } + + double max_qty = std::min(total_inventory_kg_, throughput_kg); + if (max_qty <= cyclus::eps()) { + return ports; + } + + cyclus::CompMap blended; + double blend_total = 0.0; + for (size_t i = 0; i < bins_.size(); ++i) { + const Bin& b = bins_[i]; + if (b.available_kg <= cyclus::eps() || b.comp == NULL) continue; + const cyclus::CompMap& cm = b.comp->mass(); + for (cyclus::CompMap::const_iterator it = cm.begin(); it != cm.end(); ++it) { + blended[it->first] += it->second * b.available_kg; + } + blend_total += b.available_kg; + } + + if (blend_total <= cyclus::eps()) { + return ports; + } + + for (cyclus::CompMap::iterator it = blended.begin(); + it != blended.end(); ++it) { + it->second /= blend_total; + } + + cyclus::Composition::Ptr bid_comp = + cyclus::Composition::CreateFromMass(blended); + + BidPortfolio::Ptr port(new BidPortfolio()); + std::vector*>& requests = commod_requests[outcommod]; + + for (size_t i = 0; i < requests.size(); ++i) { + Request* req = requests[i]; + double qty = std::min(req->target()->quantity(), max_qty); + if (qty <= cyclus::eps()) continue; + + // When partial fulfillment is forbidden, only bid if we can satisfy the + // full request. + if (!allow_partial && qty < req->target()->quantity()) continue; + + Material::Ptr offer = Material::CreateUntracked(qty, bid_comp); + port->AddBid(req, offer, this); + } + + CapacityConstraint cc(max_qty); + port->AddConstraint(cc); + ports.insert(port); + return ports; +} + +// Choosing a Bin/ SNF assembly + + +size_t USInventory::ChooseBin_(double req_qty, bool full_only) const { + size_t best = bins_.size(); + + for (size_t i = 0; i < bins_.size(); ++i) { + const Bin& b = bins_[i]; + + if (b.comp == NULL || b.available_kg <= cyclus::eps()) continue; + if (full_only && b.available_kg < req_qty) continue; + + // First eligible bin — always accept it as the initial candidate. + if (best == bins_.size()) { + best = i; + continue; + } + + const Bin& cur = bins_[best]; + + if (selection_policy == "first") { + // Keep the first eligible bin; no further comparison needed. + continue; + } else if (selection_policy == "older") { + if (b.discharge_date < cur.discharge_date) best = i; + } else if (selection_policy == "newer") { + if (b.discharge_date > cur.discharge_date) best = i; + } else if (selection_policy == "highest_burnup") { + if (b.burnup > cur.burnup) best = i; + } else if (selection_policy == "lowest_burnup") { + if (b.burnup < cur.burnup) best = i; + } else if (selection_policy == "highest_enrichment") { + if (b.enrichment > cur.enrichment) best = i; + } else if (selection_policy == "lowest_enrichment") { + if (b.enrichment < cur.enrichment) best = i; + } + } + + return best; +} + + +void USInventory::GetMatlTrades( + const std::vector >& trades, + std::vector, + cyclus::Material::Ptr> >& responses) { + double remaining_throughput = throughput_kg; + + for (size_t t = 0; t < trades.size(); ++t) { + const cyclus::Trade& tr = trades[t]; + double req_qty = tr.amt; + + if (req_qty <= cyclus::eps()) continue; + if (remaining_throughput <= cyclus::eps()) break; + if (total_inventory_kg_ <= cyclus::eps()) break; + + // --- Determine how much to send and which bin to draw from ------------- + + // First try to find a single bin that can satisfy the full request. + size_t chosen_i = ChooseBin_(req_qty, /*full_only=*/true); + double actual = 0.0; + + if (chosen_i != bins_.size()) { + // A bin with enough material was found. + actual = std::min(req_qty, remaining_throughput); + if (!allow_partial && actual < req_qty) continue; + } else { + // No single bin can fully satisfy the request. + if (!allow_partial) continue; + + // Partial mode: pick the best bin that has anything at all. + chosen_i = ChooseBin_(req_qty, /*full_only=*/false); + if (chosen_i == bins_.size()) continue; + + actual = std::min({req_qty, + bins_[chosen_i].available_kg, + remaining_throughput}); + } + + if (actual <= cyclus::eps()) continue; + + // --- Draw from the chosen bin + std::vector draw_kg(bins_.size(), 0.0); + draw_kg[chosen_i] = actual; + + Bin& b = bins_[chosen_i]; + b.available_kg -= actual; + total_inventory_kg_ -= actual; + remaining_throughput -= actual; + + remaining_kg_[chosen_i] = b.available_kg; -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -std::string us_inventory::str() { - return Facility::str(); + cyclus::Composition::Ptr comp = BlendedComp_(draw_kg); + cyclus::Material::Ptr mat = + cyclus::Material::CreateUntracked(actual, comp); + + responses.push_back(std::make_pair(tr, mat)); + + LOG(cyclus::LEV_INFO5, "USInventory") + << prototype() << " sent " << actual << " kg of " << outcommod + << " from bin " << b.assembly_id + << " (policy=" << selection_policy << ")"; + } +} + +// BlendedComp_ + +cyclus::Composition::Ptr USInventory::BlendedComp_( + const std::vector& draw_kg) const { + cyclus::CompMap blended; + double total = 0.0; + + for (size_t i = 0; i < bins_.size(); ++i) { + if (draw_kg[i] <= cyclus::eps() || bins_[i].comp == NULL) continue; + const cyclus::CompMap& cm = bins_[i].comp->mass(); + for (cyclus::CompMap::const_iterator it = cm.begin(); + it != cm.end(); ++it) { + blended[it->first] += it->second * draw_kg[i]; + } + total += draw_kg[i]; + } + + if (total > cyclus::eps()) { + for (cyclus::CompMap::iterator it = blended.begin(); + it != blended.end(); ++it) { + it->second /= total; + } + } + + return cyclus::Composition::CreateFromMass(blended); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void us_inventory::Tick() {} +// CSV helpers + +namespace { + +std::vector SplitCSVLine(const std::string& line) { + std::vector out; + std::stringstream ss(line); + std::string item; + while (std::getline(ss, item, ',')) { + item.erase(item.begin(), + std::find_if(item.begin(), item.end(), + [](unsigned char ch) { + return !std::isspace(ch); + })); + item.erase(std::find_if(item.rbegin(), item.rend(), + [](unsigned char ch) { + return !std::isspace(ch); + }).base(), + item.end()); + out.push_back(item); + } + return out; +} + +} + +void USInventory::LoadAssembliesCSV_(const std::string& path) { + std::ifstream f(path.c_str()); + if (!f) throw cyclus::ValueError("USInventory: cannot open " + path); + + std::string header; + if (!std::getline(f, header)) + throw cyclus::ValueError("USInventory: empty file " + path); + + std::vector cols = SplitCSVLine(header); + + // Map column names to indices + int i_id = -1; + int i_mass = -1; + int i_count = -1; + int i_date = -1; + int i_bu = -1; + int i_enr = -1; + + for (size_t i = 0; i < cols.size(); ++i) { + if (cols[i] == "assembly_id") i_id = static_cast(i); + else if (cols[i] == "total_mass_kg") i_mass = static_cast(i); + else if (cols[i] == "count") i_count = static_cast(i); + else if (cols[i] == "discharge_date")i_date = static_cast(i); + else if (cols[i] == "burnup") i_bu = static_cast(i); + else if (cols[i] == "enrichment") i_enr = static_cast(i); + } + + if (i_id < 0 || i_mass < 0) { + throw cyclus::ValueError( + "USInventory: assemblies.csv must contain assembly_id and " + "total_mass_kg columns."); + } + + std::string line; + while (std::getline(f, line)) { + if (line.empty()) continue; + std::vector v = SplitCSVLine(line); + if (static_cast(v.size()) <= std::max(i_id, i_mass)) continue; + + Bin b; + b.assembly_id = v[i_id]; + double mass = std::stod(v[i_mass]); + double count = 1.0; + + if (i_count >= 0 && i_count < static_cast(v.size()) && + !v[i_count].empty()) { + count = std::stod(v[i_count]); + } + + b.available_kg = mass * count; + + if (i_date >= 0 && i_date < static_cast(v.size()) && + !v[i_date].empty()) { + b.discharge_date = std::stod(v[i_date]); + } + + if (i_bu >= 0 && i_bu < static_cast(v.size()) && + !v[i_bu].empty()) { + b.burnup = std::stod(v[i_bu]); + } + + if (i_enr >= 0 && i_enr < static_cast(v.size()) && + !v[i_enr].empty()) { + b.enrichment = std::stod(v[i_enr]); + } + + idx_[b.assembly_id] = bins_.size(); + bins_.push_back(b); + total_inventory_kg_ += b.available_kg; + } + + if (bins_.empty()) + throw cyclus::ValueError("USInventory: no rows loaded from " + path); +} -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void us_inventory::Tock() {} +void USInventory::LoadCompositionCSV_(const std::string& path) { + std::ifstream f(path.c_str()); + if (!f) throw cyclus::ValueError("USInventory: cannot open " + path); + + std::string header; + if (!std::getline(f, header)) + throw cyclus::ValueError("USInventory: empty file " + path); + + std::vector cols = SplitCSVLine(header); + + int i_id = -1; + int i_nuc = -1; + int i_frac = -1; + + for (size_t i = 0; i < cols.size(); ++i) { + if (cols[i] == "assembly_id") i_id = static_cast(i); + else if (cols[i] == "nuclide") i_nuc = static_cast(i); + else if (cols[i] == "mass_fraction") i_frac = static_cast(i); + } + + if (i_id < 0 || i_nuc < 0 || i_frac < 0) { + throw cyclus::ValueError( + "USInventory: composition.csv must contain assembly_id, nuclide, " + "and mass_fraction columns."); + } + + std::unordered_map compmaps; + + std::string line; + while (std::getline(f, line)) { + if (line.empty()) continue; + std::vector v = SplitCSVLine(line); + if (static_cast(v.size()) <= + std::max(i_id, std::max(i_nuc, i_frac))) continue; + + std::string aid = v[i_id]; + std::string nuc = v[i_nuc]; + double frac = std::stod(v[i_frac]); + if (frac <= 0.0) continue; + + int nid = NucIdFromString_(nuc); + compmaps[aid][nid] += frac; + } + + for (std::unordered_map::iterator it = + compmaps.begin(); it != compmaps.end(); ++it) { + std::unordered_map::iterator idx_it = + idx_.find(it->first); + if (idx_it == idx_.end()) continue; + bins_[idx_it->second].comp = + cyclus::Composition::CreateFromMass(it->second); + } +} + +// --------------------------------------------------------------------------- +// Nuclide parsing — I should try using PyNE instead of ZZAAAM. +// --------------------------------------------------------------------------- + +int USInventory::NucIdFromString_(const std::string& s) const { + std::string t = s; + + t.erase( + std::remove_if(t.begin(), t.end(), + [](unsigned char c) { + return c == '-' || std::isspace(c); + }), + t.end()); + + if (t.empty()) { + throw std::runtime_error("Bad nuclide string: '" + s + "'"); + } + + size_t pos = 0; + while (pos < t.size() && std::isalpha(static_cast(t[pos]))) { + pos++; + } + + if (pos == 0 || pos == t.size()) { + throw std::runtime_error("Bad nuclide string: '" + s + "'"); + } + + std::string sym = t.substr(0, pos); + std::string a_str = t.substr(pos); + + sym[0] = std::toupper(static_cast(sym[0])); + for (size_t i = 1; i < sym.size(); ++i) { + sym[i] = std::tolower(static_cast(sym[i])); + } + + int A = std::stoi(a_str); + + if (A <= 0) { + throw std::runtime_error("Bad mass number in nuclide: '" + s + "'"); + } + + static const std::unordered_map Z = { + {"H", 1}, {"He", 2}, {"Li", 3}, {"Be", 4}, {"B", 5}, + {"C", 6}, {"N", 7}, {"O", 8}, {"F", 9}, {"Ne", 10}, + {"Na", 11}, {"Mg", 12}, {"Al", 13}, {"Si", 14}, {"P", 15}, + {"S", 16}, {"Cl", 17}, {"Ar", 18}, {"K", 19}, {"Ca", 20}, + {"Sc", 21}, {"Ti", 22}, {"V", 23}, {"Cr", 24}, {"Mn", 25}, + {"Fe", 26}, {"Co", 27}, {"Ni", 28}, {"Cu", 29}, {"Zn", 30}, + {"Ga", 31}, {"Ge", 32}, {"As", 33}, {"Se", 34}, {"Br", 35}, + {"Kr", 36}, {"Rb", 37}, {"Sr", 38}, {"Y", 39}, {"Zr", 40}, + {"Nb", 41}, {"Mo", 42}, {"Tc", 43}, {"Ru", 44}, {"Rh", 45}, + {"Pd", 46}, {"Ag", 47}, {"Cd", 48}, {"In", 49}, {"Sn", 50}, + {"Sb", 51}, {"Te", 52}, {"I", 53}, {"Xe", 54}, {"Cs", 55}, + {"Ba", 56}, {"La", 57}, {"Ce", 58}, {"Pr", 59}, {"Nd", 60}, + {"Pm", 61}, {"Sm", 62}, {"Eu", 63}, {"Gd", 64}, {"Tb", 65}, + {"Dy", 66}, {"Ho", 67}, {"Er", 68}, {"Tm", 69}, {"Yb", 70}, + {"Lu", 71}, {"Hf", 72}, {"Ta", 73}, {"W", 74}, {"Re", 75}, + {"Os", 76}, {"Ir", 77}, {"Pt", 78}, {"Au", 79}, {"Hg", 80}, + {"Tl", 81}, {"Pb", 82}, {"Bi", 83}, {"Po", 84}, {"At", 85}, + {"Rn", 86}, {"Fr", 87}, {"Ra", 88}, {"Ac", 89}, {"Th", 90}, + {"Pa", 91}, {"U", 92}, {"Np", 93}, {"Pu", 94}, {"Am", 95}, + {"Cm", 96}}; + + auto it = Z.find(sym); + + if (it == Z.end()) { + throw std::runtime_error( + "Unknown element symbol in nuclide: '" + s + "' parsed as '" + + sym + "'"); + } + + int z = it->second; + int zzaaam = z * 10000 + A * 10; + + return zzaaam; +} -// WARNING! Do not change the following this function!!! This enables your -// archetype to be dynamically loaded and any alterations will cause your -// archetype to fail. -extern "C" cyclus::Agent* Constructus_inventory(cyclus::Context* ctx) { - return new us_inventory(ctx); +extern "C" cyclus::Agent* ConstructUSInventory(cyclus::Context* ctx) { + return new USInventory(ctx); } } // namespace einstein diff --git a/src/us_inventory.h b/src/us_inventory.h index cab97a4..24e2bfe 100644 --- a/src/us_inventory.h +++ b/src/us_inventory.h @@ -1,66 +1,181 @@ -#ifndef CYCLUS_EINSTEIN_US_INVENTORY_H_ -#define CYCLUS_EINSTEIN_US_INVENTORY_H_ +#ifndef EINSTEIN_SRC_US_INVENTORY_H_ +#define EINSTEIN_SRC_US_INVENTORY_H_ +#include #include +#include +#include #include "cyclus.h" +#pragma cyclus exec from cyclus.system import CY_LARGE_DOUBLE + namespace einstein { -/// @class us_inventory -/// -/// This Facility is intended -/// as a skeleton to guide the implementation of new Facility -/// agents. -/// The us_inventory class inherits from the Facility class and is -/// dynamically loaded by the Agent class when requested. -/// -/// @section intro Introduction -/// Place an introduction to the agent here. -/// -/// @section agentparams Agent Parameters -/// Place a description of the required input parameters which define the -/// agent implementation. -/// -/// @section optionalparams Optional Parameters -/// Place a description of the optional input parameters to define the -/// agent implementation. -/// -/// @section detailed Detailed Behavior -/// Place a description of the detailed behavior of the agent. Consider -/// describing the behavior at the tick and tock as well as the behavior -/// upon sending and receiving materials and messages. -class us_inventory : public cyclus::Facility { +/// This facility represents a supply inventory of used nuclear fuel assemblies. +/// It reads assembly masses and isotopic compositions from CSV files, stores +/// them internally as inventory bins, and offers material on a configured +/// output commodity. Material is supplied from the available bins subject to a +/// per-timestep throughput limit. +class USInventory : public cyclus::Facility, + public cyclus::toolkit::CommodityProducer, + public cyclus::toolkit::Position { + public: - /// Constructor for us_inventory Class - /// @param ctx the cyclus context for access to simulation-wide parameters - explicit us_inventory(cyclus::Context* ctx); + USInventory(cyclus::Context* ctx); + virtual ~USInventory(); + + #pragma cyclus note { \ + "doc": "This facility represents a supply inventory of used nuclear fuel " \ + "assemblies. It reads assembly masses and isotopic compositions " \ + "from CSV files, stores them internally as inventory bins, and " \ + "offers material on a configured output commodity. Material is " \ + "supplied from the available bins subject to a per-timestep " \ + "throughput limit.", \ + } - /// The Prime Directive - /// Generates code that handles all input file reading and restart operations - /// (e.g., reading from the database, instantiating a new object, etc.). - /// @warning The Prime Directive must have a space before it! (A fix will be - /// in 2.0 ^TM) + #pragma cyclus def clone + #pragma cyclus def schema + #pragma cyclus def annotations + #pragma cyclus def infiletodb + #pragma cyclus def snapshot + #pragma cyclus def snapshotinv + #pragma cyclus def initinv - #pragma cyclus + virtual void InitFrom(USInventory* m); + virtual void InitFrom(cyclus::QueryableBackend* b); - #pragma cyclus note {"doc": "A stub facility is provided as a skeleton " \ - "for the design of new facility agents."} + virtual void Tick() {}; + + virtual void Tock() {}; - /// A verbose printer for the us_inventory virtual std::string str(); + virtual void EnterNotify(); + + virtual std::set::Ptr> + GetMatlBids(cyclus::CommodMap::type& commod_requests); + + virtual void GetMatlTrades( + const std::vector >& trades, + std::vector, + cyclus::Material::Ptr> >& responses); + + private: + // Cyclus state variables + + #pragma cyclus var { \ + "tooltip": "Commodity this facility supplies.", \ + "doc": "Output commodity on which the USInventory facility offers " \ + "used nuclear fuel material.", \ + "uilabel": "Output Commodity", \ + "uitype": "outcommodity", \ + } + std::string outcommod; + + #pragma cyclus var { \ + "tooltip": "Path to assemblies CSV file.", \ + "doc": "Path to a CSV file containing assembly IDs and total available " \ + "masses. Required columns: assembly_id, total_mass_kg. " \ + "Optional columns: count, discharge_date, burnup, enrichment.", \ + "uilabel": "Assemblies File", \ + } + std::string assemblies_file; + + #pragma cyclus var { \ + "tooltip": "Path to composition CSV file.", \ + "doc": "Path to a CSV file containing isotopic mass fractions for each " \ + "assembly. Required columns: assembly_id, nuclide, mass_fraction.", \ + "uilabel": "Composition File", \ + } + std::string composition_file; + + #pragma cyclus var { \ + "default": CY_LARGE_DOUBLE, \ + "tooltip": "Maximum material mass this facility can supply per time step.", \ + "units": "kg/(time step)", \ + "uilabel": "Maximum Throughput", \ + "uitype": "range", \ + "range": [0.0, CY_LARGE_DOUBLE], \ + "doc": "Amount of commodity that can be supplied at each time step.", \ + } + double throughput_kg; - /// The handleTick function specific to the us_inventory. - /// @param time the time of the tick - virtual void Tick(); + #pragma cyclus var { \ + "default": True, \ + "tooltip": "Allow partial fulfillment of material requests.", \ + "doc": "If true, the facility may partially satisfy a material trade when " \ + "the requested mass exceeds the available mass or remaining " \ + "throughput. If false, trades are only fulfilled when the full " \ + "requested quantity can be supplied.", \ + "uilabel": "Allow Partial Fulfillment", \ + } + bool allow_partial; - /// The handleTick function specific to the us_inventory. - /// @param time the time of the tock - virtual void Tock(); + #pragma cyclus var { \ + "default": "first", \ + "tooltip": "Policy used to select which bin to draw from.", \ + "doc": "Controls which assembly bin is chosen when fulfilling a trade. " \ + "Options: " \ + "'first' - always pick the earliest bin with available material; " \ + "'older' - prefer the bin with the smallest discharge_date; " \ + "'newer' - prefer the bin with the largest discharge_date; " \ + "'highest_burnup' - prefer the bin with the highest burnup; " \ + "'lowest_burnup' - prefer the bin with the lowest burnup; " \ + "'highest_enrichment' - prefer the bin with the highest initial enrichment; " \ + "'lowest_enrichment' - prefer the bin with the lowest initial enrichment.", \ + "uilabel": "Bin Selection Policy", \ + } + std::string selection_policy; - // And away we go! + #pragma cyclus var { \ + "default": [], \ + "doc": "Persisted remaining mass (kg) for each assembly bin. " \ + "Managed internally — do not set by hand.", \ + "uilabel": "Remaining Masses (internal)", \ + } + std::vector remaining_kg_; + + // --------------------------------------------------------------------------- + // Internal (non-persisted) data structures + // --------------------------------------------------------------------------- + + /// One entry per assembly (or assembly group) read from the CSV. + struct Bin { + std::string assembly_id; + double available_kg = 0.0; + double discharge_date = 0.0; // optional: used by older/newer policy + double burnup = 0.0; // optional: used by highest/lowest_burnup + double enrichment = 0.0; // optional: used by highest/lowest_enrichment + cyclus::Composition::Ptr comp; + }; + + std::vector bins_; + std::unordered_map idx_; // assembly_id -> bins_ index + double total_inventory_kg_; // running total for fast checks + + // --------------------------------------------------------------------------- + // Private helpers + // --------------------------------------------------------------------------- + + /// Return the index of the best bin for a trade of req_qty kg according to + /// selection_policy. If full_only is true only bins that can fully satisfy + /// req_qty are considered. Returns bins_.size() if no suitable bin is found. + size_t ChooseBin_(double req_qty, bool full_only) const; + + /// Build a Composition that is a mass-weighted blend of the bins drawn from. + /// draw_kg[i] is the mass drawn from bins_[i]. + cyclus::Composition::Ptr BlendedComp_( + const std::vector& draw_kg) const; + + void LoadAssembliesCSV_(const std::string& path); + void LoadCompositionCSV_(const std::string& path); + + /// Convert a nuclide string (e.g. "U-235", "U235", "92235") to a PyNE id. + int NucIdFromString_(const std::string& s) const; }; } // namespace einstein -#endif // CYCLUS_EINSTEIN_US_INVENTORY_H_ + +#endif // EINSTEIN_SRC_US_INVENTORY_H_ + From b3349541a4a3fb24ad2f729bbcaff0c79b7d6dc6 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Tue, 26 May 2026 16:23:08 -0500 Subject: [PATCH 04/13] updating the class name in my code from USInventory to us_inventory --- examples/trial3.xml | 83 +++++++++++++++++++++++++++++++++++++++++++++ src/us_inventory.cc | 62 ++++++++++++++++----------------- src/us_inventory.h | 10 +++--- 3 files changed, 119 insertions(+), 36 deletions(-) create mode 100644 examples/trial3.xml diff --git a/examples/trial3.xml b/examples/trial3.xml new file mode 100644 index 0000000..faa5757 --- /dev/null +++ b/examples/trial3.xml @@ -0,0 +1,83 @@ + + + + + 10 + 1 + 2000 + + + + + einstein + us_inventory + + + cycamore + Sink + + + agents + NullRegion + + + agents + NullInst + + + + + us_inventory + 5 + + + commodity + assemblies.csv + composition.csv + commod_recipe + 1 + + + + + + Sink + + + + commodity + + 1 + + + + + + SingleRegion + + + SingleInstitution + + + Source + 1 + + + Sink + 1 + + + + + + + + commod_recipe + mass + + 010010000 + 1 + + + + diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 3b1f274..0027f00 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -11,28 +11,28 @@ namespace einstein { -USInventory::USInventory(cyclus::Context* ctx) +us_inventory::us_inventory(cyclus::Context* ctx) : cyclus::Facility(ctx), total_inventory_kg_(0.0) {} -USInventory::~USInventory() {} +us_inventory::~us_inventory() {} -void USInventory::InitFrom(USInventory* m) { - #pragma cyclus impl initfromcopy einstein::USInventory +void us_inventory::InitFrom(us_inventory* m) { + #pragma cyclus impl initfromcopy einstein::us_inventory cyclus::toolkit::CommodityProducer::Copy(m); } -void USInventory::InitFrom(cyclus::QueryableBackend* b) { - #pragma cyclus impl initfromdb einstein::USInventory +void us_inventory::InitFrom(cyclus::QueryableBackend* b) { + #pragma cyclus impl initfromdb einstein::us_inventory namespace tk = cyclus::toolkit; tk::CommodityProducer::Add(tk::Commodity(outcommod), tk::CommodInfo(throughput_kg, throughput_kg)); } -std::string USInventory::str() { +std::string us_inventory::str() { std::stringstream ss; ss << cyclus::Facility::str() - << " USInventory(outcommod=" << outcommod + << " us_inventory(outcommod=" << outcommod << ", bins=" << bins_.size() << ", total_inventory_kg=" << total_inventory_kg_ << ", throughput_kg=" << throughput_kg @@ -41,15 +41,15 @@ std::string USInventory::str() { return ss.str(); } -void USInventory::EnterNotify() { +void us_inventory::EnterNotify() { cyclus::Facility::EnterNotify(); if (outcommod.empty()) { - throw cyclus::ValueError("USInventory: outcommod is required."); + throw cyclus::ValueError("us_inventory: outcommod is required."); } if (assemblies_file.empty() || composition_file.empty()) { throw cyclus::ValueError( - "USInventory: assemblies_file and composition_file are required."); + "us_inventory: assemblies_file and composition_file are required."); } // Validating the selection_policy early so the user gets a clear error. @@ -63,7 +63,7 @@ void USInventory::EnterNotify() { } if (!policy_ok) { throw cyclus::ValueError( - "USInventory: unknown selection_policy '" + selection_policy + "'. " + "us_inventory: unknown selection_policy '" + selection_policy + "'. " "Valid options: first, older, newer, highest_burnup, lowest_burnup, " "highest_enrichment, lowest_enrichment."); } @@ -79,7 +79,7 @@ void USInventory::EnterNotify() { if (!remaining_kg_.empty()) { if (remaining_kg_.size() != bins_.size()) { throw cyclus::ValueError( - "USInventory: persisted remaining_kg_ length does not match " + "us_inventory: persisted remaining_kg_ length does not match " "the number of rows in assemblies_file. Did the CSV change " "after a checkpoint?"); } @@ -99,14 +99,14 @@ void USInventory::EnterNotify() { for (size_t i = 0; i < bins_.size(); ++i) { if (bins_[i].comp == NULL) { throw cyclus::ValueError( - "USInventory: missing composition for assembly_id=" + + "us_inventory: missing composition for assembly_id=" + bins_[i].assembly_id); } } } std::set::Ptr> -USInventory::GetMatlBids( +us_inventory::GetMatlBids( cyclus::CommodMap::type& commod_requests) { using cyclus::BidPortfolio; using cyclus::CapacityConstraint; @@ -173,7 +173,7 @@ USInventory::GetMatlBids( // Choosing a Bin/ SNF assembly -size_t USInventory::ChooseBin_(double req_qty, bool full_only) const { +size_t us_inventory::ChooseBin_(double req_qty, bool full_only) const { size_t best = bins_.size(); for (size_t i = 0; i < bins_.size(); ++i) { @@ -212,7 +212,7 @@ size_t USInventory::ChooseBin_(double req_qty, bool full_only) const { } -void USInventory::GetMatlTrades( +void us_inventory::GetMatlTrades( const std::vector >& trades, std::vector, cyclus::Material::Ptr> >& responses) { @@ -268,7 +268,7 @@ void USInventory::GetMatlTrades( responses.push_back(std::make_pair(tr, mat)); - LOG(cyclus::LEV_INFO5, "USInventory") + LOG(cyclus::LEV_INFO5, "us_inventory") << prototype() << " sent " << actual << " kg of " << outcommod << " from bin " << b.assembly_id << " (policy=" << selection_policy << ")"; @@ -277,7 +277,7 @@ void USInventory::GetMatlTrades( // BlendedComp_ -cyclus::Composition::Ptr USInventory::BlendedComp_( +cyclus::Composition::Ptr us_inventory::BlendedComp_( const std::vector& draw_kg) const { cyclus::CompMap blended; double total = 0.0; @@ -328,13 +328,13 @@ std::vector SplitCSVLine(const std::string& line) { } -void USInventory::LoadAssembliesCSV_(const std::string& path) { +void us_inventory::LoadAssembliesCSV_(const std::string& path) { std::ifstream f(path.c_str()); - if (!f) throw cyclus::ValueError("USInventory: cannot open " + path); + if (!f) throw cyclus::ValueError("us_inventory: cannot open " + path); std::string header; if (!std::getline(f, header)) - throw cyclus::ValueError("USInventory: empty file " + path); + throw cyclus::ValueError("us_inventory: empty file " + path); std::vector cols = SplitCSVLine(header); @@ -357,7 +357,7 @@ void USInventory::LoadAssembliesCSV_(const std::string& path) { if (i_id < 0 || i_mass < 0) { throw cyclus::ValueError( - "USInventory: assemblies.csv must contain assembly_id and " + "us_inventory: assemblies.csv must contain assembly_id and " "total_mass_kg columns."); } @@ -400,16 +400,16 @@ void USInventory::LoadAssembliesCSV_(const std::string& path) { } if (bins_.empty()) - throw cyclus::ValueError("USInventory: no rows loaded from " + path); + throw cyclus::ValueError("us_inventory: no rows loaded from " + path); } -void USInventory::LoadCompositionCSV_(const std::string& path) { +void us_inventory::LoadCompositionCSV_(const std::string& path) { std::ifstream f(path.c_str()); - if (!f) throw cyclus::ValueError("USInventory: cannot open " + path); + if (!f) throw cyclus::ValueError("us_inventory: cannot open " + path); std::string header; if (!std::getline(f, header)) - throw cyclus::ValueError("USInventory: empty file " + path); + throw cyclus::ValueError("us_inventory: empty file " + path); std::vector cols = SplitCSVLine(header); @@ -425,7 +425,7 @@ void USInventory::LoadCompositionCSV_(const std::string& path) { if (i_id < 0 || i_nuc < 0 || i_frac < 0) { throw cyclus::ValueError( - "USInventory: composition.csv must contain assembly_id, nuclide, " + "us_inventory: composition.csv must contain assembly_id, nuclide, " "and mass_fraction columns."); } @@ -461,7 +461,7 @@ void USInventory::LoadCompositionCSV_(const std::string& path) { // Nuclide parsing — I should try using PyNE instead of ZZAAAM. // --------------------------------------------------------------------------- -int USInventory::NucIdFromString_(const std::string& s) const { +int us_inventory::NucIdFromString_(const std::string& s) const { std::string t = s; t.erase( @@ -534,8 +534,8 @@ int USInventory::NucIdFromString_(const std::string& s) const { return zzaaam; } -extern "C" cyclus::Agent* ConstructUSInventory(cyclus::Context* ctx) { - return new USInventory(ctx); +extern "C" cyclus::Agent* Constructus_inventory(cyclus::Context* ctx) { + return new us_inventory(ctx); } } // namespace einstein diff --git a/src/us_inventory.h b/src/us_inventory.h index 24e2bfe..5b90b05 100644 --- a/src/us_inventory.h +++ b/src/us_inventory.h @@ -17,13 +17,13 @@ namespace einstein { /// them internally as inventory bins, and offers material on a configured /// output commodity. Material is supplied from the available bins subject to a /// per-timestep throughput limit. -class USInventory : public cyclus::Facility, +class us_inventory : public cyclus::Facility, public cyclus::toolkit::CommodityProducer, public cyclus::toolkit::Position { public: - USInventory(cyclus::Context* ctx); - virtual ~USInventory(); + us_inventory(cyclus::Context* ctx); + virtual ~us_inventory(); #pragma cyclus note { \ "doc": "This facility represents a supply inventory of used nuclear fuel " \ @@ -42,7 +42,7 @@ class USInventory : public cyclus::Facility, #pragma cyclus def snapshotinv #pragma cyclus def initinv - virtual void InitFrom(USInventory* m); + virtual void InitFrom(us_inventory* m); virtual void InitFrom(cyclus::QueryableBackend* b); virtual void Tick() {}; @@ -65,7 +65,7 @@ class USInventory : public cyclus::Facility, #pragma cyclus var { \ "tooltip": "Commodity this facility supplies.", \ - "doc": "Output commodity on which the USInventory facility offers " \ + "doc": "Output commodity on which the us_inventory facility offers " \ "used nuclear fuel material.", \ "uilabel": "Output Commodity", \ "uitype": "outcommodity", \ From 362ff8170a2e1c40e87c601a64b71bcd859ba527 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 09:12:23 -0500 Subject: [PATCH 05/13] fixing the nucid value to match cyclus format --- src/us_inventory.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 0027f00..d545a73 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -529,7 +529,7 @@ int us_inventory::NucIdFromString_(const std::string& s) const { } int z = it->second; - int zzaaam = z * 10000 + A * 10; + int zzaaam = z * 10000000 + A * 10000; return zzaaam; } From b52bc2c80c61dfa07a6ac95e30a8dff078a9d3ab Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 09:18:33 -0500 Subject: [PATCH 06/13] adding more elements to the nuclide parsing function --- examples/trial3.xml | 10 ++++------ src/us_inventory.cc | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/trial3.xml b/examples/trial3.xml index faa5757..6c0eeac 100644 --- a/examples/trial3.xml +++ b/examples/trial3.xml @@ -28,14 +28,12 @@ us_inventory - 5 commodity - assemblies.csv - composition.csv - commod_recipe - 1 + ./assemblies.csv + ./composition.csv + 1000 @@ -59,7 +57,7 @@ SingleInstitution - Source + us_inventory 1 diff --git a/src/us_inventory.cc b/src/us_inventory.cc index d545a73..22c6051 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -518,7 +518,8 @@ int us_inventory::NucIdFromString_(const std::string& s) const { {"Tl", 81}, {"Pb", 82}, {"Bi", 83}, {"Po", 84}, {"At", 85}, {"Rn", 86}, {"Fr", 87}, {"Ra", 88}, {"Ac", 89}, {"Th", 90}, {"Pa", 91}, {"U", 92}, {"Np", 93}, {"Pu", 94}, {"Am", 95}, - {"Cm", 96}}; + {"Cm", 96}, {"Bk", 97}, {"Cf", 98}, {"Es", 99}, {"Fm", 100}, + {"Md", 101},{"No", 102},{"Lr", 103}}; auto it = Z.find(sym); From 8b53a047c35e071c0657d185e9882ec234ea4f8d Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 09:42:48 -0500 Subject: [PATCH 07/13] editing the discharge date of the assembly to capture the year only not the full date --- src/us_inventory.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 22c6051..73ffc8b 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -381,7 +381,7 @@ void us_inventory::LoadAssembliesCSV_(const std::string& path) { if (i_date >= 0 && i_date < static_cast(v.size()) && !v[i_date].empty()) { - b.discharge_date = std::stod(v[i_date]); + b.discharge_date = std::stod(v[i_date].substr(0, 4)); } if (i_bu >= 0 && i_bu < static_cast(v.size()) && From 9df1d860167344091f922966fd004a78a576b844 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 10:22:40 -0500 Subject: [PATCH 08/13] adding initialize position to EnterNoyify function --- src/us_inventory.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 73ffc8b..975d912 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -43,6 +43,7 @@ std::string us_inventory::str() { void us_inventory::EnterNotify() { cyclus::Facility::EnterNotify(); + InitializePosition(); if (outcommod.empty()) { throw cyclus::ValueError("us_inventory: outcommod is required."); From 5e77e7b1083aabf73722fe5ab4deab43c98d8506 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 10:27:23 -0500 Subject: [PATCH 09/13] editing the allow partial condition --- src/us_inventory.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 975d912..984f0e4 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -236,7 +236,7 @@ void us_inventory::GetMatlTrades( if (chosen_i != bins_.size()) { // A bin with enough material was found. actual = std::min(req_qty, remaining_throughput); - if (!allow_partial && actual < req_qty) continue; + if (!allow_partial && bins_[chosen_i].available_kg < req_qty) continue; } else { // No single bin can fully satisfy the request. if (!allow_partial) continue; From 6f41299009f876795809691a60064fedb956458b Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 10:56:42 -0500 Subject: [PATCH 10/13] editing nuclide from string function to get rid of the metastable m in elements name in data files --- src/us_inventory.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 984f0e4..1674837 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -488,6 +488,13 @@ int us_inventory::NucIdFromString_(const std::string& s) const { std::string sym = t.substr(0, pos); std::string a_str = t.substr(pos); + // Strip trailing metastable indicator ('m') + // e.g. "108m" -> "108" + size_t m_pos = a_str.find_first_not_of("0123456789"); + if (m_pos != std::string::npos) { + a_str = a_str.substr(0, m_pos); // keep only the digits + } + sym[0] = std::toupper(static_cast(sym[0])); for (size_t i = 1; i < sym.size(); ++i) { sym[i] = std::tolower(static_cast(sym[i])); From 26b61df2dac9989c6b35a377c425c1a5d1cfdf63 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 11:15:07 -0500 Subject: [PATCH 11/13] removing the intialize position part entirely as it was causeing a build error --- src/us_inventory.cc | 1 - src/us_inventory.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 1674837..522e50a 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -43,7 +43,6 @@ std::string us_inventory::str() { void us_inventory::EnterNotify() { cyclus::Facility::EnterNotify(); - InitializePosition(); if (outcommod.empty()) { throw cyclus::ValueError("us_inventory: outcommod is required."); diff --git a/src/us_inventory.h b/src/us_inventory.h index 5b90b05..d205308 100644 --- a/src/us_inventory.h +++ b/src/us_inventory.h @@ -18,8 +18,7 @@ namespace einstein { /// output commodity. Material is supplied from the available bins subject to a /// per-timestep throughput limit. class us_inventory : public cyclus::Facility, - public cyclus::toolkit::CommodityProducer, - public cyclus::toolkit::Position { + public cyclus::toolkit::CommodityProducer { public: us_inventory(cyclus::Context* ctx); From 09ca53b3bf6d0b2f1f63f87c48cda8477839185c Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 13:08:18 -0500 Subject: [PATCH 12/13] input files are all working properly --- examples/trial3.xml | 81 --------------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 examples/trial3.xml diff --git a/examples/trial3.xml b/examples/trial3.xml deleted file mode 100644 index 6c0eeac..0000000 --- a/examples/trial3.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - 10 - 1 - 2000 - - - - - einstein - us_inventory - - - cycamore - Sink - - - agents - NullRegion - - - agents - NullInst - - - - - us_inventory - - - commodity - ./assemblies.csv - ./composition.csv - 1000 - - - - - - Sink - - - - commodity - - 1 - - - - - - SingleRegion - - - SingleInstitution - - - us_inventory - 1 - - - Sink - 1 - - - - - - - - commod_recipe - mass - - 010010000 - 1 - - - - From 46f982b2071fa95a3403150c1f112760277d078a Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 27 May 2026 13:08:52 -0500 Subject: [PATCH 13/13] input files are all working properly --- examples/trial1.xml | 83 +++++++++++++++++++++++++++++++++++++++++++++ examples/trial2.xml | 82 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 examples/trial1.xml create mode 100644 examples/trial2.xml diff --git a/examples/trial1.xml b/examples/trial1.xml new file mode 100644 index 0000000..3490946 --- /dev/null +++ b/examples/trial1.xml @@ -0,0 +1,83 @@ + + + + + 500 + 1 + 2024 +
2628000
+ 1 +
+ + + + einstein + us_inventory + + + cycamore + Sink + + + agents + NullRegion + + + agents + NullInst + + + + + + us_inventory + + + spent_fuel + ./assemblies.csv + ./composition.csv + + + + + + Sink + + + + spent_fuel + + 10000 + + + + + + SingleRegion + + + SingleInstitution + + + us_inventory + 1 + + + Sink + 1 + + + + + + + + commod_recipe + mass + + 010010000 + 1 + + + +
\ No newline at end of file diff --git a/examples/trial2.xml b/examples/trial2.xml new file mode 100644 index 0000000..a69393e --- /dev/null +++ b/examples/trial2.xml @@ -0,0 +1,82 @@ + + + + + 10 + 1 + 2000 + 1 + + + + + einstein + us_inventory + + + cycamore + Sink + + + agents + NullRegion + + + agents + NullInst + + + + + us_inventory + + + commodity + ./assemblies.csv + ./composition.csv + 1000 + + + + + + Sink + + + + commodity + + 1 + + + + + + SingleRegion + + + SingleInstitution + + + us_inventory + 1 + + + Sink + 1 + + + + + + + + commod_recipe + mass + + 010010000 + 1 + + + +