Ejemplo n.º 1
0
class Source(Facility):
    """A minimum implementation source facility that provides a commodity with
    a given capacity.
    """
    commod = ts.String(
        doc="commodity that the source facility supplies",
        tooltip="source commodity",
        schematype="token",
        uilabel="Commodity",
        uitype="outcommodity",
    )
    recipe_name = ts.String(
        doc="Recipe name for source facility's commodity. "
        "If empty, source supplies material with requested compositions.",
        tooltip="commodity recipe name",
        schematype="token",
        default="",
        uilabel="Recipe",
        uitype="recipe",
    )
    capacity = ts.Double(
        doc="amount of commodity that can be supplied at each time step",
        uilabel="Maximum Throughput",
        tooltip="source capacity",
    )

    def build(self, parent):
        super(Source, self).build(parent)
        if self.lifetime >= 0:
            self.context.schedule_decom(self, self.exit_time)

    def get_material_bids(self, requests):
        reqs = requests.get(self.commod, None)
        if not reqs:
            return
        if len(self.recipe_name) == 0:
            bids = [req for req in reqs]
        else:
            recipe_comp = self.context.get_recipe(self.recipe_name)
            bids = []
            for req in reqs:
                qty = min(req.target.quantity, self.capacity)
                mat = ts.Material.create_untracked(qty, recipe_comp)
                bids.append({'request': req, 'offer': mat})
        return {'bids': bids, 'constraints': self.capacity}

    def get_material_trades(self, trades):
        responses = {}
        if len(self.recipe_name) == 0:
            for trade in trades:
                mat = ts.Material.create(self, trade.amt,
                                         trade.request.target.comp())
                responses[trade] = mat
        else:
            recipe_comp = self.context.get_recipe(self.recipe_name)
            for trade in trades:
                mat = ts.Material.create(self, trade.amt, recipe_comp)
                responses[trade] = mat
        return responses
Ejemplo n.º 2
0
class Storage(Facility):
    """My storage facility."""

    storage_time = ts.Int(
        doc="Minimum amount of time material must be stored",
        tooltip="Minimum amount of time material must be stored",
        units="months",
        uilabel="Storage Time",
    )
    incommod = ts.String(
        tooltip="Storage input commodity",
        doc="Input commodity on which Storage requests material.",
        uilabel="Input Commodity",
        uitype="incommodity",
    )
    outcommod = ts.Int(
        tooltip="Storage output commodity",
        doc="Output commodity on which Storage offers material.",
        uilabel="Output Commodity",
        uitype="outcommodity",
    )

    def tick(self):
        print("Hello,")
        print("World!")
Ejemplo n.º 3
0
class Sink(Facility):
    """This sink facility accepts specified amount of commodity."""
    in_commods = ts.VectorString(
        doc="commodities that the sink facility accepts.",
        tooltip="input commodities for the sink",
        uilabel="List of Input Commodities",
        uitype=["oneormore", "incommodity"],
    )
    recipe = ts.String(
        tooltip="input/request recipe name",
        doc="Name of recipe to request. If empty, sink requests material no "
        "particular composition.",
        default="",
        uilabel="Input Recipe",
        uitype="recipe",
    )
    max_inv_size = ts.Double(
        default=1e299,
        doc="total maximum inventory size of sink facility",
        uilabel="Maximum Inventory",
        tooltip="sink maximum inventory size",
    )
    capacity = ts.Double(
        doc="capacity the sink facility can accept at each time step",
        uilabel="Maximum Throughput",
        tooltip="sink capacity",
        default=100.0,
    )
    inventory = ts.ResourceBuffInv(capacity='max_inv_size')

    def get_material_requests(self):
        if len(self.recipe) == 0:
            comp = {}
        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},
            "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},
            "constraints": self.capacity
        }
        return port

    def accept_material_trades(self, responses):
        for mat in responses.values():
            self.inventory.push(mat)

    def accept_product_trades(self, responses):
        for prod in responses.values():
            self.inventory.push(prod)
Ejemplo n.º 4
0
class udb_reactor(Facility):

    reactor_id = ts.Int(
        doc=
        "This variable lists the reactor id of the reactors in the database ",
        tooltip="Reactor Id in database",
        uilabel="Reactor ID")

    outcommod = ts.String(doc="The commodity this institution will output",
                          tooltip="Output commodity",
                          uilabel="Output Commodity")

    inventory = ts.ResBufMaterialInv()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def write(self, string):
        with open('log.txt', 'a') as f:
            f.write(string + '\n')

    def tock(self):
        self.write('what')

        # Example dummy code
        composition = {922350000: 5, 922380000: 95}
        material = ts.Material.create(self, 100, composition)

        self.inventory.push(material)
        self.write(str(self.inventory.quantity))

    #     time = self.context.time
    #     get rows that match with current time

    #     for information in rows:
    #         Create material given by recipe and quantity
    #         composition = {ZZAAA0000: massfrac,
    #                        ZZAAA0000: massfrac}
    #         recipe = self.context.get_recipe()
    #         material = ts.Material.create(self, quantity, recipe)

    #         Push material to out buffer
    #         self.out.push(material)

    def get_material_bids(self, requests):
        if self.outcommod not in requests:
            return
        reqs = requests[self.outcommod]
        bids = [reqs]
        ports = [{"bids": bids, "constraints": self.inventory.quantity}]
        return ports

    def get_material_trades(self, trades):
        responses = {}
        for trade in trades:
            print(trade)
            mat = self.inventory.pop()
            responses[trade] = mat
        return responses
Ejemplo n.º 5
0
class DefaultToaster(Facility):
    """Meant for testing default values"""

    bread = ts.String(default='rye')
    level = ts.Double(default=4.2)

    def tick(self):
        print('Bread is ' + self.bread)
        print('Toast level is {0}'.format(self.level))
Ejemplo n.º 6
0
class TruckCompany(Institution):
    """
    An institution used to manage a fleet of transport trucks used to
    carry a specific commodity.
    """

    commodity = ts.String(
        doc="This is the commodity carried by the trucks in the company",
        tooltip="Managed Commodity",
        uilabel="Commodity")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def tick(self):
        pass

    def tock(self):
        pass
Ejemplo n.º 7
0
class DemandFac(Facility):
    """
    This institution deploys facilities based on demand curves using
    Non Optimizing (NO) methods.
    """

    production_rate_min = ts.Double(
        doc="The minimum rate at which this facility produces it's commodity. ",
        tooltip="The minimum rate at which this facility produces its product.",
        uilabel="Min Production")

    production_rate_max = ts.Double(
        doc="The maximum rate at which this facility produces it's commodity.",
        tooltip="The maximum rate at which this facility produces its product.",
        uilabel="Max Production")

    commodity = ts.String(doc="", tooltip="", uilabel="")

    def tick(self):
        rate = random.uniform(self.production_rate_min,
                              self.production_rate_max)
        print("Agent {0} {1} {2}".format(self.id, self.production_rate_min,
                                         rate))
        lib.record_time_series(self.commodity, self, rate)
Ejemplo n.º 8
0
class DemandFac(Facility):
    """
    This institution deploys facilities based on demand curves using 
    Non Optimizing (NO) methods. 
    """

    demand_rate_min = ts.Double(
        doc="The minimum rate at which this facility produces it's commodity. ",
        tooltip="The minimum rate at which this facility produces its product.",
        uilabel="Min Production")

    demand_rate_max = ts.Double(
        doc="The maximum rate at which this facility produces it's commodity.",
        tooltip="The maximum rate at which this facility produces its product.",
        uilabel="Max Production")

    demand_ts = ts.Int(
        doc="The number of timesteps between demand calls by the agent",
        tooltip="The number of timesteps between demand calls by the agent",
        uilabel="Demand Timestep",
        default=1)

    supply_rate_max = ts.Double(
        doc="The maximum rate at which this facility produces it's commodity.",
        tooltip="The maximum rate at which this facility produces its product.",
        uilabel="Max Production")

    supply_rate_min = ts.Double(
        doc="The maximum rate at which this facility produces it's commodity.",
        tooltip="The maximum rate at which this facility produces its product.",
        uilabel="Max Production")

    supply_ts = ts.Int(
        doc="The number of timesteps between supply calls by the agent",
        tooltip="The number of timesteps between supply calls by the agent",
        uilabel="Supply Timestep",
        default=1)

    supply_commod = ts.String(doc="The commodity supplied by this facility.",
                              tooltip="Supplied Commodity",
                              uilabel="Supplied Commodity")

    demand_commod = ts.String(doc="The commodity demanded by this facility.",
                              tooltip="Commodity demanded",
                              uilabel="Commodity Demanded")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.demand_t = -2
        self.supply_t = -2

    def tick(self):
        """
        This method defines the tick behavior for this archetype. The demand and supply
        rates are calculated, and those are recorded in time series. 
        """
        self.demand_t += 1
        self.supply_t += 1
        supply_rate = random.uniform(self.supply_rate_min,
                                     self.supply_rate_max)
        demand_rate = random.uniform(self.demand_rate_min,
                                     self.demand_rate_max)
        if self.supply_t == -1 or self.supply_t is self.supply_ts:
            lib.record_time_series(self.supply_commod, self, supply_rate)
            self.supply_t = 0
        else:
            lib.record_time_series(self.supply_commod, self, 0.)
        if self.demand_t == -1 or self.demand_t is self.demand_ts:
            lib.record_time_series(self.demand_commod, self, demand_rate)
            self.demand_t = 0
        else:
            lib.record_time_series(self.demand_commod, self, 0.)
Ejemplo n.º 9
0
class ann_lwr(Facility):
    fuel_incommod = ts.String(
        doc="The commodity name for incoming fuel",
        tooltip="Incoming fuel",
        uilabel="Incoming fuel"
    )

    fuel_outcommod = ts.String(
        doc="The commodity name for discharge fuel",
        tooltip="Discharge Fuel",
        uilabel="Discharge Fuel"
    )

    pickle_path = ts.String(
        doc="Path to the pickle file",
        tooltip="Absolute path to the pickle file"
    )

    # one row would be 2.1_30000 3.1_40000 4.1_50000 etc
    enr_bu_matrix = ts.VectorString(
        doc="enrichment and burnup matrix",
        tooltip="enrichment_burnup column separated by space"
    )

    n_assem_core = ts.Int(
        doc="Number of assemblies",
        tooltip="Number of assemblies in core"
    )

    n_assem_batch = ts.Int(
        doc="Number of assemblies per batch",
        tooltip="Number of assemblies per batch"
    )

    assem_size = ts.Double(
        doc="Assembly mass",
        tooltip="Assembly mass"
    )

    power_cap = ts.Double(
        doc="Power capacity of reactor",
        tooltip="Power capacity of reactor",
    )

    cycle_time_eq = ts.String(
        doc="cycle time of reactor equation",
        tooltip="Cycle time of reactor equation"
    )

    refuel_time_eq = ts.String(
        doc="Refuel time of reactor equation",
        tooltip="Refuel time of reactor equation"
    )

    core = ts.ResBufMaterialInv()
    waste = ts.ResBufMaterialInv()


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def enter_notify(self):
        super().enter_notify()
        self.model_dict = pickle.load(open(self.pickle_path, 'rb'))
        # change other to h-1
        other_index = self.model_dict['iso_list'].index('other')
        self.model_dict['iso_list'][other_index] = 'h-1'
        self.iso_list = self.model_dict['iso_list']

        # check if it's integer batches
        if (self.n_assem_core / self.n_assem_batch)%1 != 0:
            raise ValueError('Sorry can only do integer batches')

        # input consistency checking
        self.enr_matrix, self.bu_matrix = self.check_enr_bu_matrix()

        # !!
        self.f = open('f.txt', 'w')
        # set initial cycle and refuel time
        t = self.context.time
        self.cycle_time = max(0, int(eval(self.cycle_time_eq)))
        self.refuel_time = max(0, int(eval(self.refuel_time_eq)))

        # set core capacity
        self.core.capacity = self.n_assem_core * self.assem_size

        self.cycle_step = 0
        self.batch_gen = 0
        self.n_batch = int(self.n_assem_core / self.n_assem_batch)
        # if no exit time, exit time is 1e5
        if self.exit_time == -1:
            self.decom_time = 1e5
        else:
            self.decom_time = self.exit_time

    def tick(self):
        # If time to decommission, where if decommissioning
        # mid cycle, deplete using weighted average
        # and discharge
        if self.context.time == self.decom_time:
            # burnup is prorated by the ratio
            cycle_step_ratio = self.cycle_step / self.cycle_time
            for index, bu_list in enumerate(self.bu_matrix):
                prorated_bu_list = bu_list * cycle_step_ratio
                self.transmute_and_discharge(prorated_bu_list,
                                             self.enr_matrix[index])
            return

        if self.cycle_step == self.cycle_time:
            if self.batch_gen < self.n_batch:
                i = self.batch_gen
            else:
                i = -1
            bu_list = self.bu_matrix[i]
            self.transmute_and_discharge(bu_list,
                                         self.enr_matrix[i])
            self.batch_gen += 1


    def tock(self):
        if (self.cycle_step >= self.cycle_time + self.refuel_time) and (self.is_core_full()):
            t = self.context.time
            self.cycle_time = max(0, int(eval(self.cycle_time_eq)))
            self.refuel_time = max(0, int(eval(self.refuel_time_eq)))
            self.cycle_step = 1

        # produce power if core is full
        if (self.cycle_step >= 0) and (self.cycle_step < self.cycle_time) and (self.is_core_full()):
            self.produce_power(True)
        else:
            self.produce_power(False)

        if self.cycle_step > 0 or self.is_core_full():
            self.cycle_step += 1


    def get_material_bids(self, requests):
        """ Gets material bids that want its 'outcommod' and
            returns bid portfolio
        """
        bids = []
        if self.fuel_outcommod in requests.keys():
            reqs = requests[self.fuel_outcommod]
            for req in reqs:
                if self.waste.empty():
                    break
                qty = min(req.target.quantity, self.waste.quantity
                        )
                next_in_line = self.waste.peek()
                mat = ts.Material.create_untracked(qty, next_in_line.comp())
                bids.append({'request': req, 'offer': mat})
        if len(bids) == 0:
            return
        port = {'bids': bids}
        return port

    def get_material_trades(self, trades):
        """ Give out fuel_outcommod from waste buffer"""
        responses = {}
        for trade in trades:
            commodity = trade.request.commodity
            if commodity == self.fuel_outcommod:
                mat_list = self.waste.pop_n(self.waste.count)
            if len(mat_list) > 1:
                for mat in mat_list[1:]:
                    mat_list[0].absorb(mat)
            responses[trade] = mat_list[0]
        return responses

    def get_material_requests(self):
        """ Ask for fuel_incommod"""
        ports = []
        if self.context.time == self.decom_time:
            return []
        if self.is_core_full():
            return []

        recipes = {}
        qty = {}
        mat = {}
        t = self.context.time
        # initial core loading
        if self.batch_gen == 0:
            enr_to_request = self.enr_matrix
            for i in range(np.shape(enr_to_request)[0]):
                for j in range(np.shape(enr_to_request)[1]):
                    enr = eval(enr_to_request[i,j])
                    comp = {'u-238': 100-enr,
                            'u-235': enr}
                    qty = self.assem_size
                    mat = ts.Material.create_untracked(qty, comp)

                    ports.append({'commodities': {self.fuel_incommod: mat},
                                  'constraints': qty})
        # subsequent equilibrium batch loading
        else:
            enr_to_request = self.enr_matrix[-1]
            for enrichment in enr_to_request:
                enr = eval(enrichment)
                comp = {'u-238': 100-enr,
                        'u-235': enr}
                qty = self.assem_size
                mat = ts.Material.create_untracked(qty, comp)
                ports.append({'commodities' : {self.fuel_incommod: mat},
                              'constraints': qty})

        return ports


    def accept_material_trades(self, responses):
        """ Get fuel_incommod and store it into core"""
        for key, mat in responses.items():
            if key.request.commodity == self.fuel_incommod:
                self.core.push(mat)


    def is_core_full(self):
        if self.core.count == self.n_assem_core:
            return True
        else:
            return False


    def predict(self, enr_bu):
        model = self.model_dict['model']
        x = self.model_dict['xscaler'].transform(enr_bu)
        y = self.model_dict['yscaler'].inverse_transform(
                model.predict(x))[0]
        comp_dict = {}
        for indx, iso in enumerate(self.iso_list):
            # zero if model predicts negative
            if y[indx] < 0:
                y[indx] = 0
            comp_dict[iso] = y[indx]
        return comp_dict


    def transmute_and_discharge(self, bu_list, enr_list):
        # this should ideally be one batch,
        t = self.context.time
        if self.batch_gen < self.n_batch:
           enr = enr_list[self.batch_gen]
        else:
            enr = enr_list[-1]
        for indx, bu in enumerate(bu_list):
            enr_bu = [[eval(enr_list[indx]),eval(bu)]]
            print('Transmuting fuel with enrichment, burnup:')
            print(enr_bu)
            discharge_fuel = self.core.pop()
            comp = self.predict(enr_bu)
            discharge_fuel.transmute(comp)
            self.waste.push(discharge_fuel)


    def produce_power(self, produce=True):
        if produce:
            lib.record_time_series(lib.POWER, self, float(self.power_cap))
        else:
            lib.record_time_series(lib.POWER, self, 0)


    def check_enr_bu_matrix(self):
        # parse bu enr matrix
        empty = np.zeros(len(self.enr_bu_matrix[0].split(' ')))

        for i in self.enr_bu_matrix:
            entry = np.array(i.split(' '))
            if len(entry) != self.n_assem_batch:
                raise ValueError('The length of entry has to match n_assem_batch')
            try:
                empty = np.vstack((empty, entry))
            except ValueError:
                print('Your length of entries per batch are inconsistent!')
        matrix = empty[1:]

        # separate bu and enrichment
        sep = np.char.split(matrix, '_')
        bu_matrix = np.empty(np.shape(matrix), dtype=object)
        enr_matrix = np.empty(np.shape(matrix), dtype=object)
        for i in range(np.shape(sep)[0]):
            for j in range(np.shape(sep)[1]):
                enr_matrix[i,j] = sep[i,j][0]
                bu_matrix[i,j] = sep[i,j][1]

        return enr_matrix, bu_matrix
Ejemplo n.º 10
0
class saltproc_reactor(Facility):
    """
    This reactor imports an HDF5 file from a saltproc run (or a converted SCALE output).
    It imports the following data:
        surplus fissile output composition and isotopics in time
        waste output isotopics in time
        fertile input isotopics in time
        core isotopics in time
        blanket isotopics(if applicable)
    """
    init_fuel_commod = ts.String(
        doc="The commodity name for initial loading fuel",
        tooltip="Init Fuel",
        uilabel="Init Fuel")

    final_fuel_commod = ts.String(
        doc="The commodity name for final discharge fuel",
        tooltip="Final Fuel",
        uilabel="Final Fuel")

    fill_commod = ts.String(
        doc="The commodity this facility will take in for fertile materials ",
        tooltip="Fill Commodity",
        uilabel="Fill Commodity")

    fissile_out_commod = ts.String(
        doc="The fissile commodity this facility will output",
        tooltip="Fissile commodity",
        uilabel="Fissile Commodity")

    waste_commod = ts.String(
        doc="The waste commodity this facility will output",
        tooltip="Waste commodity",
        uilabel="Waste Commodity")

    db_path = ts.String(doc="Path to the hdf5 file",
                        tooltip="Absolute path to the hdf5 file")

    power_cap = ts.Float(doc="Power capacity of reactor",
                         tooltip="Power Capacity")

    waste_tank = ts.ResBufMaterialInv()
    fissile_tank = ts.ResBufMaterialInv()

    driver_buf = ts.ResBufMaterialInv()
    blanket_buf = ts.ResBufMaterialInv()

    fill_tank = ts.ResBufMaterialInv()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def enter_notify(self):
        super().enter_notify()
        self.f = h5py.File(self.db_path, 'r')
        self.max_nonzero_indx = self.get_max_nonzero_indx()
        # subject to change
        self.isos = self.f['iso names']
        self.num_isotopes = len(self.isos)
        self.waste_db = self.cum_to_nocum(self.f['waste tank composition'])
        self.fissile_db = self.cum_to_nocum(self.f['fissile tank composition'])
        self.driver_refill = self.cum_to_nocum(
            self.f['driver refill tank composition'])
        self.blanket_refill = self.cum_to_nocum(
            self.f['blanket refill tank composition'])
        self.driver_db = self.cutoff_nonzero(
            self.f['driver composition after reproc'])
        self.blanket_db = self.cutoff_nonzero(
            self.f['blanket composition after reproc'])

        self.siminfo_timestep = int(
            self.f['siminfo_timestep'][()].decode('utf-8'))
        self.saltproc_timestep = self.siminfo_timestep * 24 * 3600
        self.buf_dict = {
            'driver': self.driver_buf,
            'blanket': self.blanket_buf
        }
        self.prev_indx = 0
        self.driver_mass = sum(self.driver_db[0])
        self.blanket_mass = sum(self.blanket_db[0])
        self.driver_buf.capacity = self.driver_mass
        if self.blanket_mass == 0:
            self.blanket_buf.capacity = 0
            del self.buf_dict['blanket']
        else:
            self.blanket_buf.capacity = self.blanket_mass
        self.fresh = True
        self.loaded = False
        self.shutdown = False

    def cum_to_nocum(self, dataset):
        """ Convert cumulative array to non-cumulative array
        Parameters:
        -----------
        dataset: hdf5 dataset
        """
        new_array = np.zeros((self.max_nonzero_indx, self.num_isotopes))
        new_array[0] = dataset[0]
        for i in range(1, self.max_nonzero_indx):
            new_array[i] = dataset[i] - dataset[i - 1]
        return new_array

    def cutoff_nonzero(self, dataset):
        return dataset[:self.max_nonzero_indx]

    def get_max_nonzero_indx(self):
        self.tot_timesteps = len(self.f['driver composition after reproc'])
        for i in range(self.tot_timesteps):
            if sum(self.f['driver composition after reproc'][i]) == 0:
                return i - 1
        return self.tot_timesteps

    def tick(self):
        if not self.fresh:
            reactor_age_sec = self.context.dt * \
                (self.context.time - self.start_time)
            timestep_at_hdf5 = int(reactor_age_sec / self.saltproc_timestep)
            if timestep_at_hdf5 < len(self.waste_db):
                self.indx = timestep_at_hdf5
            else:
                self.indx = self.indx_tuple[1]
                self.prev_indx = self.indx_tuple[0]
        else:
            self.indx = -1
        # if reactor is `on'
        if self.indx > 0:
            # push waste from db to waste_tank
            self.get_waste()
            # push fissile from db to fissile_tank
            self.get_fissile()
            self.get_fill_demand()
            self.indx_tuple = (self.prev_indx, self.indx)
            self.prev_indx = self.indx + 1

    def check_core_full(self):
        for key, val in self.buf_dict.items():
            if (val.capacity - val.quantity) > 1:
                return False
        return True

    def tock(self):
        # check if core is full;
        if self.check_core_full():
            self.loaded = True
            self.produce_power()
            if self.fresh:
                self.start_time = self.context.time
                self.fresh = False
        elif self.context.time != self.exit_time:
            self.loaded = False
            self.produce_power(False)

    def get_waste(self):
        waste_dump = np.zeros(self.num_isotopes)
        waste_comp = {}
        # lump all the waste generated in this timestep
        # into one waste dump
        for t in np.arange(self.prev_indx, self.indx + 1):
            waste_dump += self.waste_db[t, :]
        # convert this into a dictionary

        waste_mass = sum(waste_dump)
        waste_comp = self.array_to_comp_dict(waste_dump)
        if waste_mass != 0:
            material = ts.Material.create(self, waste_mass, waste_comp)
            self.waste_tank.push(material)

    def get_fissile(self):
        fissile_dump = np.zeros(self.num_isotopes)
        fissile_comp = {}

        for t in np.arange(self.prev_indx, self.indx + 1):
            fissile_dump += self.fissile_db[t, :]

        fissile_mass = sum(fissile_dump)
        fissile_comp = self.array_to_comp_dict(fissile_dump)

        if fissile_mass != 0:
            material = ts.Material.create(self, fissile_mass, fissile_comp)
            self.fissile_tank.push(material)

    def get_fill_demand(self):
        self.get_fill = False

        demands = {}
        masses = {}
        for bufs in self.buf_dict.keys():
            demands[bufs] = np.zeros(self.num_isotopes)
        fill_comp_dict = {}
        # since the data is in negative:
        for t in np.arange(self.prev_indx, self.indx + 1):
            for key, val in demands.items():
                if 'driver' in key:
                    demands[key] += -1.0 * self.driver_refill[t, :]
                if 'blanket' in key:
                    demands[key] += -1.0 * self.blanket_refill[t, :]

        for key, val in demands.items():
            masses[key] = sum(val)

        self.qty = sum(masses.values())
        if (self.qty) == 0:
            return 0

        for key, val in self.buf_dict.items():
            val.pop(masses[key])
        self.fill_comp = sum(demands.values())

        fill_comp_dict = self.array_to_comp_dict(self.fill_comp)
        if bool(fill_comp_dict):
            self.demand_mat = ts.Material.create_untracked(
                self.qty, fill_comp_dict)
        if self.qty != 0.0:
            self.get_fill = True

    def get_material_bids(self, requests):
        """ Gets material bids that want its `outcommod' and
            returns bid portfolio
        """
        bids = []
        # waste commods
        try:
            reqs = requests[self.waste_commod]
            for req in reqs:
                qty = min(req.target.quantity, self.waste_tank.quantity)
                # returns if the inventory is empty
                if self.waste_tank.empty():
                    break
                # get the composition of the material next in line
                next_in_line = self.waste_tank.peek()
                mat = ts.Material.create_untracked(qty, next_in_line.comp())
                bids.append({'request': req, 'offer': mat})
        except KeyError:
            print('No one is requesting ', self.waste_commod)

        try:
            reqs = requests[self.fissile_out_commod]
            for req in reqs:
                qty = min(req.target.quantity, self.fissile_tank.quantity)
                if self.fissile_tank.empty():
                    break
                next_in_line = self.fissile_tank.peek()
                mat = ts.Material.create_untracked(qty, next_in_line.comp())
                bids.append({'request': req, 'offer': mat})
        except KeyError:
            print('No one is requesting ', self.fissile_out_commod)

        if self.context.time == self.exit_time:
            self.shutdown = True
            try:
                reqs = requests[self.final_fuel_commod]
                for req in reqs:
                    total_qty = self.driver_buf.quantity + self.blanket_buf.quantity
                    qty = min(req.target.quantity, total_qty)
                    if self.driver_buf.empty():
                        break
                    # driver material
                    driver_comp = self.array_to_comp_dict(
                        self.driver_db[self.indx])

                    driver_mat = ts.Material.create(self,
                                                    self.driver_buf.quantity,
                                                    driver_comp)
                    blanket_comp = self.array_to_comp_dict(
                        self.blanket_db[self.indx])
                    blanket_mat = ts.Material.create(self,
                                                     self.blanket_buf.quantity,
                                                     blanket_comp)
                    driver_mat.absorb(blanket_mat)
                    bids.append({'request': req, 'offer': driver_mat})
            except KeyError:
                print('No one is requesting ', self.final_fuel_commod)
                # postpone shutdown..?
        if len(bids) == 0:
            return
        port = {"bids": bids}
        return port

    def get_material_trades(self, trades):
        """ Give out waste_commod and fissile_out_commod from
            waste_tank and fissile_tank, respectively.
        """
        responses = {}
        for trade in trades:
            commodity = trade.request.commodity

            if commodity == self.waste_commod:
                mat_list = self.waste_tank.pop_n(self.waste_tank.count)
            if commodity == self.fissile_out_commod:
                mat_list = self.fissile_tank.pop_n(self.fissile_tank.count)
            if commodity == self.final_fuel_commod:
                blank_comp = self.array_to_comp_dict(
                    self.blanket_db[self.prev_indx, :])
                driver_comp = self.array_to_comp_dict(
                    self.driver_db[self.prev_indx, :])
                blank = ts.Material.create(self, self.blanket_mass, blank_comp)
                driv = ts.Material.create(self, self.driver_mass, driver_comp)
                driv.absorb(blank)
                mat_list = [driv]
            # absorb all materials
            # best way is to do it separately, but idk how to do it :(
            for mat in mat_list[1:]:
                mat_list[0].absorb(mat)
            responses[trade] = mat_list[0]
        return responses

    def get_material_requests(self):
        """ Ask for material fill_commod """
        ports = []
        if self.shutdown:
            return {}
        if not self.loaded:
            recipes = {}
            qty = {}
            mat = {}
            for key, val in self.buf_dict.items():
                if 'driver' in key:
                    recipes[key] = self.array_to_comp_dict(
                        self.f['siminfo_driver_init_comp'])
                if 'blanket' in key:
                    recipes[key] = self.array_to_comp_dict(
                        self.f['siminfo_blanket_init_comp'])
                qty[key] = val.capacity - val.quantity
                mat[key] = ts.Material.create_untracked(qty[key], recipes[key])

            for key, val in self.buf_dict.items():
                if 'driver' in key:
                    ports.append({
                        'commodities': {
                            self.init_fuel_commod: mat[key]
                        },
                        'constraints': qty[key]
                    })
                if 'blanket' in key:
                    ports.append({
                        'commodities': {
                            self.fill_commod: mat[key]
                        },
                        'constraints': qty[key]
                    })
            return ports
        elif self.get_fill and self.context.time != self.exit_time:
            commods = {self.fill_commod: self.demand_mat}
            port = {'commodities': commods, 'constraints': self.qty}
            return port
        return []

    def accept_material_trades(self, responses):
        """ Get fill_commod and store it into fill_tank """
        for key, mat in responses.items():
            if key.request.commodity == self.init_fuel_commod and not self.loaded:
                self.driver_buf.push(mat)
            elif key.request.commodity == self.fill_commod:
                to_blanket = mat.extract_qty(self.blanket_buf.space)
                self.blanket_buf.push(to_blanket)
                self.driver_buf.push(mat)

    def array_to_comp_dict(self, array):
        dictionary = {}
        for i, val in enumerate(array):
            if val != 0:
                iso = self.isos[i].decode('utf8')
                dictionary[iso] = val
        return dictionary

    def produce_power(self, produce=True):
        if produce:
            lib.record_time_series(lib.POWER, self, float(self.power_cap))
        else:
            lib.record_time_series(lib.POWER, self, 0)
Ejemplo n.º 11
0
class SupplyDrivenDeploymentInst(Institution):
    """
    This institution deploys facilities based on demand curves using
    time series methods.
    """

    facility_commod = ts.MapStringString(
        doc="A map of facilities and each of their corresponding" +
        " output commodities",
        tooltip="Map of facilities and output commodities in the " +
        "institution",
        alias=['facility_commod', 'facility', 'commod'],
        uilabel="Facility and Commodities")

    facility_capacity = ts.MapStringDouble(
        doc="A map of facilities and each of their corresponding" +
        " capacities",
        tooltip="Map of facilities and capacities in the " + "institution",
        alias=['facility_capacity', 'facility', 'capacity'],
        uilabel="Facility and Capacities")

    facility_pref = ts.MapStringString(
        doc="A map of facilities and each of their corresponding" +
        " preferences",
        tooltip="Map of facilities and preferences in the " + "institution",
        alias=['facility_pref', 'facility', 'pref'],
        uilabel="Facility and Preferences",
        default={})

    facility_constraintcommod = ts.MapStringString(
        doc="A map of facilities and each of their corresponding" +
        " constraint commodity",
        tooltip="Map of facilities and constraint commodities in the " +
        "institution",
        alias=['facility_constraintcommod', 'facility', 'constraintcommod'],
        uilabel="Facility and Constraint Commodities",
        default={})

    facility_constraintval = ts.MapStringDouble(
        doc="A map of facilities and each of their corresponding" +
        " constraint values",
        tooltip="Map of facilities and constraint values in the " +
        "institution",
        alias=['facility_constraintval', 'facility', 'constraintval'],
        uilabel="Facility and Constraint Commodity Values",
        default={})

    calc_method = ts.String(
        doc="This is the calculated method used to determine " +
        "the supply and capacity for the commodities of " +
        "this institution. Currently this can be ma for " +
        "moving average, or arma for autoregressive " + "moving average.",
        tooltip="Calculation method used to predict supply/capacity",
        uilabel="Calculation Method")

    record = ts.Bool(
        doc="Indicates whether or not the institution " +
        "should record it's output to text file outputs." +
        "The output files match the name of the " +
        "demand commodity of the institution.",
        tooltip=
        "Boolean to indicate whether or not to record output to text file.",
        uilabel="Record to Text",
        default=False)

    installed_cap = ts.Bool(
        doc="True if facility deployment is governed by installed capacity. " +
        "False if deployment is governed by actual commodity capacity",
        tooltip="Boolean to indicate whether or not to use installed" +
        "capacity as supply",
        uilabel="installed cap",
        default=False)

    steps = ts.Int(
        doc="The number of timesteps forward to predict supply and capacity",
        tooltip="The number of predicted steps forward",
        uilabel="Timesteps for Prediction",
        default=1)

    back_steps = ts.Int(doc="This is the number of steps backwards " +
                        "from the current time step that will " +
                        "be used to make the prediction. If " +
                        "this is set to '0' then the calculation " +
                        "will use all values in the time series.",
                        tooltip="",
                        uilabel="Back Steps",
                        default=10)

    capacity_std_dev = ts.Double(
        doc="The standard deviation adjustment for the capacity side.",
        tooltip="The standard deviation adjustment for the capacity side.",
        uilabel="capacity Std Dev",
        default=0)

    buffer_type = ts.MapStringString(
        doc=
        "Indicates whether the buffer is in percentage or float form, perc: %,"
        + "float: float for each commodity",
        tooltip=
        "Capacity buffer in Percentage or float form for each commodity",
        alias=['buffer_type', 'commod', 'type'],
        uilabel="Capacity Buffer type",
        default={})

    capacity_buffer = ts.MapStringDouble(
        doc="Capacity buffer size: % or float amount",
        tooltip="Capacity buffer amount",
        alias=['capacity_buffer', 'commod', 'buffer'],
        uilabel="Capacity Buffer",
        default={})

    degree = ts.Int(
        doc="The degree of the fitting polynomial.",
        tooltip="The degree of the fitting polynomial, if using calc methods" +
        " poly, fft, holtz-winter and exponential smoothing." +
        " Additionally, degree is used to as the 'period' input to " +
        "the stepwise_seasonal method.",
        uilabel="Degree Polynomial Fit / Period for stepwise_seasonal",
        default=1)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.commodity_capacity = {}
        self.commodity_supply = {}
        self.installed_capacity = {}
        self.fac_commod = {}
        self.fresh = True
        CALC_METHODS['ma'] = no.predict_ma
        CALC_METHODS['arma'] = no.predict_arma
        CALC_METHODS['arch'] = no.predict_arch
        CALC_METHODS['poly'] = do.polyfit_regression
        CALC_METHODS['exp_smoothing'] = do.exp_smoothing
        CALC_METHODS['holt_winters'] = do.holt_winters
        CALC_METHODS['fft'] = do.fft
        CALC_METHODS['sw_seasonal'] = ml.stepwise_seasonal

    def print_variables(self):
        print('commodities: %s' % self.commodity_dict)
        print('calc_method: %s' % self.calc_method)
        print('record: %s' % str(self.record))
        print('steps: %i' % self.steps)
        print('back_steps: %i' % self.back_steps)
        print('capacity_std_dev: %f' % self.capacity_std_dev)

    def enter_notify(self):
        super().enter_notify()
        if self.fresh:
            # convert list of strings to dictionary
            self.commodity_dict = di.build_dict(self.facility_commod,
                                                self.facility_capacity,
                                                self.facility_pref,
                                                self.facility_constraintcommod,
                                                self.facility_constraintval)
            for commod, proto_dict in self.commodity_dict.items():
                protos = proto_dict.keys()
                for proto in protos:
                    self.fac_commod[proto] = commod
            commod_list = list(self.commodity_dict.keys())
            for commod in commod_list:
                self.installed_capacity[commod] = defaultdict(float)
                self.installed_capacity[commod][0] = 0.
            self.buffer_dict = di.build_buffer_dict(self.capacity_buffer,
                                                    commod_list)
            self.buffer_type_dict = di.build_buffer_type_dict(
                self.buffer_type, commod_list)
            for commod in self.commodity_dict:
                # swap supply and demand for supply_inst
                # change demand into capacity
                lib.TIME_SERIES_LISTENERS["supply" + commod].append(
                    self.extract_supply)
                lib.TIME_SERIES_LISTENERS["demand" + commod].append(
                    self.extract_capacity)
                self.commodity_capacity[commod] = defaultdict(float)
                self.commodity_supply[commod] = defaultdict(float)
            for child in self.children:
                itscommod = self.fac_commod[child.prototype]
                self.installed_capacity[itscommod][0] += self.commodity_dict[
                    itscommod][child.prototype]['cap']
            self.fresh = False

    def decision(self):
        """
        This is the tock method for decision the institution. Here the institution determines the difference
        in supply and capacity and makes the the decision to deploy facilities or not.
        """
        time = self.context.time
        for commod, proto_dict in self.commodity_dict.items():

            diff, capacity, supply = self.calc_diff(commod, time)
            lib.record_time_series('calc_supply' + commod, self, supply)
            lib.record_time_series('calc_capacity' + commod, self, capacity)

            if diff < 0:
                if self.installed_cap:
                    deploy_dict = solver.deploy_solver(self.installed_capacity,
                                                       self.commodity_dict,
                                                       commod, diff, time)
                else:
                    deploy_dict = solver.deploy_solver(self.commodity_supply,
                                                       self.commodity_dict,
                                                       commod, diff, time)
                for proto, num in deploy_dict.items():
                    for i in range(num):
                        self.context.schedule_build(self, proto)
                # update installed capacity dict
                for proto, num in deploy_dict.items():
                    self.installed_capacity[commod][time + 1] = \
                        self.installed_capacity[commod][time] + \
                        self.commodity_dict[commod][proto]['cap'] * num
            else:
                self.installed_capacity[commod][
                    time + 1] = self.installed_capacity[commod][time]
            if self.record:
                out_text = "Time " + str(time) + \
                    " Deployed " + str(len(self.children))
                out_text += " capacity " + \
                    str(self.commodity_capacity[commod][time])
                out_text += " supply " + \
                    str(self.commodity_supply[commod][time]) + "\n"
                with open(commod + ".txt", 'a') as f:
                    f.write(out_text)
        for child in self.children:
            if child.exit_time == time:
                itscommod = self.fac_commod[child.prototype]
                self.installed_capacity[itscommod][
                    time + 1] -= self.commodity_dict[itscommod][
                        child.prototype]['cap']

    def calc_diff(self, commod, time):
        """
        This function calculates the different in capacity and supply for a given facility
        Parameters
        ----------
        time : int
            This is the time step that the difference is being calculated for.
        Returns
        -------
        diff : double
            This is the difference between capacity and supply at [time]
        capacity : double
            The calculated capacity of the capacity commodity at [time].
        supply : double
            The calculated supply of the supply commodity at [time]
        """
        if time not in self.commodity_supply[commod]:
            t = 0
            self.commodity_supply[commod][time] = 0
        if time not in self.commodity_capacity[commod]:
            self.commodity_capacity[commod][time] = 0.0
        capacity = self.predict_capacity(commod)

        if self.buffer_type_dict[commod] == 'perc':
            supply = self.predict_supply(commod,
                                         time) * (1 + self.buffer_dict[commod])
        elif self.buffer_type_dict[commod] == 'float':
            supply = self.predict_supply(commod,
                                         time) + self.buffer_dict[commod]
        else:
            raise Exception(
                'You can only choose perc (%) or float (double) for buffer size'
            )

        diff = capacity - supply
        return diff, capacity, supply

    def predict_capacity(self, commod):
        def target(incommod):
            if self.installed_cap:
                return self.installed_capacity[incommod]
            else:
                return self.commodity_capacity[incommod]

        if self.calc_method in ['arma', 'ma', 'arch']:
            capacity = CALC_METHODS[self.calc_method](
                target(commod),
                steps=self.steps,
                std_dev=self.capacity_std_dev,
                back_steps=self.back_steps)
        elif self.calc_method in [
                'poly', 'exp_smoothing', 'holt_winters', 'fft'
        ]:
            capacity = CALC_METHODS[self.calc_method](
                target(commod), back_steps=self.back_steps, degree=self.degree)
        elif self.calc_method in ['sw_seasonal']:
            capacity = CALC_METHODS[self.calc_method](target(commod),
                                                      period=self.degree)
        else:
            raise ValueError(
                'The input calc_method is not valid. Check again.')
        return capacity

    def predict_supply(self, commod, time):
        if self.calc_method in ['arma', 'ma', 'arch']:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply[commod],
                steps=self.steps,
                std_dev=self.capacity_std_dev,
                back_steps=self.back_steps)
        elif self.calc_method in [
                'poly', 'exp_smoothing', 'holt_winters', 'fft'
        ]:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply[commod],
                back_steps=self.back_steps,
                degree=self.degree)
        elif self.calc_method in ['sw_seasonal']:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply[commod], period=self.degree)
        else:
            raise ValueError(
                'The input calc_method is not valid. Check again.')
        return supply

    def extract_capacity(self, agent, time, value, commod):
        """
        Gather information on the available capacity of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_capacity[commod][time] += value
        # update commodities
        # self.commodity_dict[commod] = {agent.prototype: value}

    def extract_supply(self, agent, time, value, commod):
        """
        Gather information on the capacity of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_supply[commod][time] += value
Ejemplo n.º 12
0
class udb_reactor(Facility):

    reactor_id = ts.Int(
        doc="This variable lists the reactor id of the reactors in the database ",
        tooltip="Reactor Id in database",
        uilabel="Reactor ID"
    )

    outcommod = ts.String(
        doc="The commodity this institution will output",
        tooltip="Output commodity",
        uilabel="Output Commodity"
    )

    db_path = ts.String(
        doc="Path to the sqlite file of udb data",
        tooltip="Absolute path to the udb sqlite data"
    )

    recipe_name = ts.String(
        doc="if using recipe, this parameter holds the recipe name",
        tooltip="recipe to be used for recipe composition",
        default=''
    )

    startyear = ts.Int(
        doc="Startyear of simulation",
        tooltip="Simulation Startyear"
    )

    startmonth = ts.Int(
        doc="Startmonth of simulation",
        tooltip="Simulation Startmonth"
    )

    use_rom = ts.Bool(
        doc="Boolean to use reduced-order-model for depletion"
        tooltip="ROM bool"
        default=0
    )

    inventory = ts.ResBufMaterialInv()

    ## Import pickle file into `depletion_model_dict'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def write(self, string):
        # for debugging purposes.
        with open('log.txt', 'a+') as f:
            f.write(string + '\n')

    def enter_notify(self):
        super().enter_notify()
        df = pd.read_table(self.db_path)
        self.reactor_assems = df.loc[df['reactor_id'] == self.reactor_id]
        self.reactor_assems['discharge_date'] = self.reactor_assems['discharge_date'].str[:7]
        self.assembly_dates = self.reactor_assems['discharge_date'].unique()
        # for memory
        del df

    def tick(self):
        year_month = self.find_year_month()
        if year_month in self.assembly_dates:
            assembly_id_list = self.reactor_assems.loc[self.reactor_assems['discharge_date'] == year_month]['assembly_id'].unique()

            for assembly in assembly_id_list:
                assem_mass = np.array(
                    self.reactor_assems.loc[self.reactor_assems['assembly_id'] == assembly_id]['initial_uranium_kg'])[0]
                if self.recipe_name != '':
                    composition = self.context.get_recipe(self.recipe_name)
                elif use_rom:
                    composition = self.rom_depletion(assembly)
                else:
                    composition = self.data_depletion(assembly)

                material = ts.Material.create(self, assem_mass, composition)
                self.inventory.push(material)


    def get_material_bids(self, requests):
        """ Gets material bids that want its `outcommod' an
            returns bid portfolio
        """
        if self.outcommod not in requests:
            return
        reqs = requests[self.outcommod]
        bids = []
        for req in reqs:
            qty = min(req.target.quantity, self.inventory.quantity)
            # returns if the inventory is empty
            if self.inventory.empty():
                return
            # get the composition of the material next in line
            next_in_line = self.inventory.peek()
            mat = ts.Material.create_untracked(qty, next_in_line.comp())
            bids.append({'request': req, 'offer': mat})
        port = {"bids": bids}
        return port


    def get_material_trades(self, trades):
        responses = {}
        for trade in trades:
            mat_list = self.inventory.pop_n(self.inventory.count)
            # absorb all materials
            # best way is to do it separately, but idk how to do it :(
            for mat in mat_list[1:]:
                mat_list[0].absorb(mat)
            responses[trade] = mat_list[0]
        return responses

    def find_year_month(self):
        time = self.context.time
        year = self.startyear + time // 12
        month = self.startmonth + time % 12
        if month < 10:
            return (str(year) + '-0' + str(month))
        else:
            return (str(year) + '-' + str(month))

    def rom_depletion(self, assembly_id):
        enr_bu = self.reactor_assems.loc[self.reactor_assems['assembly_id'] == assembly_id][[
            'initial_enrichment', 'discharge_burnup']]
        enr_bu = np.array(enr_bu)[0]
        
        composition = {}
        for iso, model in self.depletion_model_dict.items():
            composition[iso] = model.predict(enr_bu)[0]

    def data_depletion(self, assembly_id):
        assem_data = self.reactor_assems.loc[self.reactor_assems['assembly_id'] == assembly_id][['name', 'total_mass_g']]
        assem_data['comp'] = assem_data['total_mass_g'] / sum(assem_data['total_mass_g'])
        composition = {}
        for indx, row in assem_data.iterrows():
            composition[row['name']] = row['comp']
        return composition
Ejemplo n.º 13
0
class Truck(Facility):
    """
    A truck that transports material through the fuel cycle.
    """

    dest_commodity = ts.String(
        doc="The commodity that the truck carries",
        tooltip="Shipped Commodity",
        uilabel="Commodity"
    )

    source_commodity = ts.String(
        doc="The commodity that the truck carries",
        tooltip="Shipped Commodity",
        uilabel="Commodity"
    )

    contract = ts.PairDoubleMapIntDouble(
        doc="The contract quantity and recipe",
        tooltip="Contract quantity and recipe",
        uilabel="Contract",
        default=(0.0,{})
    )

    contractee = ts.Int(
        doc="The reactor that originates the contract with the truck (agentID)",
        tooltip="Reactor generating the contract",
        uilabel="Contractee",
        default=-1
    )

    total_trip_duration = ts.Int(
        doc="The reactor that originates the contract with the truck (agentID)",
        tooltip="Reactor generating the contract",
        uilabel="Contractee"
    )

    trip_time = ts.Int(
        doc="The reactor that originates the contract with the truck (agentID)",
        tooltip="Reactor generating the contract",
        uilabel="Contractee",
        default=-1
    )

    return_trip_time = ts.Int(
        doc="The reactor that originates the contract with the truck (agentID)",
        tooltip="Reactor generating the contract",
        uilabel="Contractee",
        default=-1
    )

    capacity = ts.Double(
        doc="The reactor that originates the contract with the truck (agentID)",
        tooltip="Reactor generating the contract",
        uilabel="Contractee",
    )

    inventory = ts.ResBufMaterialInv()


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.inventory.capacity = self.capacity
    
    def tock(self):
        #print("Truck: " + str(self.id) + " " + str(self.inventory.count))
        #print(self.return_trip_time, self.trip_time, self.total_trip_duration)
        if self.return_trip_time >= 0:
            self.return_trip_time += 1
        if self.return_trip_time == self.total_trip_duration:
            self.return_trip_time = -1
            return
        elif self.trip_time >= 0 and self.trip_time < self.total_trip_duration:
            self.trip_time += 1

    def get_material_requests(self):
        if self.return_trip_time >= 0:
            return []
        if self.contractee > -1 and self.inventory.count == 0:
            #requestfuel
            target_a = ts.Material.create_untracked(self.contract[0], self.contract[1])
            commods = {self.source_commodity: target_a}
            port = {"commodities": commods, "constraints": self.capacity}
            #print(str(self.id) + " is attempting to pick up fresh fuel")
            return [port]
        else:
            return []

    def get_material_bids(self, requests):
        if self.return_trip_time >= 0:
            return
        ports = []
        if self.dest_commodity not in requests and self.dest_commodity+"-contract" not in requests:
            return
        if self.contractee == -1 and self.inventory.count == 0:
            #print(str(self.id) + " is accepting contracts")
            #offercontract
            if self.dest_commodity+"-contract" in requests:
                reqs = requests[self.dest_commodity+"-contract"]
                bids = list(reqs)
                ports.append({"bids": bids, "constraints": self.capacity})
                return ports
        elif self.contractee > -1 and self.inventory.count > 0 and self.trip_time == self.total_trip_duration:
            #offerfuel
            bid = ""
            reqs = requests[self.dest_commodity]
            for req in reqs:
                if req.requester.id == self.contractee:
                    bid = req
                    break
            bids = [bid]
            ports.append({"bids": bids, "constraints": self.capacity})
            return ports
        else:
            return ports

    def get_material_trades(self, trades):
        responses = {}
        if self.return_trip_time >= 0:
            return responses
        if self.contractee == -1 and self.inventory.count == 0:
            #offercontract
            for trade in trades:
                self.contract = (trade.amt, trade.request.target.comp())
                self.contractee = trade.request.requester.id
                #print(str(self.id) + " is accepting a contract from " + str(self.contractee))
        elif self.contractee > -1 and self.inventory.count > 0 and self.trip_time == self.total_trip_duration:
            #offerfuel
            for trade in trades:
                mat = self.inventory.pop()
                responses[trade] = mat
            #print(str(self.id) + " is dropping off fuel at " + str(self.contractee))
            self.return_trip_time = 0
            self.contract = (-1, {})
            self.contractee = -1
        return responses

    def accept_material_trades(self, responses):
        if self.return_trip_time >= 0:
            return
        for mat in responses.values():
            self.inventory.push(mat)
            self.trip_time = 0
Ejemplo n.º 14
0
class DeterministicInst(Institution):
    """
    This institution deploys facilities based on demand curves using
    time series methods.
    """

    demand_eq = ts.String(
        doc="This is the string for the demand equation of the driving commodity. " +
        "The equation should use `t' as the dependent variable",
        tooltip="Demand equation for driving commodity",
        uilabel="Demand Equation"
    )

    prototypes = ts.VectorString(
        doc="A list of the prototypes controlled by the institution.",
        tooltip="List of prototypes in the institution.",
        uilabel="Prototypes",
        uitype="oneOrMore"
    )

    fac_rates = ts.VectorString(
        doc="This is the string for the demand equation of the driving commodity. " +
        "The equation should use `t' as the dependent variable",
        tooltip="Demand equation for driving commodity",
        uitype="oneOrMore",
        uilabel="Demand Equation"
    )


    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.commods = {}
        self.construct = []
        self.demand = [0]
        
    def enter_notify(self):
        super().enter_notify() 
        for proto in self.prototypes:
            self.construct.append(0)

    def decision(self):
        self.commods, matrix = self.construct_matrix()
        t = self.context.time
        self.demand.append(self.demand_calc(t+1))
        demand = self.demand[-1] - self.demand[-2]
        results = [0]*len(self.prototypes)
        results[0] = demand
        solve = []
        for proto in self.prototypes:
            solve.append(matrix[proto])
        out = np.linalg.solve(solve, results)
        print(out)
        print(self.construct)
        for i in range(len(out)):
            self.construct[i] += out[i]
        print(self.construct)
        for i in range(len(self.construct)):
            j = 0
            while j < self.construct[i]:
                self.context.schedule_build(self, self.prototypes[i])
                self.construct[i] -= 1
                j+=1       

    def construct_matrix(self):
        matrix = {}
        commodities = {}
        for i in range(len(self.prototypes)):
            proto = self.prototypes[i]
            matrix[proto] = np.array(self.fac_rates[i].split(",")).astype(float)
        return commodities, matrix
    '''    
    def extract_supply(self, agent, time, value, commod):
        """
        Gather information on the available supply of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_supply[commod][time] += value
        # update commodities
        # self.commodity_dict[commod] = {agent.prototype: value}

    def extract_demand(self, agent, time, value, commod):
        """
        Gather information on the demand of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_demand[commod][time] += value
    '''
    def demand_calc(self, time):
        """
        Calculate the electrical demand at a given timestep (time).
        Parameters
        ----------
        time : int
            The timestep that the demand will be calculated at.
        Returns
        -------
        demand : The calculated demand at a given timestep.
        """
        t = time
        demand = eval(self.demand_eq)
        return demand
Ejemplo n.º 15
0
class NOInst(Institution):
    """
    This institution deploys facilities based on demand curves using 
    Non Optimizing (NO) methods. 
    """

    prototypes = ts.VectorString(
        doc="A list of prototypes that the institution will draw upon to fit" +
        "the demand curve",
        tooltip="List of prototypes the institution can use to meet demand",
        uilabel="Prototypes",
        uitype="oneOrMore")

    growth_rate = ts.Double(
        doc="This value represents the growth rate that the institution is " +
        "attempting to meet.",
        tooltip="Growth rate of growth commodity",
        uilabel="Growth Rate",
        default="0.02")

    supply_commod = ts.String(
        doc=
        "The commodity this institution will be monitoring for supply growth.",
        tooltip="Supply commodity",
        uilabel="Supply Commodity")

    demand_commod = ts.String(
        doc=
        "The commodity this institution will be monitoring for demand growth.",
        tooltip="Growth commodity",
        uilabel="Growth Commodity")

    initial_demand = ts.Double(doc="The initial power of the facility",
                               tooltip="Initital demand",
                               uilabel="Initial demand")

    calc_method = ts.String(
        doc=
        "This is the calculated method used to determine the supply and demand "
        +
        "for the commodities of this institution. Currently this can be ma for "
        + "moving average, or arma for autoregressive moving average.",
        tooltip="Calculation method used to predict supply/demand",
        uilabel="Calculation Method")

    record = ts.Bool(
        doc=
        "Indicates whether or not the institution should record it's output to text "
        +
        "file outputs. The output files match the name of the demand commodity of the "
        + "institution.",
        tooltip=
        "Boolean to indicate whether or not to record output to text file.",
        uilabel="Record to Text",
        default=False)

    supply_std_dev = ts.Double(
        doc="The number of standard deviations off mean for ARMA predictions",
        tooltip="Std Dev off mean for ARMA",
        uilabel="Supple Std Dev",
        default=0.)

    demand_std_dev = ts.Double(
        doc="The number of standard deviations off mean for ARMA predictions",
        tooltip="Std Dev off mean for ARMA",
        uilabel="Demand Std Dev",
        default=0.)

    steps = ts.Int(
        doc="The number of timesteps forward for ARMA or order of the MA",
        tooltip="Std Dev off mean for ARMA",
        uilabel="Demand Std Dev",
        default=1)
    back_steps = ts.Int(
        doc="This is the number of steps backwards from the current time step"
        + "that will be used to make the prediction. If this is set to '0'" +
        "then the calculation will use all values in the time series.",
        tooltip="",
        uilabel="",
        default="5")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.commodity_supply = defaultdict(float)
        self.commodity_demand = defaultdict(float)
        self.fac_supply = {}
        CALC_METHODS['ma'] = self.moving_avg
        CALC_METHODS['arma'] = self.predict_arma
        CALC_METHODS['arch'] = self.predict_arch

    def enter_notify(self):
        super().enter_notify()
        lib.TIME_SERIES_LISTENERS[self.supply_commod].append(
            self.extract_supply)
        lib.TIME_SERIES_LISTENERS[self.demand_commod].append(
            self.extract_demand)

    def tock(self):
        """
        This is the tock method for the institution. Here the institution determines the difference
        in supply and demand and makes the the decision to deploy facilities or not.     
        """
        time = self.context.time
        diff, supply, demand = self.calc_diff(time)
        if diff < 0:
            proto = random.choice(self.prototypes)
            prod_rate = self.commodity_supply[time] / len(self.children)
            number = np.ceil(-1 * diff / prod_rate)
            i = 0
            while i < number:
                self.context.schedule_build(self, proto)
                i += 1
        if self.record:
            with open(self.demand_commod + ".txt", 'a') as f:
                f.write("Time " + str(time) + " Deployed " +
                        str(len(self.children)) + " supply " +
                        str(self.commodity_supply[time]) + " demand " +
                        str(self.commodity_demand[time]) + "\n")

    def calc_diff(self, time):
        """
        This function calculates the different in supply and demand for a given facility
        Parameters
        ----------        
        time : int
            This is the time step that the difference is being calculated for.
        Returns
        -------
        diff : double
            This is the difference between supply and demand at [time]
        supply : double
            The calculated supply of the supply commodity at [time].
        demand : double
            The calculated demand of the demand commodity at [time]
        """
        try:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply,
                steps=self.steps,
                std_dev=self.supply_std_dev)
        except (ValueError, np.linalg.linalg.LinAlgError):
            supply = CALC_METHODS['ma'](self.commodity_supply)
        if not self.commodity_demand:
            self.commodity_demand[time] = self.initial_demand
        if self.demand_commod == 'power':
            demand = self.demand_calc(time + 1)
            self.commodity_demand[time] = demand
        try:
            demand = CALC_METHODS[self.calc_method](
                self.commodity_demand,
                steps=self.steps,
                std_dev=self.demand_std_dev)
        except (np.linalg.linalg.LinAlgError, ValueError):
            demand = CALC_METHODS['ma'](self.commodity_demand)
        diff = supply - demand
        return diff, supply, demand

    def extract_supply(self, agent, time, value):
        """
        Gather information on the available supply of a commodity over the
        lifetime of the simulation. 

        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        self.commodity_supply[time] += value

    def extract_demand(self, agent, time, value):
        """
        Gather information on the demand of a commodity over the
        lifetime of the simulation.
        
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        self.commodity_demand[time] += value

    def demand_calc(self, time):
        """
        Calculate the electrical demand at a given timestep (time). 
        
        Parameters
        ----------
        time : int
            The timestep that the demand will be calculated at. 
        Returns
        -------
        demand : The calculated demand at a given timestep.
        """
        timestep = self.context.dt
        time = time * timestep
        demand = self.initial_demand * (
            (1.0 + self.growth_rate)**(time / 3.154e+7))
        return demand

    def moving_avg(self, ts, steps=1, std_dev=0, back_steps=5):
        """
        Calculates the moving average of a previous [order] entries in
        timeseries [ts]. It will automatically reduce the order if the
        length of ts is shorter than the order. 

        Parameters:
        -----------
        ts : Array of doubles
            An array of time series data to be used for the arma prediction
        order : int
            The number of values used for the moving average. 
        Returns
        -------
        x : The moving average calculated by the function.         
        """
        supply = np.array(list(ts.values()))
        if steps >= len(supply):
            steps = len(supply) * -1
        else:
            steps *= -1
        x = np.average(supply[steps:])
        return x

    def predict_arma(self, ts, steps=1, std_dev=0, back_steps=5):
        """
        Predict the value of supply or demand at a given time step using the 
        currently available time series data. This method impliments an ARMA
        calculation to perform the prediciton. 

        Parameters:
        -----------
        ts : Array of doubles
            An array of time series data to be used for the arma prediction
        time: int
            The number of timesteps to predict forward. 
        Returns:
        --------
        x : Predicted value for the time series at chosen timestep (time). 
        """
        v = list(ts.values())
        fit = sm.tsa.ARMA(v, (1, 0)).fit(disp=-1)
        forecast = fit.forecast(steps)
        x = fit[0][steps - 1] + fit[1][steps - 1] * std_dev
        return x

    def predict_arch(self, ts, steps=1, std_dev=0, back_steps=5):
        """
        Predict the value of supply or demand at a given time step using the 
        currently available time series data. This method impliments an ARCH
        calculation to perform the prediciton. 
        """
        f_obs = len(ts) - back_steps
        if f_obs < 0 or back_steps == 0: f_obs = 0
        model = arch_model(ts)
        fit = model.fit(disp='nothing',
                        update_freq=0,
                        show_warning=False,
                        first_obs=f_obs)
        forecast = fit.forecast(horizon=steps)
        x = forecast.mean.get('h.1')[len(ts) - 1]
        std_dev = math.sqrt(
            forecast.variance.get('h.1')[len(ts) - 1]) * std_dev
        return x + std_dev
Ejemplo n.º 16
0
class record_listener(Facility):
    f33_file = ts.String(doc="f33_filename",
                         tooltip="tooltip",
                         uilabel='label')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def enter_notify(self):
        super().enter_notify()
        lib.TIME_SERIES_LISTENERS['depletion_history'].append(self.listen)
        self.depl_history = []

    def tick(self):
        print('TICK', self.context.time)
        t = [1, 2, 3, 4, 5, 6, 7, 5, 9, 10]
        p = [11, 12, 13, 14, 15, 16, 17, 15, 19, 20]
        t_ = t[self.context.time]
        p_ = p[self.context.time]
        begin_comp = {'u235': t_, 'u238': 100 - t_}
        print(t_, p_)

        end_comp = self.check_existing_history(t_, p_, begin_comp)
        if end_comp == 0:
            print('Do depletion')
            end_comp = {'cs137': t_, 'u238': 100 - t_}
            self.record(t[self.context.time], p[self.context.time], begin_comp,
                        end_comp)

        print('TICK END\n\n')

    def check_existing_history(self, t_, p_, begin_comp):
        print('Checking existing history for time', self.context.time)
        for i in self.depl_history:
            q = i.split(',')
            print(q)
            entry_dict = {
                'f33_file': q[0],
                't': int(q[1]),
                'p': float(q[2]),
                'begin_comp': self.comp_entry_to_dict(q[3]),
                'end_comp': self.comp_entry_to_dict(q[4])
            }
            print(entry_dict)
            print(t_, p_, begin_comp)
            cat1 = (entry_dict['f33_file'] == self.f33_file)
            cat2 = (entry_dict['t'] == t_)
            cat3 = (entry_dict['p'] == p_)
            cat4 = (entry_dict['begin_comp'] == begin_comp)

            if cat1 and cat2 and cat3 and cat4:
                # already exists
                print('=====================')
                print('=====================')
                print('=====================')
                print('Already Exists!')
                print('=====================')
                print('=====================')
                print('=====================')

                end_comp = entry_dict['end_comp']

                return end_comp

        # if nothing is found:
        return 0

    def comp_entry_to_dict(self, s):
        """ Converts entery iso1:frac1;iso2:frac2;iso3:frac3...
            to dict
        """
        x = s.split(';')
        iso = [q.split(':')[0] for q in x]
        val = [q.split(':')[1] for q in x]
        return {k: float(v) for k, v in zip(iso, val)}

    def listen(self, agent, time, value, commod):
        print('Agent')
        print(agent)
        print('time')
        print(time)
        print('value')
        print(value)
        self.depl_history.append(value)

    def record(self, time, power, begin_comp, end_comp):
        # records hash of [f33_file, begincomphash, time, power, endcomphas]
        l = [self.f33_file, str(time), str(power)]

        # boc:
        """
        boc = l + ['boc']
        print(boc)
        for iso, frac in begin_comp.items():
            row = boc + [str(iso), str(frac)]
            lib.record_time_series('depletion_history', self, ','.join(row))
        eoc = l + ['eoc']
        print(eoc)
        for iso, frac in end_comp.items():
            row = eoc + [str(iso), str(frac)]
            lib.record_time_series('depletion_history', self, ','.join(row))
        """
        s = ','.join(l) + ','
        for iso, frac in begin_comp.items():
            s += str(iso) + ':' + str(frac) + ';'
        s = s[:-1] + ','
        for iso, frac in end_comp.items():
            s += str(iso) + ':' + str(frac) + ';'
        s = s[:-1]
        print(s)
        lib.record_time_series('depletion_history', self, s)

        print('done')
Ejemplo n.º 17
0
class Reactor(Facility):
    """
    A reactor model that requests fuel early such that it will recieve fuel in time for
    operation.  
    """

    request_lead_time = ts.Double(
        doc="The number of time steps before refuel that the reactor will request fuel.", 
        tooltip="The number of time steps before refuel that the reactor will request fuel.",
        uilabel="Request Lead Time"
    )

    commodity = ts.String(
        doc="The commodity that the reactor desires", 
        tooltip="Reactor Commodity",
        uilabel="Commodity"
    )

    cycle_length = ts.Double(
        doc="The amount of time steps between reactor refuels", 
        tooltip="Cycle length of the reactor.",
        uilabel="Cycle Length"
    )
    
    recipe = ts.String(
        doc="Recipe", 
        tooltip="Recipe",
        uilabel="Recipe"
    )

    fuel_mass = ts.Double(
        doc="Mass of requested fuel", 
        tooltip="Mass of Batch",
        uilabel="Fuel Mass"
    )


    fresh_fuel = ts.ResBufMaterialInv(capacity=1000.)
    core = ts.ResBufMaterialInv(capacity=1000.)
    waste = ts.ResBufMaterialInv()
    

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.rx_time = 0;
        self.ct_time = -2;        

    def tick(self):
        #print(self.id, self.fresh_fuel.count, self.core.count, self.waste.count)
        if self.rx_time == self.cycle_length:
            self.waste.push(self.core.pop())
            self.core.push(self.fresh_fuel.pop())
        elif self.rx_time < self.cycle_length:
            self.rx_time += 1
            self.ct_time += 1

    def get_material_requests(self):
        ports = []
        if self.fresh_fuel.count == 0:
            #print(str(self.id) + " is requesting fuel")
            request_qty = self.fuel_mass
            recipe_a = self.context.get_recipe(self.recipe)
            target_a = ts.Material.create_untracked(request_qty, recipe_a)
            commods = {self.commodity: target_a}
            port = {"commodities": commods, "constraints": request_qty}
            ports.append(port)
        if self.ct_time == self.cycle_length-self.request_lead_time or self.ct_time == -1:
            #print(str(self.id) + " requesting contract")
            request_qty = self.fuel_mass
            recipe_a = self.context.get_recipe(self.recipe)
            target_a = ts.Material.create_untracked(request_qty, recipe_a)
            commods = {self.commodity+"-contract": target_a}
            port = {"commodities": commods, "constraints": request_qty}
            ports.append(port)
        return ports

    def accept_material_trades(self, responses):
        for mat in responses.values():
            if self.core.count == 0:
                self.core.push(mat)
            else:
                self.fresh_fuel.push(mat)
            self.rx_time = 0
            self.ct_time = 0
Ejemplo n.º 18
0
class NOInst(Institution):
    """
    This institution deploys facilities based on demand curves using
    Non Optimizing (NO) methods.
    """

    prototypes = ts.VectorString(
        doc="A list of prototypes that the institution will draw upon to fit" +
        "the demand curve",
        tooltip="List of prototypes the institution can use to meet demand",
        uilabel="Prototypes",
        uitype="oneOrMore")

    growth_rate = ts.Double(
        doc="This value represents the growth rate that the institution is " +
        "attempting to meet.",
        tooltip="Growth rate of growth commodity",
        uilabel="Growth Rate")

    growth_commod = ts.String(
        doc=
        "The commodity this institution will be monitoring for demand growth. "
        + "The default value of this field is electric power.",
        tooltip="Growth commodity",
        uilabel="Growth Commodity")

    initial_demand = ts.Double(doc="The initial power of the facility",
                               tooltip="Initital demand",
                               uilabel="Initial demand")

    #The supply of a commodity
    commodity_supply = {}

    def tick(self):
        """
        #Method for the deployment of facilities.
        """
        if self.growth_commod not in lib.TIME_SERIES_LISTENERS:
            lib.TIME_SERIES_LISTENERS[self.growth_commod].append(
                self.extract_supply)
        time = self.context.time
        if time is 0:
            return
        print(self.commodity_supply[time - 1], self.demand_calc(time))
        if self.commodity_supply[time - 1] < self.demand_calc(time):
            proto = random.choice(self.prototypes)
            print("New fac: " + proto)
            print(self.kind)
            self.context.schedule_build(self, proto)

    def extract_supply(self, agent, time, value):
        """
        Gather information on the available supply of a commodity over the
        lifetime of the simulation.
        """
        if time in self.commodity_supply:
            self.commodity_supply[time] += value
        else:
            self.commodity_supply[time] = value

    def demand_calc(self, time):
        """
        Calculate the electrical demand at a given timestep (time).
        Parameters
        ----------
        time : int
            The timestep that the demand will be calculated at.
        """
        timestep = self.context.dt / 86400 / 28
        demand = self.initial_demand * (
            (1.0 + self.growth_rate)**(time / timestep))
        return demand
Ejemplo n.º 19
0
class TimeSeriesInst(Institution):
    """
    This institution deploys facilities based on demand curves using
    time series methods.
    """

    commodities = ts.VectorString(
        doc="A list of commodities that the institution will manage. " +
        "commodity_prototype_capacity format" +
        " where the commoditity is what the facility supplies",
        tooltip="List of commodities in the institution.",
        uilabel="Commodities",
        uitype="oneOrMore")

    demand_eq = ts.String(
        doc=
        "This is the string for the demand equation of the driving commodity. "
        + "The equation should use `t' as the dependent variable",
        tooltip="Demand equation for driving commodity",
        uilabel="Demand Equation")

    calc_method = ts.String(
        doc=
        "This is the calculated method used to determine the supply and demand "
        +
        "for the commodities of this institution. Currently this can be ma for "
        + "moving average, or arma for autoregressive moving average.",
        tooltip="Calculation method used to predict supply/demand",
        uilabel="Calculation Method")

    record = ts.Bool(
        doc=
        "Indicates whether or not the institution should record it's output to text "
        +
        "file outputs. The output files match the name of the demand commodity of the "
        + "institution.",
        tooltip=
        "Boolean to indicate whether or not to record output to text file.",
        uilabel="Record to Text",
        default=False)

    driving_commod = ts.String(
        doc="Sets the driving commodity for the institution. That is the " +
        "commodity that no_inst will deploy against the demand equation.",
        tooltip="Driving Commodity",
        uilabel="Driving Commodity",
        default="POWER")

    steps = ts.Int(
        doc="The number of timesteps forward to predict supply and demand",
        tooltip="The number of predicted steps forward",
        uilabel="Timesteps for Prediction",
        default=1)

    back_steps = ts.Int(
        doc="This is the number of steps backwards from the current time step"
        + "that will be used to make the prediction. If this is set to '0'" +
        "then the calculation will use all values in the time series.",
        tooltip="",
        uilabel="Back Steps",
        default=10)

    supply_std_dev = ts.Double(
        doc="The standard deviation adjustment for the supple side.",
        tooltip="The standard deviation adjustment for the supple side.",
        uilabel="Supply Std Dev",
        default=0)

    demand_std_dev = ts.Double(
        doc="The standard deviation adjustment for the demand side.",
        tooltip="The standard deviation adjustment for the demand side.",
        uilabel="Demand Std Dev",
        default=0)

    demand_std_dev = ts.Double(
        doc="The standard deviation adjustment for the demand side.",
        tooltip="The standard deviation adjustment for the demand side.",
        uilabel="Demand Std Dev",
        default=0)

    degree = ts.Int(
        doc="The degree of the fitting polynomial.",
        tooltip="The degree of the fitting polynomial, if using calc methods" +
        " poly, fft, holtz-winter and exponential smoothing." +
        " Additionally, degree is used to as the 'period' input to " +
        "the stepwise_seasonal method.",
        uilabel="Degree Polynomial Fit / Period for stepwise_seasonal",
        default=1)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.commodity_supply = {}
        self.commodity_demand = {}
        self.rev_commodity_supply = {}
        self.rev_commodity_demand = {}
        self.fresh = True
        CALC_METHODS['ma'] = no.predict_ma
        CALC_METHODS['arma'] = no.predict_arma
        CALC_METHODS['arch'] = no.predict_arch
        CALC_METHODS['poly'] = do.polyfit_regression
        CALC_METHODS['exp_smoothing'] = do.exp_smoothing
        CALC_METHODS['holt_winters'] = do.holt_winters
        CALC_METHODS['fft'] = do.fft
        CALC_METHODS['sw_seasonal'] = ml.stepwise_seasonal

    def print_variables(self):
        print('commodities: %s' % self.commodity_dict)
        print('demand_eq: %s' % self.demand_eq)
        print('calc_method: %s' % self.calc_method)
        print('record: %s' % str(self.record))
        print('steps: %i' % self.steps)
        print('back_steps: %i' % self.back_steps)
        print('supply_std_dev: %f' % self.supply_std_dev)
        print('demand_std_dev: %f' % self.demand_std_dev)

    def parse_commodities(self, commodities):
        """ This function parses the vector of strings commodity variable
            and replaces the variable as a dictionary. This function should be deleted
            after the map connection is fixed."""
        temp = commodities
        commodity_dict = {}

        for entry in temp:
            # commodity, prototype, capacity, preference, constraint_commod, constraint
            z = entry.split('_')
            if len(z) < 3:
                raise ValueError(
                    'Input is malformed: need at least commodity_prototype_capacity'
                )
            else:
                # append zero for all other values if not defined
                while len(z) < 6:
                    z.append(0)
            if z[0] not in commodity_dict.keys():
                commodity_dict[z[0]] = {}
                commodity_dict[z[0]].update({
                    z[1]: {
                        'cap': float(z[2]),
                        'pref': str(z[3]),
                        'constraint_commod': str(z[4]),
                        'constraint': float(z[5])
                    }
                })

            else:
                commodity_dict[z[0]].update({
                    z[1]: {
                        'cap': float(z[2]),
                        'pref': str(z[3]),
                        'constraint_commod': str(z[4]),
                        'constraint': float(z[5])
                    }
                })
        return commodity_dict

    def enter_notify(self):
        super().enter_notify()
        if self.fresh:
            # convert list of strings to dictionary
            self.commodity_dict = self.parse_commodities(self.commodities)
            commod_list = list(self.commodity_dict.keys())
            for key, val in self.commodity_dict.items():
                for key2, val2 in val.items():
                    if val2['constraint_commod'] != '0':
                        commod_list.append(val2['constraint_commod'])
            commod_list = list(set(commod_list))
            for commod in commod_list:
                lib.TIME_SERIES_LISTENERS["supply" + commod].append(
                    self.extract_supply)
                lib.TIME_SERIES_LISTENERS["demand" + commod].append(
                    self.extract_demand)
                self.commodity_supply[commod] = defaultdict(float)
                self.commodity_demand[commod] = defaultdict(float)
            self.fresh = False

    def decision(self):
        """
        This is the tock method for decision the institution. Here the institution determines the difference
        in supply and demand and makes the the decision to deploy facilities or not.
        """
        time = self.context.time
        for commod, proto_dict in self.commodity_dict.items():

            diff, supply, demand = self.calc_diff(commod, time)
            lib.record_time_series('calc_supply' + commod, self, supply)
            lib.record_time_series('calc_demand' + commod, self, demand)

            if diff < 0:
                deploy_dict = solver.deploy_solver(self.commodity_supply,
                                                   self.commodity_dict, commod,
                                                   diff, time)
                for proto, num in deploy_dict.items():
                    for i in range(num):
                        self.context.schedule_build(self, proto)
            if self.record:
                out_text = "Time " + str(time) + \
                    " Deployed " + str(len(self.children))
                out_text += " supply " + \
                    str(self.commodity_supply[commod][time])
                out_text += " demand " + \
                    str(self.commodity_demand[commod][time]) + "\n"
                with open(commod + ".txt", 'a') as f:
                    f.write(out_text)

    def calc_diff(self, commod, time):
        """
        This function calculates the different in supply and demand for a given facility
        Parameters
        ----------
        time : int
            This is the time step that the difference is being calculated for.
        Returns
        -------
        diff : double
            This is the difference between supply and demand at [time]
        supply : double
            The calculated supply of the supply commodity at [time].
        demand : double
            The calculated demand of the demand commodity at [time]
        """
        if time not in self.commodity_demand[commod]:
            t = 0
            self.commodity_demand[commod][time] = eval(self.demand_eq)
        if time not in self.commodity_supply[commod]:
            self.commodity_supply[commod][time] = 0.0
        supply = self.predict_supply(commod)
        demand = self.predict_demand(commod, time)
        diff = supply - demand
        return diff, supply, demand

    def predict_supply(self, commod):
        if self.calc_method in ['arma', 'ma', 'arch']:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply[commod],
                steps=self.steps,
                std_dev=self.supply_std_dev,
                back_steps=self.back_steps)
        elif self.calc_method in [
                'poly', 'exp_smoothing', 'holt_winters', 'fft'
        ]:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply[commod],
                back_steps=self.back_steps,
                degree=self.degree)
        elif self.calc_method in ['sw_seasonal']:
            supply = CALC_METHODS[self.calc_method](
                self.commodity_supply[commod], period=self.degree)
        else:
            raise ValueError(
                'The input calc_method is not valid. Check again.')
        return supply

    def predict_demand(self, commod, time):
        if commod == self.driving_commod:
            demand = self.demand_calc(time + 1)
            self.commodity_demand[commod][time + 1] = demand
        else:
            if self.calc_method in ['arma', 'ma', 'arch']:
                demand = CALC_METHODS[self.calc_method](
                    self.commodity_demand[commod],
                    steps=self.steps,
                    std_dev=self.supply_std_dev,
                    back_steps=self.back_steps)
            elif self.calc_method in [
                    'poly', 'exp_smoothing', 'holt_winters', 'fft'
            ]:
                demand = CALC_METHODS[self.calc_method](
                    self.commodity_demand[commod],
                    back_steps=self.back_steps,
                    degree=self.degree)
            elif self.calc_method in ['sw_seasonal']:
                demand = CALC_METHODS[self.calc_method](
                    self.commodity_demand[commod], period=self.degree)
            else:
                raise ValueError(
                    'The input calc_method is not valid. Check again.')
        return demand

    def extract_supply(self, agent, time, value, commod):
        """
        Gather information on the available supply of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_supply[commod][time] += value
        # update commodities
        # self.commodity_dict[commod] = {agent.prototype: value}

    def extract_demand(self, agent, time, value, commod):
        """
        Gather information on the demand of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_demand[commod][time] += value

    def demand_calc(self, time):
        """
        Calculate the electrical demand at a given timestep (time).
        Parameters
        ----------
        time : int
            The timestep that the demand will be calculated at.
        Returns
        -------
        demand : The calculated demand at a given timestep.
        """
        t = time
        demand = eval(self.demand_eq)
        return demand
class DemandDrivenDeploymentInst(Institution):
    """
    This institution deploys facilities based on demand curves using
    time series methods.
    """

    facility_commod = ts.MapStringString(
        doc="A map of facilities and each of their corresponding" +
        " output commodities",
        tooltip="Map of facilities and output commodities in the " +
        "institution",
        alias=['facility_commod', 'facility', 'commod'],
        uilabel="Facility and Commodities"
    )

    facility_capacity = ts.MapStringDouble(
        doc="A map of facilities and each of their corresponding" +
        " capacities",
        tooltip="Map of facilities and capacities in the " +
        "institution",
        alias=['facility_capacity', 'facility', 'capacity'],
        uilabel="Facility and Capacities"
    )

    facility_pref = ts.MapStringString(
        doc="A map of facilities and each of their corresponding" +
        " preferences",
        tooltip="Map of facilities and preferences in the " +
        "institution",
        alias=['facility_pref', 'facility', 'pref'],
        uilabel="Facility and Preferences",
        default={}
    )

    facility_constraintcommod = ts.MapStringString(
        doc="A map of facilities and each of their corresponding" +
        " constraint commodity",
        tooltip="Map of facilities and constraint commodities in the " +
        "institution",
        alias=['facility_constraintcommod', 'facility', 'constraintcommod'],
        uilabel="Facility and Constraint Commodities",
        default={}
    )

    facility_constraintval = ts.MapStringDouble(
        doc="A map of facilities and each of their corresponding" +
        " constraint values",
        tooltip="Map of facilities and constraint values in the " +
        "institution",
        alias=['facility_constraintval', 'facility', 'constraintval'],
        uilabel="Facility and Constraint Commodity Values",
        default={}
    )

    facility_sharing = ts.MapStringDouble(
        doc="A map of facilities that share a commodity",
        tooltip="Map of facilities and percentages of sharing",
        alias=['facility_sharing', 'facility', 'percentage'],
        uilabel="Facility and Percentages",
        default={}
    )

    demand_eq = ts.String(
        doc="This is the string for the demand equation of the driving commodity. " +
        "The equation should use `t' as the dependent variable",
        tooltip="Demand equation for driving commodity",
        uilabel="Demand Equation")

    calc_method = ts.String(
        doc="This is the calculated method used to determine the supply and demand " +
        "for the commodities of this institution. Currently this can be ma for " +
        "moving average, or arma for autoregressive moving average.",
        tooltip="Calculation method used to predict supply/demand",
        uilabel="Calculation Method")

    record = ts.Bool(
        doc="Indicates whether or not the institution should record it's output to text " +
        "file outputs. The output files match the name of the demand commodity of the " +
        "institution.",
        tooltip="Boolean to indicate whether or not to record output to text file.",
        uilabel="Record to Text",
        default=False)

    driving_commod = ts.String(
        doc="Sets the driving commodity for the institution. That is the " +
            "commodity that no_inst will deploy against the demand equation.",
        tooltip="Driving Commodity",
        uilabel="Driving Commodity",
        default="POWER"
    )

    installed_cap = ts.Bool(
        doc="True if facility deployment is governed by installed capacity. " +
        "False if deployment is governed by actual commodity supply",
        tooltip="Boolean to indicate whether or not to use installed" +
                "capacity as supply",
        uilabel="installed cap",
        default=False)

    steps = ts.Int(
        doc="The number of timesteps forward to predict supply and demand",
        tooltip="The number of predicted steps forward",
        uilabel="Timesteps for Prediction",
        default=1
    )

    back_steps = ts.Int(
        doc="This is the number of steps backwards from the current time step" +
        "that will be used to make the prediction. If this is set to '0'" +
        "then the calculation will use all values in the time series.",
        tooltip="",
        uilabel="Back Steps",
        default=5)

    supply_std_dev = ts.Double(
        doc="The standard deviation adjustment for the supple side.",
        tooltip="The standard deviation adjustment for the supple side.",
        uilabel="Supply Std Dev",
        default=0
    )

    buffer_type = ts.MapStringString(
        doc="Indicates whether the buffer is a relative or absolute value," +
        "rel: % value, abs: double value, for each commodity",
        tooltip="Supply buffer as a relative or absolute value for," +
        "each commodity",
        alias=[
            'buffer_type',
            'commod',
            'type'],
        uilabel="Supply Buffer type",
        default={})

    supply_buffer = ts.MapStringDouble(
        doc="Supply buffer size: relative or absolute value ",
        tooltip="Supply buffer Amount.",
        alias=['supply_buffer', 'commod', 'buffer'],
        uilabel="Supply Buffer",
        default={}
    )

    degree = ts.Int(
        doc="The degree of the fitting polynomial.",
        tooltip="The degree of the fitting polynomial, if using calc methods" +
                " poly, fft, holtz-winter and exponential smoothing." +
                " Additionally, degree is used to as the 'period' input to " +
                "the stepwise_seasonal method.",
        uilabel="Degree Polynomial Fit / Period for stepwise_seasonal",
        default=1
    )

    os_time = ts.Int(
        doc="The number of oversupply timesteps before decommission",
        tooltip="",
        uilabel="Oversupply Time Limit",
        default=120
    )

    os_int = ts.Int(
        doc="The number of facilities over capacity " +
            "for a given commodity that is allowed. i.e If this" +
            " value is 1. One facility capacity over demand is considered" +
            " an oversupplied situtation.",
        tooltip="",
        uilabel="Oversupply Fac Limit",
        default=1
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.commodity_supply = {}
        self.commodity_demand = {}
        self.installed_capacity = {}
        self.fac_commod = {}
        self.commod_os = {}
        self.fresh = True
        CALC_METHODS['ma'] = no.predict_ma
        CALC_METHODS['arma'] = no.predict_arma
        CALC_METHODS['arch'] = no.predict_arch
        CALC_METHODS['poly'] = do.polyfit_regression
        CALC_METHODS['exp_smoothing'] = do.exp_smoothing
        CALC_METHODS['holt_winters'] = do.holt_winters
        CALC_METHODS['fft'] = do.fft
        CALC_METHODS['sw_seasonal'] = ml.stepwise_seasonal

    def print_variables(self):
        print('commodities: %s' % self.commodity_dict)
        print('demand_eq: %s' % self.demand_eq)
        print('calc_method: %s' % self.calc_method)
        print('record: %s' % str(self.record))
        print('steps: %i' % self.steps)
        print('back_steps: %i' % self.back_steps)
        print('supply_std_dev: %f' % self.supply_std_dev)

    def enter_notify(self):
        super().enter_notify()
        if self.fresh:
            # convert input into dictionary
            self.commodity_dict = di.build_dict(
                self.facility_commod,
                self.facility_capacity,
                self.facility_pref,
                self.facility_constraintcommod,
                self.facility_constraintval,
                self.facility_sharing)
            for commod, proto_dict in self.commodity_dict.items():
                self.commod_os[commod] = 0
                protos = proto_dict.keys()
                for proto in protos:
                    self.fac_commod[proto] = commod
            self.commod_list = list(self.commodity_dict.keys())
            for commod in self.commod_list:
                self.installed_capacity[commod] = defaultdict(float)
                self.installed_capacity[commod][0] = 0.
            for commod, commod_dict in self.commodity_dict.items():
                for proto, proto_dict in commod_dict.items():
                    if proto_dict['constraint_commod'] != '0':
                        self.commod_list.append(
                            proto_dict['constraint_commod'])
            for commod, commod_dict in self.commodity_dict.items():
                tot = 0
                for proto, proto_dict in commod_dict.items():
                    tot += proto_dict['share']
                if tot != 0 and tot != 100:
                    print("Share preferences do not add to 100")
                    raise Exception()
            self.buffer_dict = di.build_buffer_dict(self.supply_buffer,
                                                    self.commod_list)
            self.buffer_type_dict = di.build_buffer_type_dict(
                self.buffer_type, self.commod_list)
            for commod in self.commod_list:
                lib.TIME_SERIES_LISTENERS["supply" +
                                          commod].append(self.extract_supply)
                lib.TIME_SERIES_LISTENERS["demand" +
                                          commod].append(self.extract_demand)
                self.commodity_supply[commod] = defaultdict(float)
                self.commodity_demand[commod] = defaultdict(float)
            self.commod_mins = solver.find_mins(self.commodity_dict)
            for child in self.children:
                if child.prototype not in self.fac_commod:
                    continue
                itscommod = self.fac_commod[child.prototype]
                self.installed_capacity[itscommod][0] += \
                    self.commodity_dict[itscommod][child.prototype]['cap']
            self.fresh = False

    def decision(self):
        """
        This is the tock method for decision the institution. Here the
        institution determines the difference in supply and demand and
        makes the the decision to deploy facilities or not.
        """
        time = self.context.time
        for commod, proto_dict in self.commodity_dict.items():
            diff, supply, demand = self.calc_diff(commod, time)
            lib.record_time_series('calc_supply' + commod, self, supply)
            lib.record_time_series('calc_demand' + commod, self, demand)
            if diff < 0:
                if self.installed_cap:
                    deploy_dict, self.commodity_dict = solver.deploy_solver(
                        self.installed_capacity, self.commodity_dict, commod, diff, time)
                else:
                    deploy_dict, self.commodity_dict = solver.deploy_solver(
                        self.commodity_supply, self.commodity_dict, commod, diff, time)
                for proto, num in deploy_dict.items():
                    for i in range(num):
                        self.context.schedule_build(self, proto)
                # update installed capacity dict
                self.installed_capacity[commod][time + 1] = \
                    self.installed_capacity[commod][time]
                for proto, num in deploy_dict.items():
                    self.installed_capacity[commod][time + 1] += \
                        self.commodity_dict[commod][proto]['cap'] * num
            else:
                self.installed_capacity[commod][time +
                                                1] = self.installed_capacity[commod][time]
            os_limit = self.commod_mins[commod] * self.os_int
            if diff > os_limit:
                self.commod_os[commod] += 1
            else:
                self.commod_os[commod] = 0
            if diff > os_limit and self.commod_os[commod] > self.os_time:
                solver.decommission_oldest(self, self.commodity_dict[commod], diff, commod, time)
            if self.record:
                out_text = "Time " + str(time) + \
                    " Deployed " + str(len(self.children))
                out_text += " supply " + \
                    str(self.commodity_supply[commod][time])
                out_text += " demand " + \
                    str(self.commodity_demand[commod][time]) + "\n"
                with open(commod + ".txt", 'a') as f:
                    f.write(out_text)
        for child in self.children:
            if child.exit_time == time:
                itscommod = self.fac_commod[child.prototype]
                self.installed_capacity[itscommod][time + 1] -= \
                    self.commodity_dict[itscommod][child.prototype]['cap']

    def calc_diff(self, commod, time):
        """
        This function calculates the different in supply and demand for a given facility
        Parameters
        ----------
        time : int
            This is the time step that the difference is being calculated for.
        Returns
        -------
        diff : double
            This is the difference between supply and demand at [time]
        supply : double
            The calculated supply of the supply commodity at [time].
        demand : double
            The calculated demand of the demand commodity at [time]
        """
        if time not in self.commodity_demand[commod]:
            if commod == self.driving_commod:
                t = time
                self.commodity_demand[commod][time] = eval(self.demand_eq)
            else:
                self.commodity_demand[commod][time] = 0.0
        if time not in self.commodity_supply[commod]:
            self.commodity_supply[commod][time] = 0.0
        supply = self.predict_supply(commod)
        if self.buffer_type_dict[commod] == 'rel':
            demand = self.predict_demand(
                commod, time) * (1 + self.buffer_dict[commod])
        elif self.buffer_type_dict[commod] == 'abs':
            demand = self.predict_demand(
                commod, time) + self.buffer_dict[commod]
        else:
            raise Exception(
                'You can only choose rel or abs types for buffer type')
        diff = supply - demand
        return diff, supply, demand

    def predict_supply(self, commod):
        def target(incommod):
            if self.installed_cap:
                return self.installed_capacity[incommod]
            else:
                return self.commodity_supply[incommod]
        if self.calc_method in ['arma', 'ma', 'arch']:
            supply = CALC_METHODS[self.calc_method](target(commod),
                                                    steps=self.steps,
                                                    std_dev=self.supply_std_dev,
                                                    back_steps=self.back_steps)
        elif self.calc_method in ['poly', 'exp_smoothing', 'holt_winters', 'fft']:
            supply = CALC_METHODS[self.calc_method](target(commod),
                                                    back_steps=self.back_steps,
                                                    degree=self.degree,
                                                    steps=self.steps)
        elif self.calc_method in ['sw_seasonal']:
            supply = CALC_METHODS[self.calc_method](
                target(commod), period=self.degree)
        else:
            raise ValueError(
                'The input calc_method is not valid. Check again.')
        return supply

    def predict_demand(self, commod, time):
        if commod == self.driving_commod:
            demand = self.demand_calc(time + 1)
            self.commodity_demand[commod][time + 1] = demand
        else:
            if self.calc_method in ['arma', 'ma', 'arch']:
                demand = CALC_METHODS[self.calc_method](self.commodity_demand[commod],
                                                        steps=self.steps,
                                                        std_dev=self.supply_std_dev,
                                                        back_steps=self.back_steps)
            elif self.calc_method in ['poly', 'exp_smoothing', 'holt_winters', 'fft']:
                demand = CALC_METHODS[self.calc_method](self.commodity_demand[commod],
                                                        back_steps=self.back_steps,
                                                        degree=self.degree,
                                                        steps=self.steps)
            elif self.calc_method in ['sw_seasonal']:
                demand = CALC_METHODS[self.calc_method](
                    self.commodity_demand[commod], period=self.degree)
            else:
                raise ValueError(
                    'The input calc_method is not valid. Check again.')
        return demand

    def extract_supply(self, agent, time, value, commod):
        """
        Gather information on the available supply of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_supply[commod][time] += value
        # update commodities
        # self.commodity_dict[commod] = {agent.prototype: value}

    def extract_demand(self, agent, time, value, commod):
        """
        Gather information on the demand of a commodity over the
        lifetime of the simulation.
        Parameters
        ----------
        agent : cyclus agent
            This is the agent that is making the call to the listener.
        time : int
            Timestep that the call is made.
        value : object
            This is the value of the object being recorded in the time
            series.
        """
        commod = commod[6:]
        self.commodity_demand[commod][time] += value

    def demand_calc(self, time):
        """
        Calculate the electrical demand at a given timestep (time).
        Parameters
        ----------
        time : int
            The timestep that the demand will be calculated at.
        Returns
        -------
        demand : The calculated demand at a given timestep.
        """
        t = time
        demand = eval(self.demand_eq)
        return demand