From 888cd5513510dce7feef3c1c3d012a3e92c75f1a Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Wed, 18 Mar 2026 12:54:16 -0500 Subject: [PATCH 1/3] fixing bins info, adding preference, and adding detailed material composition --- src/us_inventory.cc | 526 +++++++++++++++++++++++++++++++------------- src/us_inventory.h | 113 +++++++--- 2 files changed, 457 insertions(+), 182 deletions(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 9a348a3..359f33f 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -1,22 +1,54 @@ #include "us_inventory.h" +#include +#include #include #include #include -#include -#include -#include "toolkit/mat_query.h" // optional, but sometimes useful +namespace cycamore { -USInventory::USInventory(cyclus::Context* ctx) : cyclus::Facility(ctx) {} +// ---------------------------------------------------------------------- +// Constructor / Destructor +// ---------------------------------------------------------------------- + +USInventory::USInventory(cyclus::Context* ctx) + : cyclus::Facility(ctx), + total_inventory_kg_(0.0) {} USInventory::~USInventory() {} +// ---------------------------------------------------------------------- +// Cyclus boilerplate +// ---------------------------------------------------------------------- + +#pragma cyclus def schema cycamore::USInventory +#pragma cyclus def annotations cycamore::USInventory +#pragma cyclus def initinv cycamore::USInventory +#pragma cyclus def snapshotinv cycamore::USInventory +#pragma cyclus def infiletodb cycamore::USInventory +#pragma cyclus def snapshot cycamore::USInventory +#pragma cyclus def clone cycamore::USInventory + +void USInventory::InitFrom(USInventory* m) { +#pragma cyclus impl initfromcopy cycamore::USInventory +} + +void USInventory::InitFrom(cyclus::QueryableBackend* b) { +#pragma cyclus impl initfromdb cycamore::USInventory +} + +// ---------------------------------------------------------------------- +// Basic facility methods +// ---------------------------------------------------------------------- + std::string USInventory::str() { std::stringstream ss; ss << cyclus::Facility::str() << " USInventory(outcommod=" << outcommod - << ", bins=" << bins_.size() << ")"; + << ", bins=" << bins_.size() + << ", total_inventory_kg=" << total_inventory_kg_ + << ")"; return ss.str(); } @@ -24,295 +56,475 @@ void USInventory::EnterNotify() { cyclus::Facility::EnterNotify(); if (outcommod.empty()) { - throw std::runtime_error("USInventory: outcommod is required."); + throw cyclus::ValueError("USInventory: outcommod is required."); } + if (assemblies_file.empty() || composition_file.empty()) { - throw std::runtime_error("USInventory: assemblies_file and composition_file are required."); + throw cyclus::ValueError( + "USInventory: assemblies_file and composition_file are required."); } bins_.clear(); idx_.clear(); + total_inventory_kg_ = 0.0; LoadAssembliesCSV_(assemblies_file); LoadCompositionCSV_(composition_file); - // Sanity check: every bin must have a composition - for (const auto& b : bins_) { - if (b.comp == nullptr) { - throw std::runtime_error("USInventory: missing composition for assembly_id=" + b.assembly_id); + // Sanity check: every loaded bin must have a composition + 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); } } } -// ------------------------- DRE Methods ------------------------- +void USInventory::Tick() {} + +void USInventory::Tock() {} + +// ---------------------------------------------------------------------- +// DRE Methods +// ---------------------------------------------------------------------- void USInventory::GetMatlBids( cyclus::CommodMap::type& commod_requests, cyclus::BidPortfolio::type& bids) { - // Only respond to our commodity - auto it = commod_requests.find(outcommod); + cyclus::CommodMap::type::iterator it = + commod_requests.find(outcommod); + if (it == commod_requests.end()) { return; } - // Total available in all bins - double total_avail = 0.0; - for (const auto& b : bins_) total_avail += b.available_kg; + if (total_inventory_kg_ <= 0.0 || throughput_kg <= 0.0) { + return; + } - if (total_avail <= 0.0) return; + // Pick one valid composition for bid offers. + // This is just to create a valid offer object for the bid. + cyclus::Composition::Ptr bid_comp = NULL; + for (size_t i = 0; i < bins_.size(); ++i) { + if (bins_[i].available_kg > 0.0 && bins_[i].comp != NULL) { + bid_comp = bins_[i].comp; + break; + } + } - // Total requested mass - double total_req = 0.0; - for (auto& req : it->second) { - total_req += req->target()->quantity(); + if (bid_comp == NULL) { + return; } - if (total_req <= 0.0) return; - // Throughput limit per timestep - double can_supply = std::min(total_avail, throughput_kg); + double remaining_bid_capacity = std::min(total_inventory_kg_, throughput_kg); - // Create bids: simplest strategy = bid on every request with same “capacity” - // Cyclus will allocate trades; we finalize exact masses in GetMatlTrades. std::vector*>& reqs = it->second; + for (size_t i = 0; i < reqs.size(); ++i) { + cyclus::Request* req = reqs[i]; + double req_qty = req->target()->quantity(); - for (auto* r : reqs) { - // Bid some positive quantity. We'll honor final trade mass later. - // Use a dummy material for the bid with any valid comp (use first non-empty bin). - cyclus::Composition::Ptr c = nullptr; - for (const auto& b : bins_) { - if (b.available_kg > 0.0 && b.comp != nullptr) { c = b.comp; break; } + if (req_qty <= 0.0 || remaining_bid_capacity <= 0.0) { + continue; } - if (c == nullptr) return; - double q = std::min(r->target()->quantity(), can_supply); - if (q <= 0.0) continue; + double offer_qty = std::min(req_qty, remaining_bid_capacity); + cyclus::Material::Ptr offer = + cyclus::Material::CreateUntracked(offer_qty, bid_comp); + + bids.AddBid(req, offer, this, outcommod); - auto offer = cyclus::Material::Create(this->context(), q, c); - bids.AddBid(r, offer, this, outcommod); + // This prevents wildly overbidding across many requests. + remaining_bid_capacity -= offer_qty; } } +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 <= 0.0) { + continue; + } + + if (full_only && b.available_kg < req_qty) { + continue; + } + + if (best == bins_.size()) { + best = i; + continue; + } + + const Bin& cur = bins_[best]; + + if (selection_policy == "first") { + // keep the first eligible bin + 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; + } + } else { + // fallback if user gives unknown policy + continue; + } + } + + return best; +} + void USInventory::GetMatlTrades( - const std::vector< cyclus::Trade >& trades, - std::vector< std::pair< cyclus::Trade, - cyclus::Material::Ptr > >& responses) { + const std::vector >& trades, + std::vector, + cyclus::Material::Ptr> >& responses) { double remaining_throughput = throughput_kg; - for (const auto& tr : trades) { - double q = tr.amt; // requested trade quantity (kg) - if (q <= 0.0) continue; + for (size_t t = 0; t < trades.size(); ++t) { + const cyclus::Trade& tr = trades[t]; + double req_qty = tr.amt; - if (!allow_partial) { - // If partial not allowed, you can reject trades not fully satisfiable. - // Here we simply skip if we can't supply fully. - double total_avail = 0.0; - for (const auto& b : bins_) total_avail += b.available_kg; - if (q > total_avail || q > remaining_throughput) continue; + if (req_qty <= 0.0) { + continue; } - // Cap by throughput - double send = std::min(q, remaining_throughput); - if (send <= 0.0) break; - - // Withdraw mass from bins FIFO - // If you want “closest match” by burnup/enr later, this is where you’d choose bins differently. - cyclus::Composition::Ptr chosen_comp = nullptr; - double to_make = send; - - // We may need to split across bins with different compositions. - // For now: simplest policy = take from the first bin with enough mass. - // If not enough, we’ll take what we can from a bin and keep going, - // BUT composition would change. To keep it consistent per trade, - // we instead enforce: fulfill each trade from a single bin. - size_t chosen_i = bins_.size(); - for (size_t i = 0; i < bins_.size(); ++i) { - if (bins_[i].available_kg > 0.0) { - chosen_i = i; - break; + if (remaining_throughput <= 0.0 || total_inventory_kg_ <= 0.0) { + break; + } + + size_t chosen_i = ChooseBin_(req_qty, true); + double actual = 0.0; + + if (chosen_i != bins_.size()) { + actual = std::min(req_qty, remaining_throughput); + + if (!allow_partial && actual < req_qty) { + continue; + } + } else { + if (!allow_partial) { + continue; + } + + chosen_i = ChooseBin_(req_qty, false); + if (chosen_i == bins_.size()) { + continue; } + + actual = std::min(req_qty, + std::min(bins_[chosen_i].available_kg, + remaining_throughput)); + } + + if (chosen_i == bins_.size() || actual <= 0.0) { + continue; } - if (chosen_i == bins_.size()) continue; Bin& b = bins_[chosen_i]; - chosen_comp = b.comp; - double max_from_bin = std::min(b.available_kg, remaining_throughput); - double actual = allow_partial ? std::min(to_make, max_from_bin) : to_make; + actual = std::min(actual, b.available_kg); + actual = std::min(actual, remaining_throughput); - if (actual <= 0.0) continue; + if (actual <= 0.0) { + continue; + } - // Decrement inventory b.available_kg -= actual; + total_inventory_kg_ -= actual; remaining_throughput -= actual; - // Create the material response - auto mat = cyclus::Material::Create(this->context(), actual, chosen_comp); + cyclus::Material::Ptr mat = + cyclus::Material::Create(context(), actual, b.comp); + responses.push_back(std::make_pair(tr, mat)); } } -// ------------------------- CSV Loading ------------------------- +// ---------------------------------------------------------------------- +// CSV Helpers +// ---------------------------------------------------------------------- + +namespace { -static std::vector SplitCSVLine(const std::string& line) { - // Simple CSV splitter (no quoted commas). Good enough if your files are simple. +std::vector SplitCSVLine(const std::string& line) { std::vector out; std::stringstream ss(line); std::string item; + while (std::getline(ss, item, ',')) { - // trim whitespace - 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()); + 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; } +} // namespace + void USInventory::LoadAssembliesCSV_(const std::string& path) { std::ifstream f(path.c_str()); - if (!f) throw std::runtime_error("USInventory: cannot open " + path); + if (!f) { + throw cyclus::ValueError("USInventory: cannot open " + path); + } std::string header; - if (!std::getline(f, header)) throw std::runtime_error("USInventory: empty file " + path); - auto cols = SplitCSVLine(header); - - auto col_index = [&](const std::string& name) -> int { - for (size_t i = 0; i < cols.size(); ++i) if (cols[i] == name) return (int)i; - return -1; - }; + if (!std::getline(f, header)) { + throw cyclus::ValueError("USInventory: empty file " + path); + } - int i_id = col_index("assembly_id"); - int i_mass = col_index("total_mass_kg"); - int i_count = col_index("count"); // optional + std::vector cols = SplitCSVLine(header); + + 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 = i; + } else if (cols[i] == "total_mass_kg") { + i_mass = i; + } else if (cols[i] == "count") { + i_count = i; + } else if (cols[i] == "discharge_date") { + i_date = i; + } else if (cols[i] == "burnup") { + i_bu = i; + } else if (cols[i] == "enrichment") { + i_enr = i; + } + } if (i_id < 0 || i_mass < 0) { - throw std::runtime_error("USInventory: assemblies.csv must contain assembly_id and total_mass_kg"); + throw cyclus::ValueError( + "USInventory: assemblies.csv must contain assembly_id and total_mass_kg"); } std::string line; while (std::getline(f, line)) { - if (line.empty()) continue; - auto v = SplitCSVLine(line); - if ((int)v.size() <= std::max(i_id, i_mass)) continue; + if (line.empty()) { + continue; + } + + std::vector v = SplitCSVLine(line); + if ((int)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 < (int)v.size() && !v[i_count].empty()) { count = std::stod(v[i_count]); } + b.available_kg = mass * count; + if (i_date >= 0 && i_date < (int)v.size() && !v[i_date].empty()) { + b.discharge_date = std::stoi(v[i_date]); + } + + if (i_bu >= 0 && i_bu < (int)v.size() && !v[i_bu].empty()) { + b.burnup = std::stod(v[i_bu]); + } + + if (i_enr >= 0 && i_enr < (int)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 std::runtime_error("USInventory: no rows loaded from " + path); + throw cyclus::ValueError("USInventory: no rows loaded from " + path); } } void USInventory::LoadCompositionCSV_(const std::string& path) { std::ifstream f(path.c_str()); - if (!f) throw std::runtime_error("USInventory: cannot open " + path); + if (!f) { + throw cyclus::ValueError("USInventory: cannot open " + path); + } std::string header; - if (!std::getline(f, header)) throw std::runtime_error("USInventory: empty file " + path); - auto cols = SplitCSVLine(header); + if (!std::getline(f, header)) { + throw cyclus::ValueError("USInventory: empty file " + path); + } + + std::vector cols = SplitCSVLine(header); - auto col_index = [&](const std::string& name) -> int { - for (size_t i = 0; i < cols.size(); ++i) if (cols[i] == name) return (int)i; - return -1; - }; + int i_id = -1; + int i_nuc = -1; + int i_frac = -1; - int i_id = col_index("assembly_id"); - int i_nuc = col_index("nuclide"); - int i_frac = col_index("mass_fraction"); + for (size_t i = 0; i < cols.size(); ++i) { + if (cols[i] == "assembly_id") { + i_id = i; + } else if (cols[i] == "nuclide") { + i_nuc = i; + } else if (cols[i] == "mass_fraction") { + i_frac = i; + } + } if (i_id < 0 || i_nuc < 0 || i_frac < 0) { - throw std::runtime_error("USInventory: composition.csv must contain assembly_id, nuclide, mass_fraction"); + throw cyclus::ValueError( + "USInventory: composition.csv must contain assembly_id, nuclide, mass_fraction"); } - // Build comp maps per assembly_id std::unordered_map compmaps; std::string line; while (std::getline(f, line)) { - if (line.empty()) continue; - auto v = SplitCSVLine(line); - if ((int)v.size() <= std::max({i_id, i_nuc, i_frac})) continue; + if (line.empty()) { + continue; + } + + std::vector v = SplitCSVLine(line); + if ((int)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; + + if (frac <= 0.0) { + continue; + } int nid = NucIdFromString_(nuc); - compmaps[aid][nid] += frac; // += in case of duplicates + compmaps[aid][nid] += frac; } - // Create cyclus compositions and assign to bins - for (auto& kv : compmaps) { - const std::string& aid = kv.first; - auto it = idx_.find(aid); - if (it == idx_.end()) continue; // composition for an assembly not in assemblies.csv (skip) - // CreateFromMass expects mass fractions or masses; relative values are fine. - bins_[it->second].comp = cyclus::Composition::CreateFromMass(kv.second); + 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 ------------------------- +// ---------------------------------------------------------------------- +// Nuclide Parsing +// ---------------------------------------------------------------------- int USInventory::NucIdFromString_(const std::string& s) const { - // Minimal parser for strings like "U235", "Pu239", "Cs137". - // Produces zzaaam * 10? Cyclus commonly uses zzaaam format (e.g., 922350). - // We'll return zzaaam where m=0. - // If your dataset uses other forms (e.g., "U-235" or "92235"), tell me and I’ll adjust. - std::string t = s; - // Remove '-' and spaces - 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 + "'"); - // Split leading letters (element) + trailing digits (A) + t.erase(std::remove_if(t.begin(), t.end(), + [](unsigned char c) { + return c == '-' || std::isspace(c); + }), + t.end()); + + if (t.empty()) { + throw cyclus::ValueError("Bad nuclide string: '" + s + "'"); + } + size_t pos = 0; - while (pos < t.size() && std::isalpha((unsigned char)t[pos])) pos++; - if (pos == 0 || pos == t.size()) throw std::runtime_error("Bad nuclide string: '" + s + "'"); + while (pos < t.size() && std::isalpha(static_cast(t[pos]))) { + ++pos; + } + + if (pos == 0 || pos == t.size()) { + throw cyclus::ValueError("Bad nuclide string: '" + s + "'"); + } std::string sym = t.substr(0, pos); std::string a_str = t.substr(pos); - // Normalize symbol: first uppercase, rest lowercase - sym[0] = std::toupper((unsigned char)sym[0]); - for (size_t i = 1; i < sym.size(); ++i) sym[i] = std::tolower((unsigned char)sym[i]); + 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 + "'"); + if (A <= 0) { + throw cyclus::ValueError("Bad mass number in nuclide: '" + s + "'"); + } - // Small element->Z map (extend as needed). Tell me if you have lots of elements beyond these. 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 '" + sym + "')"); + {"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}}; + + std::unordered_map::const_iterator it = Z.find(sym); + if (it == Z.end()) { + throw cyclus::ValueError( + "Unknown element symbol in nuclide: '" + s + "'"); + } int z = it->second; - int zzaaam = z*10000 + A*10 + 0; // m=0 + int zzaaam = z * 10000 + A * 10; return zzaaam; } -// ---------- Cyclus boilerplate ---------- -#pragma cyclus impl \ No newline at end of file +// ---------------------------------------------------------------------- +// Plugin Constructor +// ---------------------------------------------------------------------- + +extern "C" cyclus::Agent* ConstructUSInventory(cyclus::Context* ctx) { + return new USInventory(ctx); +} + +} // namespace cycamore \ No newline at end of file diff --git a/src/us_inventory.h b/src/us_inventory.h index 47bf4c9..7c372a5 100644 --- a/src/us_inventory.h +++ b/src/us_inventory.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef CYCAMORE_US_INVENTORY_H_ +#define CYCAMORE_US_INVENTORY_H_ #include #include @@ -6,57 +7,119 @@ #include "cyclus.h" #include "cyclus_facility.h" +#include "cycamore_version.h" + +namespace cycamore { class USInventory : public cyclus::Facility { public: - USInventory(cyclus::Context* ctx); + explicit USInventory(cyclus::Context* ctx); virtual ~USInventory(); - // --- Cyclus hooks --- - virtual void EnterNotify(); - virtual std::string str(); - - // --- DRE (Material supplier) --- - virtual void GetMatlBids(cyclus::CommodMap::type& commod_requests, - cyclus::BidPortfolio::type& bids); + #pragma cyclus decl - virtual void GetMatlTrades(const std::vector< cyclus::Trade >& trades, - std::vector< std::pair< cyclus::Trade, - cyclus::Material::Ptr > >& responses); + virtual void InitFrom(USInventory* m); + virtual void InitFrom(cyclus::QueryableBackend* b); - // --- Configurable parameters (set via XML) --- - #pragma cyclus var {"tooltip":"Commodity this facility supplies (e.g., pwr_snf)."} + /// Cyclus hooks + virtual void EnterNotify(); + virtual std::string str(); + virtual void Tick(); + virtual void Tock(); + virtual std::string version() { return CYCAMORE_VERSION; } + + /// Material supplier interface + virtual void GetMatlBids( + cyclus::CommodMap::type& commod_requests, + cyclus::BidPortfolio::type& bids); + + virtual void GetMatlTrades( + const std::vector >& trades, + std::vector, + cyclus::Material::Ptr> >& responses); + + #pragma cyclus note {"doc": "USInventory is a source-like facility that loads " + "spent nuclear fuel inventory data at initialization " + "and supplies material to other facilities on request. " + "It does not accept incoming commodities."} + + /// Output commodity + #pragma cyclus var {"tooltip":"Commodity supplied by this facility.", \ + "doc":"Commodity name offered to requesting facilities.", \ + "uilabel":"Output Commodity", \ + "uitype":"outcommodity"} std::string outcommod; - #pragma cyclus var {"tooltip":"Path to assemblies.csv"} + /// File containing assembly inventory data + #pragma cyclus var {"tooltip":"Path to assemblies CSV file."} std::string assemblies_file; - #pragma cyclus var {"tooltip":"Path to composition.csv"} + /// File containing isotopic composition data + #pragma cyclus var {"tooltip":"Path to composition CSV file."} std::string composition_file; - #pragma cyclus var {"default":1e99, "tooltip":"Max kg this facility can supply per timestep."} + /// Maximum mass supplied per timestep + #pragma cyclus var {"default": 1e99, \ + "tooltip":"Maximum mass supplied per timestep (kg).", \ + "units":"kg"} double throughput_kg; - #pragma cyclus var {"default":true, "tooltip":"Allow partial fulfillment (mass-based)."} + /// Whether partial requests may be fulfilled + #pragma cyclus var {"default": true, \ + "tooltip":"Allow partial fulfillment of requests."} bool allow_partial; - private: + /// Bin selection policy + #pragma cyclus var {"default":"first", \ + "tooltip":"Bin selection policy: first, older, newer, highest_burnup, lowest_burnup, highest_enrichment, lowest_enrichment."} + std::string selection_policy; + + protected: struct Bin { std::string assembly_id; - double available_kg = 0.0; // remaining mass + double available_kg; cyclus::Composition::Ptr comp; + + int discharge_date; + double burnup; + double enrichment; + + Bin() + : assembly_id(""), + available_kg(0.0), + comp(), + discharge_date(0), + burnup(0.0), + enrichment(0.0) {} }; - // Storage: bins in FIFO order + /// Inventory bins loaded from the database std::vector bins_; - // Fast lookup: assembly_id -> index in bins_ + /// Fast lookup from assembly id to bin index std::unordered_map idx_; - // Helper: CSV loading + /// Total available mass in all bins + double total_inventory_kg_; + + /// Helper methods for loading data void LoadAssembliesCSV_(const std::string& path); void LoadCompositionCSV_(const std::string& path); - // Helper: Convert nuclide string (e.g., "U235") to nuc id (zzaaam) + /// Helper for choosing a bin according to policy + size_t ChooseBin_(double req_qty, bool full_only) const; + + /// Helper for nuclide-name parsing int NucIdFromString_(const std::string& s) const; -}; \ No newline at end of file + + friend class USInventoryTest; + + private: + // Code Injection + #include "toolkit/matl_sell_policy.cycpp.h" + #include "toolkit/position.cycpp.h" +}; + +} // namespace cycamore + +#endif // CYCAMORE_US_INVENTORY_H_ \ No newline at end of file From 724e69564e951f9576339ef94f0408089b6070e9 Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Tue, 7 Apr 2026 00:56:56 -0500 Subject: [PATCH 2/3] adding cmake files --- cmake/FindCyclus.cmake | 207 +++++++++++++++++++++++++++++++++ cmake/cmake_uninstall.cmake.in | 22 ++++ install.py | 158 +++++++++++++++++++++++++ src/us_inventory.cc | 31 +---- 4 files changed, 393 insertions(+), 25 deletions(-) create mode 100644 cmake/FindCyclus.cmake create mode 100644 cmake/cmake_uninstall.cmake.in create mode 100644 install.py diff --git a/cmake/FindCyclus.cmake b/cmake/FindCyclus.cmake new file mode 100644 index 0000000..f7e2e44 --- /dev/null +++ b/cmake/FindCyclus.cmake @@ -0,0 +1,207 @@ +# CYCLUS_CORE_FOUND - system has the Cyclus Core library +# CYCLUS_CORE_INCLUDE_DIR - the Cyclus include directory +# CYCLUS_CORE_LIBRARIES - The libraries needed to use the Cyclus Core Library +# CYCLUS_AGENT_TEST_LIBRARIES - A test library for agents +# CYCLUS_TEST_LIBRARIES - All testing libraries +# CYCLUS_DEFAULT_TEST_DRIVER - The default cyclus unit test driver + +# Check if we have an environment variable for cyclus root +if(DEFINED ENV{CYCLUS_ROOT_DIR}) + if(NOT DEFINED CYCLUS_ROOT_DIR) + set(CYCLUS_ROOT_DIR "$ENV{CYCLUS_ROOT_DIR}") + else() + message(STATUS "\tTwo CYCLUS_ROOT_DIRs have been found:") + message(STATUS "\t\tThe defined cmake variable CYCLUS_ROOT_DIR: ${CYCLUS_ROOT_DIR}") + message(STATUS "\t\tThe environment variable CYCLUS_ROOT_DIR: $ENV{CYCLUS_ROOT_DIR}") + endif() +elseif(DEFINED ENV{CONDA_PREFIX}) + if(NOT DEFINED CYCLUS_ROOT_DIR) + set(CYCLUS_ROOT_DIR "$ENV{CONDA_PREFIX}") + endif() +else() + find_program(CYCLUS_BIN cyclus) + if(CYCLUS_BIN) + execute_process( + COMMAND ${CYCLUS_BIN} --install-path + OUTPUT_VARIABLE CYCLUS_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + message(FATAL_ERROR + "Could not determine CYCLUS_ROOT_DIR. " + "Please set CYCLUS_ROOT_DIR or use a Conda environment with Cyclus installed.") + endif() +endif() + +# Let the user know if we're using a hint +message(STATUS "Using ${CYCLUS_ROOT_DIR} as CYCLUS_ROOT_DIR.") + +# Use $DEPS_ROOT_DIR if available +if(DEFINED DEPS_ROOT_DIR AND DEPS_ROOT_DIR) + set(DEPS_CYCLUS "${DEPS_ROOT_DIR}" + "${DEPS_ROOT_DIR}/cyclus") + set(DEPS_LIB_CYCLUS "${DEPS_ROOT_DIR}" + "${DEPS_ROOT_DIR}/cyclus" + "${DEPS_ROOT_DIR}/lib") + set(DEPS_SHARE_CYCLUS "${DEPS_ROOT_DIR}/share" + "${DEPS_ROOT_DIR}/share/cyclus") + set(DEPS_INCLUDE_CYCLUS "${DEPS_ROOT_DIR}/include" + "${DEPS_ROOT_DIR}/include/cyclus") +else() + set(DEPS_CYCLUS) + set(DEPS_LIB_CYCLUS) + set(DEPS_SHARE_CYCLUS) + set(DEPS_INCLUDE_CYCLUS) +endif() + +message(STATUS "-- Dependency Cyclus (DEPS_CYCLUS): ${DEPS_CYCLUS}") +message(STATUS "-- Dependency Library Cyclus (DEPS_LIB_CYCLUS): ${DEPS_LIB_CYCLUS}") +message(STATUS "-- Dependency Share Cyclus (DEPS_SHARE_CYCLUS): ${DEPS_SHARE_CYCLUS}") +message(STATUS "-- Dependency Include Cyclus (DEPS_INCLUDE_CYCLUS): ${DEPS_INCLUDE_CYCLUS}") + +# Set the include dir, this will be the future basis for other defined dirs +find_path(CYCLUS_CORE_INCLUDE_DIR cyclus.h + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + "${CYCLUS_ROOT_DIR}/include" + "${CYCLUS_ROOT_DIR}/include/cyclus" + ${DEPS_INCLUDE_CYCLUS} + /usr/local/cyclus /opt/local/cyclus + PATH_SUFFIXES cyclus/include include include/cyclus) + +# Set the include dir for test headers +find_path(CYCLUS_CORE_TEST_INCLUDE_DIR agent_tests.h + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus/tests" + "${CYCLUS_ROOT_DIR}/include" + "${CYCLUS_ROOT_DIR}/include/cyclus/tests" + ${DEPS_INCLUDE_CYCLUS} + /usr/local/cyclus /opt/local/cyclus + PATH_SUFFIXES cyclus/include include include/cyclus include/cyclus/tests cyclus/include/tests) + +# Add the root dir to the hints +set(CYCLUS_ROOT_DIR "${CYCLUS_CORE_INCLUDE_DIR}/../..") + +# Look for the shared data files +find_path(CYCLUS_CORE_SHARE_DIR cyclus.rng.in + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + "${CYCLUS_ROOT_DIR}/share" "${CYCLUS_ROOT_DIR}/share/cyclus" + ${DEPS_SHARE_CYCLUS} + /usr/local/cyclus /opt/local/cyclus + PATH_SUFFIXES cyclus/share share) + +# Look for the main library +find_library(CYCLUS_CORE_LIBRARY NAMES cyclus + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + ${DEPS_CYCLUS} + /usr/local/cyclus/lib /usr/local/cyclus + /opt/local /opt/local/cyclus + PATH_SUFFIXES cyclus/lib lib) + +# Optional libraries, only present if Cyclus was built with Cython support +find_library(CYCLUS_EVENTHOOKS_LIBRARY NAMES eventhooks + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + ${DEPS_CYCLUS} + /usr/local/cyclus/lib /usr/local/cyclus + /opt/local /opt/local/cyclus + PATH_SUFFIXES cyclus/lib lib) + +find_library(CYCLUS_PYINFILE_LIBRARY NAMES pyinfile + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + ${DEPS_CYCLUS} + /usr/local/cyclus/lib /usr/local/cyclus + /opt/local /opt/local/cyclus + PATH_SUFFIXES cyclus/lib lib) + +find_library(CYCLUS_PYMODULE_LIBRARY NAMES pymodule + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + ${DEPS_CYCLUS} + /usr/local/cyclus/lib /usr/local/cyclus + /opt/local /opt/local/cyclus + PATH_SUFFIXES cyclus/lib lib) + +# Look for the test libraries +find_library(CYCLUS_AGENT_TEST_LIBRARY NAMES baseagentunittests + HINTS "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + ${DEPS_CYCLUS} + /usr/local/cyclus/lib /usr/local/cyclus + /opt/local /opt/local/cyclus + PATH_SUFFIXES cyclus/lib lib lib/cyclus) + +find_library(CYCLUS_GTEST_LIBRARY NAMES gtest + HINTS "${CYCLUS_ROOT_DIR}/lib/cyclus" + "${CYCLUS_ROOT_DIR}" "${CYCLUS_ROOT_DIR}/cyclus" + "${CYCLUS_ROOT_DIR}/lib" "${CYCLUS_CORE_SHARE_DIR}/../lib" + ${DEPS_LIB_CYCLUS} + /usr/local/cyclus/lib /usr/local/cyclus + /opt/local/lib /opt/local/cyclus/lib + PATH_SUFFIXES cyclus/lib lib) + +# Copy the results to the output variables. +if(CYCLUS_CORE_INCLUDE_DIR AND CYCLUS_CORE_TEST_INCLUDE_DIR + AND CYCLUS_CORE_LIBRARY AND CYCLUS_GTEST_LIBRARY + AND CYCLUS_CORE_SHARE_DIR AND CYCLUS_AGENT_TEST_LIBRARY) + + set(CYCLUS_CORE_FOUND 1) + set(CYCLUS_CORE_LIBRARIES "${CYCLUS_CORE_LIBRARY}") + + # If Cyclus was installed without Cython, these may not exist. + if(NOT "${CYCLUS_EVENTHOOKS_LIBRARY}" STREQUAL "CYCLUS_EVENTHOOKS_LIBRARY-NOTFOUND") + list(APPEND CYCLUS_CORE_LIBRARIES "${CYCLUS_EVENTHOOKS_LIBRARY}") + endif() + + if(NOT "${CYCLUS_PYINFILE_LIBRARY}" STREQUAL "CYCLUS_PYINFILE_LIBRARY-NOTFOUND") + list(APPEND CYCLUS_CORE_LIBRARIES "${CYCLUS_PYINFILE_LIBRARY}") + endif() + + if(NOT "${CYCLUS_PYMODULE_LIBRARY}" STREQUAL "CYCLUS_PYMODULE_LIBRARY-NOTFOUND") + list(APPEND CYCLUS_CORE_LIBRARIES "${CYCLUS_PYMODULE_LIBRARY}") + endif() + + set(CYCLUS_TEST_LIBRARIES "${CYCLUS_GTEST_LIBRARY}" "${CYCLUS_AGENT_TEST_LIBRARY}") + set(CYCLUS_AGENT_TEST_LIBRARIES "${CYCLUS_AGENT_TEST_LIBRARY}") + set(CYCLUS_CORE_INCLUDE_DIRS "${CYCLUS_CORE_INCLUDE_DIR}") + set(CYCLUS_CORE_TEST_INCLUDE_DIRS "${CYCLUS_CORE_TEST_INCLUDE_DIR}") + set(CYCLUS_CORE_SHARE_DIRS "${CYCLUS_CORE_SHARE_DIR}") + set(CYCLUS_DEFAULT_TEST_DRIVER "${CYCLUS_CORE_SHARE_DIR}/cyclus_default_unit_test_driver.cc") +else() + set(CYCLUS_CORE_FOUND 0) + set(CYCLUS_CORE_LIBRARIES) + set(CYCLUS_TEST_LIBRARIES) + set(CYCLUS_AGENT_TEST_LIBRARIES) + set(CYCLUS_CORE_INCLUDE_DIRS) + set(CYCLUS_CORE_TEST_INCLUDE_DIRS) + set(CYCLUS_CORE_SHARE_DIRS) + set(CYCLUS_DEFAULT_TEST_DRIVER) +endif() + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CYCLUS_CORE_INCLUDE_DIR}/../../share/cyclus/cmake) + +# Report the results. +if(CYCLUS_CORE_FOUND) + set(CYCLUS_CORE_DIR_MESSAGE "Found Cyclus Core Headers : ${CYCLUS_CORE_INCLUDE_DIRS}") + set(CYCLUS_CORE_TEST_DIR_MESSAGE "Found Cyclus Core Test Headers : ${CYCLUS_CORE_TEST_INCLUDE_DIRS}") + set(CYCLUS_CORE_SHARE_MESSAGE "Found Cyclus Core Shared Data : ${CYCLUS_CORE_SHARE_DIRS}") + set(CYCLUS_CORE_LIB_MESSAGE "Found Cyclus Core Library : ${CYCLUS_CORE_LIBRARIES}") + set(CYCLUS_TEST_LIB_MESSAGE "Found Cyclus Test Libraries : ${CYCLUS_TEST_LIBRARIES}") + message(STATUS "${CYCLUS_CORE_DIR_MESSAGE}") + message(STATUS "${CYCLUS_CORE_TEST_DIR_MESSAGE}") + message(STATUS "${CYCLUS_CORE_SHARE_MESSAGE}") + message(STATUS "${CYCLUS_CORE_LIB_MESSAGE}") + message(STATUS "${CYCLUS_TEST_LIB_MESSAGE}") +else() + set(CYCLUS_CORE_DIR_MESSAGE + "Cyclus was not found. Make sure CYCLUS_CORE_LIBRARY and CYCLUS_CORE_INCLUDE_DIR are set.") + if(NOT Cyclus_FIND_QUIETLY) + message(STATUS "${CYCLUS_CORE_DIR_MESSAGE}") + message(STATUS "CYCLUS_CORE_SHARE_DIR was set to : ${CYCLUS_CORE_SHARE_DIR}") + message(STATUS "CYCLUS_CORE_LIBRARY was set to : ${CYCLUS_CORE_LIBRARY}") + message(STATUS "CYCLUS_TEST_LIBRARIES was set to : ${CYCLUS_GTEST_LIBRARY}") + if(Cyclus_FIND_REQUIRED) + message(FATAL_ERROR "${CYCLUS_CORE_DIR_MESSAGE}") + endif() + endif() +endif() + +mark_as_advanced( + CYCLUS_CORE_INCLUDE_DIR + CYCLUS_CORE_LIBRARY +) \ No newline at end of file diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..78789af --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,22 @@ +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +list(REVERSE files) +foreach(file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if(EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif(NOT ${rm_retval} EQUAL 0) + else(EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif(EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) \ No newline at end of file diff --git a/install.py b/install.py new file mode 100644 index 0000000..656c242 --- /dev/null +++ b/install.py @@ -0,0 +1,158 @@ +#! /usr/bin/env python3 +import os +import sys +import subprocess +import shutil + +try: + import argparse as ap +except ImportError: + import pyne._argparse as ap + + +def absexpanduser(x): + return os.path.abspath(os.path.expanduser(x)) + + +def default_prefix(): + return os.environ.get("CONDA_PREFIX", sys.prefix) + + +def check_windows_cmake(cmake_cmd): + if os.name != 'nt': + return cmake_cmd + + files_on_path = set() + for p in os.environ.get('PATH', '').split(';')[::-1]: + if os.path.exists(p): + try: + files_on_path.update(os.listdir(p)) + except OSError: + pass + + if 'cl.exe' in files_on_path: + pass + elif 'sh.exe' in files_on_path: + cmake_cmd += ['-G', 'MSYS Makefiles'] + elif 'gcc.exe' in files_on_path: + cmake_cmd += ['-G', 'MinGW Makefiles'] + + return cmake_cmd + + +def install(args): + if os.path.exists(args.build_dir) and args.clean_build: + shutil.rmtree(args.build_dir) + + if not os.path.exists(args.build_dir): + os.mkdir(args.build_dir) + + root_dir = os.path.abspath(os.path.dirname(__file__)) + + # Always re-run cmake unless build_only is intended to skip reconfigure. + cmake_cmd = ['cmake', root_dir] + + if args.prefix: + cmake_cmd += ['-DCMAKE_INSTALL_PREFIX=' + absexpanduser(args.prefix)] + + if args.cmake_prefix_path: + cmake_cmd += ['-DCMAKE_PREFIX_PATH=' + absexpanduser(args.cmake_prefix_path)] + + if args.coin_root: + cmake_cmd += ['-DCOIN_ROOT_DIR=' + absexpanduser(args.coin_root)] + + if args.cyclus_root: + cmake_cmd += ['-DCYCLUS_ROOT_DIR=' + absexpanduser(args.cyclus_root)] + + if args.boost_root: + cmake_cmd += ['-DBOOST_ROOT=' + absexpanduser(args.boost_root)] + + if args.build_type: + cmake_cmd += ['-DCMAKE_BUILD_TYPE=' + args.build_type] + + cmake_cmd = check_windows_cmake(cmake_cmd) + + subprocess.check_call(cmake_cmd, cwd=args.build_dir, + shell=(os.name == 'nt')) + + build_cmd = ['make'] + if args.threads: + build_cmd += ['-j' + str(args.threads)] + + subprocess.check_call(build_cmd, cwd=args.build_dir, + shell=(os.name == 'nt')) + + if args.test: + test_cmd = ['make', 'test'] + subprocess.check_call(test_cmd, cwd=args.build_dir, + shell=(os.name == 'nt')) + elif not args.build_only: + install_cmd = ['make', 'install'] + subprocess.check_call(install_cmd, cwd=args.build_dir, + shell=(os.name == 'nt')) + + +def uninstall(args): + makefile = os.path.join(args.build_dir, 'Makefile') + if not os.path.exists(args.build_dir) or not os.path.exists(makefile): + sys.exit("May not uninstall because it has not yet been built.") + + subprocess.check_call(['make', 'uninstall'], cwd=args.build_dir, + shell=(os.name == 'nt')) + + +def main(): + default_install = default_prefix() + + description = ( + "An installation helper script for building and installing this Cyclus " + "archetype module." + ) + parser = ap.ArgumentParser(description=description) + + parser.add_argument('--build_dir', default='build', + help='where to place the build directory') + + parser.add_argument('--uninstall', action='store_true', default=False, + help='uninstall') + + parser.add_argument('--clean-build', action='store_true', + help='remove the build directory before building') + + parser.add_argument('-j', '--threads', type=int, + help='number of threads to use in make') + + parser.add_argument('--prefix', default=default_install, + help='installation prefix (default: CONDA_PREFIX or sys.prefix)') + + parser.add_argument('--build-only', action='store_true', + help='only build the package, do not install') + + parser.add_argument('--test', action='store_true', + help='run tests after building') + + parser.add_argument('--coin_root', + help='path to the Coin-OR libraries directory') + + parser.add_argument('--cyclus_root', + help='path to Cyclus installation directory') + + parser.add_argument('--boost_root', + help='path to Boost libraries directory') + + parser.add_argument('--cmake_prefix_path', + help='CMAKE_PREFIX_PATH for find_package/find_library') + + parser.add_argument('--build_type', + help='CMAKE_BUILD_TYPE') + + args = parser.parse_args() + + if args.uninstall: + uninstall(args) + else: + install(args) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 359f33f..6e2367b 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -8,10 +8,6 @@ namespace cycamore { -// ---------------------------------------------------------------------- -// Constructor / Destructor -// ---------------------------------------------------------------------- - USInventory::USInventory(cyclus::Context* ctx) : cyclus::Facility(ctx), total_inventory_kg_(0.0) {} @@ -19,7 +15,7 @@ USInventory::USInventory(cyclus::Context* ctx) USInventory::~USInventory() {} // ---------------------------------------------------------------------- -// Cyclus boilerplate +// Cyclus // ---------------------------------------------------------------------- #pragma cyclus def schema cycamore::USInventory @@ -71,7 +67,7 @@ void USInventory::EnterNotify() { LoadAssembliesCSV_(assemblies_file); LoadCompositionCSV_(composition_file); - // Sanity check: every loaded bin must have a composition + // for (size_t i = 0; i < bins_.size(); ++i) { if (bins_[i].comp == NULL) { throw cyclus::ValueError( @@ -453,6 +449,7 @@ void USInventory::LoadCompositionCSV_(const std::string& path) { // ---------------------------------------------------------------------- // Nuclide Parsing +// should use material class instead // ---------------------------------------------------------------------- int USInventory::NucIdFromString_(const std::string& s) const { @@ -489,24 +486,10 @@ int USInventory::NucIdFromString_(const std::string& s) const { if (A <= 0) { throw cyclus::ValueError("Bad mass number in nuclide: '" + s + "'"); } - + // example of isotopes definision till I add the actual ones, or find out how to use materials class 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}}; + }; std::unordered_map::const_iterator it = Z.find(sym); if (it == Z.end()) { @@ -519,9 +502,7 @@ int USInventory::NucIdFromString_(const std::string& s) const { return zzaaam; } -// ---------------------------------------------------------------------- -// Plugin Constructor -// ---------------------------------------------------------------------- + extern "C" cyclus::Agent* ConstructUSInventory(cyclus::Context* ctx) { return new USInventory(ctx); From 87b4f8dce7233a5b393bfb780d34337c6751f92b Mon Sep 17 00:00:00 2001 From: Samar Abdelkawy Date: Tue, 7 Apr 2026 01:06:37 -0500 Subject: [PATCH 3/3] changing namespace to from cycamore to einstein --- src/us_inventory.cc | 22 +++++++++++----------- src/us_inventory.h | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/us_inventory.cc b/src/us_inventory.cc index 6e2367b..a67411e 100644 --- a/src/us_inventory.cc +++ b/src/us_inventory.cc @@ -6,7 +6,7 @@ #include #include -namespace cycamore { +namespace einstein { USInventory::USInventory(cyclus::Context* ctx) : cyclus::Facility(ctx), @@ -18,20 +18,20 @@ USInventory::~USInventory() {} // Cyclus // ---------------------------------------------------------------------- -#pragma cyclus def schema cycamore::USInventory -#pragma cyclus def annotations cycamore::USInventory -#pragma cyclus def initinv cycamore::USInventory -#pragma cyclus def snapshotinv cycamore::USInventory -#pragma cyclus def infiletodb cycamore::USInventory -#pragma cyclus def snapshot cycamore::USInventory -#pragma cyclus def clone cycamore::USInventory +#pragma cyclus def schema einstein::USInventory +#pragma cyclus def annotations einstein::USInventory +#pragma cyclus def initinv einstein::USInventory +#pragma cyclus def snapshotinv einstein::USInventory +#pragma cyclus def infiletodb einstein::USInventory +#pragma cyclus def snapshot einstein::USInventory +#pragma cyclus def clone einstein::USInventory void USInventory::InitFrom(USInventory* m) { -#pragma cyclus impl initfromcopy cycamore::USInventory +#pragma cyclus impl initfromcopy einstein::USInventory } void USInventory::InitFrom(cyclus::QueryableBackend* b) { -#pragma cyclus impl initfromdb cycamore::USInventory +#pragma cyclus impl initfromdb einstein::USInventory } // ---------------------------------------------------------------------- @@ -508,4 +508,4 @@ extern "C" cyclus::Agent* ConstructUSInventory(cyclus::Context* ctx) { return new USInventory(ctx); } -} // namespace cycamore \ No newline at end of file +} // namespace einstein \ No newline at end of file diff --git a/src/us_inventory.h b/src/us_inventory.h index 7c372a5..28fef53 100644 --- a/src/us_inventory.h +++ b/src/us_inventory.h @@ -1,5 +1,5 @@ -#ifndef CYCAMORE_US_INVENTORY_H_ -#define CYCAMORE_US_INVENTORY_H_ +#ifndef EINSTEIN_US_INVENTORY_H_ +#define EINSTEIN_US_INVENTORY_H_ #include #include @@ -7,9 +7,9 @@ #include "cyclus.h" #include "cyclus_facility.h" -#include "cycamore_version.h" +#include "einstein_version.h" -namespace cycamore { +namespace einstein { class USInventory : public cyclus::Facility { public: @@ -26,7 +26,7 @@ class USInventory : public cyclus::Facility { virtual std::string str(); virtual void Tick(); virtual void Tock(); - virtual std::string version() { return CYCAMORE_VERSION; } + virtual std::string version() { return EINSTEIN_VERSION; } /// Material supplier interface virtual void GetMatlBids( @@ -120,6 +120,6 @@ class USInventory : public cyclus::Facility { #include "toolkit/position.cycpp.h" }; -} // namespace cycamore +} // namespace einstein -#endif // CYCAMORE_US_INVENTORY_H_ \ No newline at end of file +#endif // EINSTEIN_US_INVENTORY_H_ \ No newline at end of file