Source code for cyclopts.exchange_family

"""This module defines a ProblemFamily subclass for Cyclus Resource Exchanges.

:author: Matthew Gidden <matthew.gidden _at_ gmail.com>
"""
import numpy as np
from collections import Iterable

from cyclopts.problems import ProblemFamily
import cyclopts.cyclopts_io as cycio
import cyclopts.tools as tools
import cyclopts.exchange_instance as exinst

_N_CAPS_MAX = 4

# add to this if more objects need to be persistable
_tbl_names = {
    "ExGroup": "ExchangeGroups",
    "ExNode": "ExchangeNodes",
    "ExArc": "ExchangeArcs",
    "properties": "ExchangeInstProperties",
    "solutions": "ExchangeInstSolutions",    
    "solution_properties": "ExchangeInstSolutionProperties",    
}

# this must be kept up to date with the cyclopts.instance classes
_dtypes = {
    "ExGroup": np.dtype([
        ("instid", ('str', 16)), # 16 bytes for uuid
        ("id", np.int64),
        ("kind", np.bool_),
        ("caps", (np.float64, _N_CAPS_MAX),), # array of size N_CAPS_MAX
        ("cap_dirs", (np.bool_, _N_CAPS_MAX),), # array of size N_CAPS_MAX
        ("qty", np.float64),
        ]),
    "ExNode": np.dtype([
        ("instid", ('str', 16)), # 16 bytes for uuid
        ("id", np.int64),
        ("gid", np.int64),
        ("kind", np.bool_),
        ("qty", np.float64),
        ("excl", np.bool_),
        ("excl_id", np.int64),
        ]),
    "ExArc": np.dtype([
        ("instid", ('str', 16)), # 16 bytes for uuid
        ("id", np.int64),
        ("uid", np.int64),
        ("ucaps", (np.float64, _N_CAPS_MAX),), # array of size N_CAPS_MAX
        ("vid", np.int64),
        ("vcaps", (np.float64, _N_CAPS_MAX),), # array of size N_CAPS_MAX
        ("pref", np.float64),
        ]),
    "properties": np.dtype([
        ("paramid", ('str', 16)), # 16 bytes for uuid
        ("instid", ('str', 16)), # 16 bytes for uuid
        ("species", ('str', 30)), # 30 is long enough..
        ("n_arcs", np.int64),
        ("n_u_grps", np.int64),
        ("n_v_grps", np.int64),
        ("n_u_nodes", np.int64),
        ("n_v_nodes", np.int64),
        ("n_constrs", np.int64),
        ("excl_frac", np.float64),
        ]),
    "solutions": np.dtype([
        ("solnid", ('str', 16)), # 16 bytes for uuid
        ("arc_id", np.int64),
        ("flow", np.float64),
        ]),
    "solution_properties": np.dtype([
        ("solnid", ('str', 16)), # 16 bytes for uuid
        ("instid", ('str', 16)), # 16 bytes for uuid
        ("pref_flow", np.float64),
        ("cyclus_version", ('str', 12)),
        ]),
    }

# these functions must be kept up to date with cyclopts.instance
def grp_tpl(instid, obj):    
    return(instid.bytes, 
           obj.id, 
           obj.kind, 
           np.append(obj.caps, [0] * (_N_CAPS_MAX - len(obj.caps))),
           np.append(obj.cap_dirs, [0] * (_N_CAPS_MAX - len(obj.cap_dirs))), 
           obj.qty,)

def node_tpl(instid, obj):    
    return(instid.bytes, obj.id, obj.gid, obj.kind, obj.qty, obj.excl, obj.excl_id)

def arc_tpl(instid, obj):
    return(instid.bytes, obj.id, 
           obj.uid, np.append(obj.ucaps, [0] * (_N_CAPS_MAX - len(obj.ucaps))), 
           obj.vid, np.append(obj.vcaps, [0] * (_N_CAPS_MAX - len(obj.vcaps))), 
           obj.pref)

def prop_tpl(instid, paramid, species, groups, nodes, arcs):
    nu_grps = sum(1 for g in groups if int(g.kind))
    nv_grps = len(groups) - nu_grps
    nu_nodes = sum(1 for n in nodes if n.kind)
    nv_nodes = len(nodes) - nu_nodes
    excl = {n.id: n.excl for n in nodes}
    excl_frac = sum(1.0 for a in arcs if excl[a.uid] or excl[a.vid]) / len(arcs)
    nconstr = sum(len(g.caps) for g in groups)
    return (paramid.bytes, instid.bytes, species, len(arcs), nu_grps, nv_grps, 
            nu_nodes, nv_nodes, nconstr, excl_frac)

[docs]class ResourceExchange(ProblemFamily): """A class representing families of resource exchange problems.""" def __init__(self): super(ResourceExchange, self).__init__() @property
[docs] def name(self): """ Returns ------- name : string The name of this species """ return 'ResourceExchange'
@property
[docs] def property_table_name(self): """ Returns ------- name : string The name of this family's instance property table """ return _tbl_names['properties']
[docs] def register_tables(self, h5file, prefix): """Parameters ---------- h5file : PyTables File the hdf5 file prefix : string the absolute path to the group for tables of this family Returns ------- tables : list of cyclopts_io.Tables All tables that could be written to by this species. """ return [cycio.Table(h5file, '/'.join([prefix, _tbl_names[x]]), _dtypes[x]) for x in _tbl_names.keys()]
[docs] def record_inst(self, inst, inst_uuid, param_uuid, species, tables): """Parameters ---------- inst : tuple of lists of ExGroups, ExNodes, and ExArgs A representation of a problem instance inst_uuid : uuid The uuid of the instance param_uuid : uuid The uuid of the point in parameter space species : str The name of the species that generated this instance tables : list of cyclopts_io.Table The tables that can be written to """ groups, nodes, arcs = inst data = [grp_tpl(inst_uuid, x) for x in groups] tables[_tbl_names['ExGroup']].append_data(data) data = [node_tpl(inst_uuid, x) for x in nodes] tables[_tbl_names['ExNode']].append_data(data) data = [arc_tpl(inst_uuid, x) for x in arcs] tables[_tbl_names['ExArc']].append_data(data) data = [prop_tpl(inst_uuid, param_uuid, species, groups, nodes, arcs)] tables[_tbl_names['properties']].append_data(data)
[docs] def record_soln(self, soln, soln_uuid, inst, inst_uuid, tables): """Parameters ---------- soln : ExSolution A representation of a problem solution soln_uuid : uuid The uuid of the solution inst : tuple of lists of ExGroups, ExNodes, and ExArgs A representation of a problem instance inst_uuid : uuid The uuid of the instance tables : list of cyclopts_io.Table The tables that can be written to """ groups, nodes, arcs = inst tbl = tables[_tbl_names['solutions']] for arcid, flow in soln.flows.iteritems(): if flow > 0: tbl.append_data([(soln_uuid.bytes, arcid, flow)]) tbl = tables[_tbl_names['solution_properties']] tbl.append_data([(soln_uuid.bytes, inst_uuid.bytes, soln.pref_flow, soln.cyclus_version)])
[docs] def read_inst(self, uuid, tables): """Parameters ---------- uuid : uuid The uuid of the instance to read tables : list of cyclopts_io.Table The tables that can be written to Returns ------- inst : tuple of lists of ExGroups, ExNodes, and ExArgs A representation of a problem instance """ ctors = {'ExGroup': exinst.ExGroup, 'ExNode': exinst.ExNode, 'ExArc': exinst.ExArc} objs = {'ExGroup': [], 'ExNode': [], 'ExArc': []} for name in ctors.keys(): tbl = tables[_tbl_names[name]] rows = tbl.instid_rows(uuid.bytes) setattrs = tools.cyc_members(ctors[name]()) for row in rows: obj = ctors[name]() if name == 'ExGroup': ncaps = len([x for x in row['caps'] if x > 0]) for var in setattrs: attr = getattr(obj, var) if isinstance(attr, Iterable): ary = row[var] if name == 'ExGroup': attr = [ary[i] for i in range(ncaps)] else: attr = ary[ary > 0] else: attr = row[var] #print('setting {0} to {1}'.format(var, attr)) setattr(obj, var, attr) objs[name].append(obj) return objs['ExGroup'], objs['ExNode'], objs['ExArc']
[docs] def run_inst(self, inst, solver, verbose=False): """Parameters ---------- inst : tuple of lists of ExGroups, ExNodes, and ExArgs A representation of a problem instance solver : ProbSolver or similar A representation of a problem solver verbose : bool A verbosity flag Returns ------- soln : ExSolution A representation of a problem solution """ groups, nodes, arcs = inst soln = exinst.Run(groups, nodes, arcs, solver, verbose) return soln