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
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
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
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
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
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)