Skip to content

Commit

Permalink
Merge pull request cyclus#1594 from cyclus/python-api
Browse files Browse the repository at this point in the history
Add functionality to python API
  • Loading branch information
gonuke authored Feb 8, 2024
2 parents 85068a0 + 3881109 commit 59c99c7
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ jobs:
parallel: true
tag-latest-on-default: ${{ env.tag-latest-on-default }}
dockerfile: docker/Dockerfile
build-args: pkg_mgr=${{ matrix.pkg_mgr }}, ubuntu_version=${{ matrix.ubuntu_versions }}
build-args: pkg_mgr=${{ matrix.pkg_mgr }}, ubuntu_version=${{ matrix.ubuntu_versions }}
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Since last release
* Allow randomness in request frequency and size through buy policy (#1634)
* Adds support for Cython3 (#1636)
* Adds TotalInvTracker, which allows an inventory cap to be set for multiple resource buffers, and is now required for material buy policy (#1646)
* AddMutalReqs and AddReciepe functions and exclusive bids in python API of DRE (#1584)

**Changed:**

Expand Down
2 changes: 1 addition & 1 deletion INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Installation
Before going further with the installation procedure be sure you have installed
all the required dependencies listed above. We have provided detailed
instructions for `installing dependencies <DEPENDENCIES.rst>`_ for the major supported
instructions for :doc:`installing dependencies <DEPENDENCIES>`.for the major supported
systems.


Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Package Minimum Version
``boost`` 1.46.1
``libxml2`` 2
``libxml++`` 2.36
``python`` 2.7 or 3.3+
``python`` 2.7 or 3.10
``sqlite3`` 3.7.10
``HDF5`` 1.8.4
``Coin-Cbc`` 2.5
Expand Down
1 change: 0 additions & 1 deletion cyclus/agents.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,6 @@ cdef class _Facility(_Agent):
function, they must call their superclass' decommission function at the
END of their decommission() function.
"""
print('decom_fac')
(<CyclusFacilityShim*> (<_Agent> self).shim).Decommission()

@property
Expand Down
1 change: 1 addition & 0 deletions cyclus/cpp_cyclus.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ cdef extern from "context.h" namespace "cyclus":
void SchedBuild(Agent*, std_string, int)
void SchedDecom(Agent*)
void SchedDecom(Agent*, int)
void AddRecipe(std_string, shared_ptr[Composition])
Datum* NewDatum(std_string)
#void RegisterAgent(Agent*) # private
void RegisterTrader(Trader*)
Expand Down
30 changes: 19 additions & 11 deletions cyclus/gentypesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -2279,21 +2279,29 @@ class {{rclsname}}Request(_{{rclsname}}Request):
shared_ptr[cpp_cyclus.RequestPortfolio[{{cyr}}]](
new cpp_cyclus.RequestPortfolio[{{cyr}}]()
)
cdef std_vector[cpp_cyclus.RequestPortfolio[{{cyr}}].request_ptr] mreqs
cdef cpp_cyclus.Request[{{cyr}}]* single_request
cdef std_string commod
cdef _{{rclsname}} targ
cdef shared_ptr[{{cyr}}] targ_ptr
# add requests
for name, reqs in pyport['commodities'].items():
commod = str_py_to_cpp(name)
for req in reqs:
targ = <_{{rclsname}}> req['target']
targ_ptr = reinterpret_pointer_cast[{{ts.cython_type(r)}},
cpp_cyclus.Resource](targ.ptx)
if req['cost'] is not None:
raise ValueError('setting cost functions from Python is not yet '
'supported.')
port.get().AddRequest(targ_ptr, requester, commod, req['preference'],
req['exclusive'])
for commodity in pyport['commodities']:
for name, reqs in commodity.items():
commod = str_py_to_cpp(name)
for req in reqs:
targ = <_{{rclsname}}> req['target']
targ_ptr = reinterpret_pointer_cast[{{ts.cython_type(r)}},
cpp_cyclus.Resource](targ.ptx)
if req['cost'] is not None:
raise ValueError('setting cost functions from Python is not yet '
'supported.')
single_request = port.get().AddRequest(targ_ptr, requester, commod, req['preference'],
req['exclusive'])
mreqs.push_back(single_request)
port.get().AddMutualReqs(mreqs)
# add constraints
for constr in pyport['constraints']:
port.get().AddConstraint(
Expand Down
92 changes: 64 additions & 28 deletions cyclus/lib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,24 @@ cdef class _Context:
return
del self.ptx

def add_recipe(self, name, comp, basis):
"""
Adds a new recipe to a simulation
Parameters:
----------
name: str
name for recipe
comp: dict
dictionary mapping nuclides to their compostion fraction
basis: str
'atom' or 'mass' to specify the type of composition fraction
"""
cdef std_string cpp_name = str_py_to_cpp(name)
cpp_comp = ts.composition_ptr_from_py(comp, basis)
self.ptx.AddRecipe(cpp_name, cpp_comp)


def del_agent(self, agent):
"""Destructs and cleans up an agent (and it's children recursively)."""
self.ptx.DelAgent(dynamic_agent_ptr(agent))
Expand Down Expand Up @@ -1808,44 +1826,62 @@ cpdef dict normalize_request_portfolio(object inp):
if not isinstance(inp, Mapping):
inp = dict(inp)
if 'commodities' in inp:
commods = inp['commodities']
commods = []
for commodity in inp['commodities']:
for name, reqs in commodity.items():
if name == 'preference' or name == 'exclusive':
continue

commods.append({name:reqs})
constrs = inp.get('constraints', [])
else:
commods = inp
commods = []
for name, reqs in inp.items():
if name == 'preference' or name == 'exclusive':
continue
commods.append({name:reqs})
constrs = []
# canonize constraints
if not isinstance(constrs, Iterable):
constrs = [constrs]
# canonize commods
if not isinstance(commods, Mapping):
commods = dict(commods)
if not isinstance(commods, Iterable):
commods = list(commods)
cdef dict default_req = {'target': None, 'preference': 1.0,
'exclusive': False, 'cost': None}
for key, val in commods.items():
if isinstance(val, ts.Resource):
req = default_req.copy()
req['target'] = val
commods[key] = [req]
elif isinstance(val, Mapping):
req = default_req.copy()
req.update(val)
commods[key] = [req]
elif isinstance(val, Sequence):
newval = []
for x in val:
for index, commodity in enumerate(commods):
for key, val in commodity.items():
if isinstance(val, ts.Resource):
req = default_req.copy()
if isinstance(x, ts.Resource):
req['target'] = x
elif isinstance(x, Mapping):
req.update(x)
else:
raise TypeError('Did not recognize type of request while '
'converting to portfolio: ' + repr(inp))
newval.append(req)
commods[key] = newval
else:
raise TypeError('Did not recognize type of commodity while '
'converting to portfolio: ' + repr(inp))
req['target'] = val
if 'commodities' in inp:
if 'preference' in inp['commodities'][index]:
req['preference'] = inp['commodities'][index]['preference']
if 'exclusive' in inp['commodities'][index]:
req['exclusive'] = inp['commodities'][index]['exclusive']
commods[index][key] = [req]

elif isinstance(val, Mapping):
req = default_req.copy()
req.update(val)
commods[key] = [req]
elif isinstance(val, Sequence):
newval = []
for x in val:
req = default_req.copy()
if isinstance(x, ts.Resource):
req['target'] = x
elif isinstance(x, Mapping):
req.update(x)
else:
raise TypeError('Did not recognize type of request while '
'converting to portfolio: ' + repr(inp))
newval.append(req)
commods[key] = newval
else:
raise TypeError('Did not recognize type of commodity while '
'converting to portfolio: ' + repr(inp))

cdef dict rtn = {'commodities': commods, 'constraints': constrs}
return rtn

Expand Down
4 changes: 2 additions & 2 deletions cyclus/pyagents.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ def get_material_requests(self):
else:
comp = self.context.get_recipe(self.recipe)
mat = ts.Material.create_untracked(self.capacity, comp)
port = {"commodities": {c: mat for c in self.in_commods},
port = {"commodities": [{c: mat} for c in self.in_commods],
"constraints": self.capacity}
return port

def get_product_requests(self):
prod = ts.Product.create_untracked(self.capacity, "")
port = {"commodities": {c: prod for c in self.in_commods},
port = {"commodities": [{c: prod} for c in self.in_commods],
"constraints": self.capacity}
return port

Expand Down
7 changes: 4 additions & 3 deletions src/request_portfolio.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ template <class T> struct QtyCoeffConverter : public Converter<T> {

/// @class RequestPortfolio
///
/// @brief A RequestPortfolio is a group of (possibly constrainted) requests for
/// @brief A RequestPortfolio is a group of (possibly constrained) requests for
/// resources
///
/// The portfolio contains a grouping of resource requests that may be mutually
Expand All @@ -69,7 +69,7 @@ template <class T> struct QtyCoeffConverter : public Converter<T> {
/// RequestPortfolio<SomeResource>());
/// // add some requests
/// rp->AddRequest(/* args */);
/// // declare some of them as multicommodity requsts (i.e., any one will
/// // declare some of them as multi-commodity requests (i.e., any one will
/// // satisfy this demand).
/// rp->AddMutualReqs(/* args */);
///
Expand All @@ -88,6 +88,7 @@ class RequestPortfolio
public:
typedef boost::shared_ptr<RequestPortfolio<T>> Ptr;
typedef std::function<double(boost::shared_ptr<T>)> cost_function_t;
typedef Request<T>* request_ptr;

RequestPortfolio() : requester_(NULL), qty_(0) {}

Expand Down Expand Up @@ -229,7 +230,7 @@ class RequestPortfolio
/// constraints_ is a set because constraints are assumed to be unique
std::set<CapacityConstraint<T>> constraints_;

/// the total quantity of resources assocaited with the portfolio
/// the total quantity of resources associated with the portfolio
double qty_;
Trader* requester_;
};
Expand Down
2 changes: 1 addition & 1 deletion src/xml_file_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ void XMLFileLoader::LoadSolver() {
if (!exclusive) {
std::stringstream ss;
ss << "You have set allow_exclusive_orders to False."
<< " Many archetypes (e.g., :cycamore:Reactor will not work"
<< " Many archetypes (e.g., :cycamore:Reactor) will not work"
<< " as intended with this feature turned off.";
Warn<VALUE_WARNING>(ss.str());
}
Expand Down

0 comments on commit 59c99c7

Please sign in to comment.