def reset(self, extraction_vessel): ''' generate empty vessels ''' vessels = [copy.deepcopy(extraction_vessel)] for i in range(self.n_empty_vessels): temp_vessel = vessel.Vessel(label='beaker_{}'.format(i + 1), v_max=self.max_vessel_volume, default_dt=0.05, n_pixels=self.n_vessel_pixels) vessels.append(temp_vessel) # generate oil vessel oil_vessel = vessel.Vessel( label='oil_vessel', v_max=self.oil_volume, n_pixels=self.n_vessel_pixels, settling_switch=False, layer_switch=False, ) oil_vessel_material_dict = {} C6H14 = material.C6H14 oil_vessel_material_dict[C6H14().get_name()] = [C6H14, self.oil_volume] oil_vessel_material_dict, _, _ = util.check_overflow( material_dict=oil_vessel_material_dict, solute_dict={}, v_max=oil_vessel.get_max_volume()) event = ['update material dict', oil_vessel_material_dict] oil_vessel.push_event_to_queue(feedback=[event], dt=0) state = util.generate_state(vessels, max_n_vessel=self.n_total_vessels) return vessels, oil_vessel, state
def wurtz_vessel(): """ Function to generate an input vessel for the oil and water extraction experiment. Parameters --------------- None Returns --------------- `extract_vessel` : `vessel` A vessel object containing state variables, materials, solutes, and spectral data. Raises --------------- None """ # initialize extraction vessel extraction_vessel = vessel.Vessel(label='boil_vessel') # initialize C6H14 C6H14 = material.C6H14() # initialize Dodecane Dodecane = material.Dodecane() Dodecane.set_solute_flag(True) Dodecane.set_color(0.0) Dodecane.set_phase('l') # material_dict material_dict = { C6H14.get_name(): [C6H14, 4.0, 'mol'], Dodecane.get_name(): [Dodecane, 1.0, 'mol'] } # solute_dict solute_dict = { Dodecane.get_name(): { C6H14.get_name(): [C6H14, 1.0, 'mol'] } } material_dict, solute_dict, _ = util.check_overflow( material_dict=material_dict, solute_dict=solute_dict, v_max=extraction_vessel.get_max_volume()) # set events and push them to the queue extraction_vessel.push_event_to_queue( events=None, feedback=[['update material dict', material_dict], ['update solute dict', solute_dict]], dt=0) extraction_vessel.push_event_to_queue(events=None, feedback=None, dt=-100000) return extraction_vessel
def _update_vessel(self): ''' Method to update the information stored in the vessel upon completing a step. Parameters --------------- None Returns --------------- None Raises --------------- None ''' # get the temperature and pressure from the state variables temperature = self.T volume = self.V pressure = self.P # tabulate all the materials used and their new values new_material_dict = {} for i in range(self.reaction.n.shape[0]): material_name = self.reaction.labels[i] material_class = self.reaction.material_classes[i] amount = self.reaction.n[i] new_material_dict[material_name] = [material_class, amount] # tabulate all the solutes and their values new_solute_dict = {} for i in range(self.reaction.initial_solutes.shape[0]): solute_name = self.reaction.solute_labels[i] solute_class = self.reaction.solute_classes[i] amount = self.reaction.initial_solutes[i] # create the new solute dictionary to be appended to a new vessel object new_solute_dict[solute_name] = [solute_class, amount] # create a new vessel and update it with new data new_vessel = vessel.Vessel('react_vessel', temperature=self.Ti, v_max=self.Vmax, v_min=self.Vmin, Tmax=self.Tmax, Tmin=self.Tmin, default_dt=self.dt) new_vessel.temperature = temperature new_vessel._material_dict = new_material_dict new_vessel._solute_dict = new_solute_dict new_vessel.volume = volume new_vessel.pressure = pressure # replace the old vessel with the updated version self.vessels = new_vessel
def __init__(self): super(ExtractWorld_Wurtz_Ctd_v1, self).__init__(extraction='wurtz', extraction_vessel=get_extract_vessel( vessel_path=os.path.join( os.getcwd(), "react_vessel.pickle"), extract_vessel=vessel.Vessel(label='temp')), solvents=["H2O", "DiEthylEther"], target_material='dodecane', out_vessel_path=os.getcwd())
def update_vessel(self, temperature, volume): """ Method to update the provided vessel object with materials from the reaction base and new thermodynamic variables. Parameters --------------- `temperature` : `float` The final temperature of the vessel after all reactions have been completed. `volume` : `float` The final temperature of the vessel after all reactions have been completed. Returns --------------- `new_vessel` : `float` The new vessel containing the final materials and thermodynamic variables. Raises --------------- None """ # tabulate all the materials and solutes used and their new values new_material_dict = {} new_solute_dict = {} for i in range(self.n.shape[0]): material_name = self.materials[i] material_class = self.material_classes[i] amount = self.n[i] new_material_dict[material_name] = [ material_class(), amount, 'mol' ] if material_class().is_solute(): # create the new solute dictionary to be appended to a new vessel object new_solute_dict[material_name] = { material_name: [material_class(), amount, 'mol'] } # create a new vessel and update it with new data new_vessel = vessel.Vessel('react_vessel', temperature=self.Ti, v_max=self.Vmax, v_min=self.Vmin, Tmax=self.Tmax, Tmin=self.Tmin, default_dt=self.dt) new_vessel.temperature = temperature new_vessel.volume = volume new_vessel._material_dict = new_material_dict new_vessel._solute_dict = new_solute_dict new_vessel.pressure = new_vessel.get_pressure() return new_vessel
def reset(self, extraction_vessel): ''' generate empty vessels ''' vessels = [copy.deepcopy(extraction_vessel)] for i in range(self.n_empty_vessels): temp_vessel = vessel.Vessel(label='beaker_{}'.format(i + 1), v_max=self.max_vessel_volume, default_dt=0.05, n_pixels=self.n_vessel_pixels) vessels.append(temp_vessel) # generate oil vessel ethyl_vessel = vessel.Vessel( label='ethyl_vessel', v_max=self.ethyl_volume, n_pixels=self.n_vessel_pixels, settling_switch=False, layer_switch=False, ) ethyl = material.EthylAcetate ethyl_vessel_material_dict = { ethyl().get_name(): [ethyl, self.ethyl_volume] } ethyl_vessel_material_dict, _, _ = util.check_overflow( material_dict=ethyl_vessel_material_dict, solute_dict={}, v_max=ethyl_vessel.get_max_volume()) event = ['update material dict', ethyl_vessel_material_dict] ethyl_vessel.push_event_to_queue(feedback=[event], dt=0) state = util.generate_layers_obs(vessels, max_n_vessel=self.n_total_vessels, n_vessel_pixels=self.n_vessel_pixels) return vessels, ethyl_vessel, state
def _prepare_vessel(self, in_vessel_path=None, materials=[], solvents=[]): """ Method to prepare the initial vessel. Parameters --------------- `in_vessel_path` : `str` (default=`None`) A string indicating the path to a vessel intended to be loaded into the reaction bench environment. `materials` : `list` (default=`None`) A list of dictionaries including initial material names and amounts. `solvents` : `list` (default=`None`) A list of dictionaries including initial solvent names and amounts. Returns --------------- `vessels` : `vessel.Vessel` A vessel object containing materials and solvents to be used in the reaction bench. Raises --------------- None """ # initialize vessels by providing a empty default vessel or loading an existing saved vessel if in_vessel_path is None: # prepare the provided materials into a compatible material dictionary material_dict = self._prepare_materials(materials=materials) # prepare the solutes that have been provided solute_dict = self._prepare_solutes(material_dict=material_dict, solvents=solvents) # add the materials and solutes to an empty vessel vessels = vessel.Vessel('default', materials=material_dict, solutes=solute_dict, default_dt=self.dt) else: with open(in_vessel_path, 'rb') as handle: vessels = pickle.load(handle) return vessels
def reset(self, init_boil_vessel): ''' Method to reset the environment. Parameters --------------- `boil_vessel` : `vessel` (default=`None`) A vessel object containing state variables, materials, solutes, and spectral data. Returns --------------- `vessels` : `list` A list of all the vessel objects that contain materials and solutes. `state` : `np.array` An array containing state variables, material concentrations, and spectral data. Raises --------------- None ''' # delete the solute dictionary from the boil vessel boil_vessel = deepcopy(init_boil_vessel) # set the unit of the boil vessel boil_vessel.unit = 'l' # append wait to boil vessel (needed if using old pickle file) boil_vessel._event_dict['wait'] = vessel.Vessel._wait # add the inputted boil vessel to the list of all vessels vessels = [boil_vessel] # create the empty beaker vessels, set variables to default values for i in range(self.n_empty_vessels): beaker = vessel.Vessel( label="beaker_{}".format(i), temperature=293.15, # room temp in Kelvin v_max=self.max_vessel_volume, default_dt=self.dt, materials={}, solutes={}) vessels.append(beaker) return vessels
def oil_vessel(): ''' Function to generate an input vessel for the oil and water extraction experiment. Parameters --------------- None Returns --------------- `extract_vessel` : `vessel` A vessel object containing state variables, materials, solutes, and spectral data. Raises --------------- None ''' # initialize extraction vessel extraction_vessel = vessel.Vessel(label='extraction_vessel') # initialize H2O H2O = material.H2O # initialize Na Na = material.Na Na().set_charge(1.0) Na().set_solute_flag(True) Na().set_polarity(2.0) # initialize Cl Cl = material.Cl Cl().set_charge(-1.0) Cl().set_solute_flag(True) Cl().set_polarity(2.0) # material_dict material_dict = { H2O().get_name(): [H2O, 30.0], Na().get_name(): [Na, 1.0], Cl().get_name(): [Cl, 1.0] } # solute_dict solute_dict = { Na().get_name(): [H2O().get_name(), 1.0], Cl().get_name(): [H2O().get_name(), 1.0], } material_dict, solute_dict, _ = util.check_overflow( material_dict=material_dict, solute_dict=solute_dict, v_max=extraction_vessel.get_max_volume()) # set events and push them to the queue extraction_vessel.push_event_to_queue( events=None, feedback=[['update material dict', material_dict], ['update solute dict', solute_dict], ['fully mix']], dt=0) return extraction_vessel
def reset(self, extraction_vessel): # generate empty vessels vessels = [copy.deepcopy(extraction_vessel)] for i in range(self.n_empty_vessels): temp_vessel = vessel.Vessel(label='beaker_{}'.format(i + 1), v_max=self.max_vessel_volume, default_dt=0.05, n_pixels=self.n_vessel_pixels) vessels.append(temp_vessel) # generate solution vessel2 solution_1_vessel = vessel.Vessel( label='solution_1_vessel', v_max=self.solution_volume, n_pixels=self.n_vessel_pixels, settling_switch=False, layer_switch=False, ) solution_2_vessel = vessel.Vessel( label='solution_2_vessel', v_max=self.solution_volume, n_pixels=self.n_vessel_pixels, settling_switch=False, layer_switch=False, ) H2O = material.H2O Na = material.Na Cl = material.Cl Li = material.Li F = material.F solution_1_vessel_material_dict = { H2O().get_name(): [H2O, 30.0], Na().get_name(): [Na, 1.0], Cl().get_name(): [Cl, 1.0] } solution_1_solute_dict = { Na().get_name(): { H2O().get_name(): 1.0 }, Cl().get_name(): { H2O().get_name(): 1.0 }, } solution_2_vessel_material_dict = { H2O().get_name(): [H2O, 30.0], Li().get_name(): [Li, 1.0], F().get_name(): [F, 1.0] } solution_2_solute_dict = { Li().get_name(): { H2O().get_name(): 1.0 }, F().get_name(): { H2O().get_name(): 1.0 }, } solution_1_vessel_material_dict, solution_1_solute_dict, _ = util.check_overflow( material_dict=solution_1_vessel_material_dict, solute_dict=solution_1_solute_dict, v_max=solution_1_vessel.get_max_volume(), ) solution_2_vessel_material_dict, solution_2_solute_dict, _ = util.check_overflow( material_dict=solution_2_vessel_material_dict, solute_dict=solution_2_solute_dict, v_max=solution_2_vessel.get_max_volume(), ) event_s1_m = ['update material dict', solution_1_vessel_material_dict] event_s1_s = ['update solute dict', solution_1_solute_dict] event_s2_m = ['update material dict', solution_2_vessel_material_dict] event_s2_s = ['update solute dict', solution_2_solute_dict] solution_1_vessel.push_event_to_queue(feedback=[event_s1_m], dt=0) solution_1_vessel.push_event_to_queue(feedback=[event_s1_s], dt=0) solution_2_vessel.push_event_to_queue(feedback=[event_s2_m], dt=0) solution_2_vessel.push_event_to_queue(feedback=[event_s2_s], dt=0) return vessels, [solution_1_vessel, solution_2_vessel], util.generate_state( vessels, max_n_vessel=self.n_total_vessels)
def boil_vessel(): """ Function to generate an input vessel for distillation. Parameters --------------- None Returns --------------- `extract_vessel` : `vessel` A vessel object containing state variables, materials, solutes, and spectral data. Raises --------------- None """ # initialize boiling vessel boil_vessel = vessel.Vessel(label='boil_vessel') # initialize materials OneChlorohexane = material.OneChlorohexane TwoChlorohexane = material.TwoChlorohexane ThreeChlorohexane = material.ThreeChlorohexane Na = material.Na Dodecane = material.Dodecane FiveMethylundecane = material.FiveMethylundecane FourEthyldecane = material.FourEthyldecane FiveSixDimethyldecane = material.FiveSixDimethyldecane FourEthylFiveMethylnonane = material.FourEthylFiveMethylnonane FourFiveDiethyloctane = material.FourFiveDiethyloctane NaCl = material.NaCl H2O = material.H2O # material_dict material_dict = { OneChlorohexane().get_name(): [OneChlorohexane, 0.62100387, 'mol'], TwoChlorohexane().get_name(): [TwoChlorohexane, 0.71239483, 'mol'], ThreeChlorohexane().get_name(): [ThreeChlorohexane, 0.6086047, 'mol'], Na().get_name(): [Na, 0.028975502, 'mol'], Dodecane().get_name(): [Dodecane, 0.10860507, 'mol'], FiveMethylundecane().get_name(): [FiveMethylundecane, 0.07481375, 'mol'], FourEthyldecane().get_name(): [FourEthyldecane, 0.08697271, 'mol'], FiveSixDimethyldecane().get_name(): [FiveSixDimethyldecane, 0.07173399, 'mol'], FourEthylFiveMethylnonane().get_name(): [FourEthylFiveMethylnonane, 0.069323435, 'mol'], FourFiveDiethyloctane().get_name(): [FourFiveDiethyloctane, 0.07406321, 'mol'], NaCl().get_name(): [NaCl, 0.9710248, 'mol'], H2O().get_name(): [H2O, 0.2767138495698029, 'mol'] } # solute_dict solute_dict = {} material_dict, solute_dict, _ = util.check_overflow( material_dict=material_dict, solute_dict=solute_dict, v_max=boil_vessel.get_max_volume()) # set events and push them to the queue boil_vessel.push_event_to_queue( events=None, feedback=[['update material dict', material_dict], ['update solute dict', solute_dict]], dt=0) return boil_vessel
def __init__(self, reaction=Reaction, in_vessel_path=None, out_vessel_path=None, materials=None, solutes=None, desired="", n_steps=50, dt=0.01, Ti=300.0, Tmin=250.0, Tmax=500.0, dT=50.0, Vi=0.002, Vmin=0.001, Vmax=0.005, dV=0.0005, overlap=False): ''' Constructor class method to pass thermodynamic variables to class methods. Parameters --------------- `reaction` : `class` A reaction class containing various methods that properly define a reaction to be carried out. `in_vessel_path` : `str` (default=`None`) A string indicating the path to a vessel intended to be loaded into this module. `out_vessel_path` : `str` (default=`None`) A string indicating the path to a directory where the final output vessel is saved. `materials` : `list` (default=`None`) A list of dictionaries including initial material names, classes, and amounts. `solutes` : `list` (default=`None`) A list of dictionaries including initial solute names, classes, and amounts. `desired` : `str` (default="") A string indicating the desired output material. `n_steps` : `int` (default=`50`) The number of time steps to be taken during each action. `dt` : `float` (default=`0.01`) The amount of time taken in each time step. `Ti` : `float` (default=`300.0`) The initial temperature of the system in Kelvin. `Tmin` : `float` (default=`250.0`) The minimal temperature of the system in Kelvin. `Tmax` : `float` (default=`500.0`) The maximal temperature of the system in Kelvin. `dT` : `float` (default=`50.0`) The maximal allowed temperature change, in Kelvin, for a single action. `Vi` : `float` (default=`0.002`) The initial volume of the system in litres. `Vmin` : `float` (default=`0.001`) The minimal volume of the system in litres. `Vmax` : `float` (default=`0.005`) The maximal volume of the system in litres. `dV` : `float` (default=`0.0005`) The maximal allowed volume change, in litres, for a single action. `overlap` : `boolean` (default=`False`) Indicates if the spectral plots show overlapping signatures. Returns --------------- None Raises --------------- None ''' # assign an identifier to this bench self.name = "react_bench" # validate the parameters inputted to the reaction bench engine input_parameters = self._validate_parameters( reaction=reaction, in_vessel_path=in_vessel_path, out_vessel_path=out_vessel_path, materials=materials, solutes=solutes, desired=desired, n_steps=n_steps, dt=dt, Ti=Ti, Tmin=Tmin, Tmax=Tmax, dT=dT, Vi=Vi, Vmin=Vmin, Vmax=Vmax, dV=dV, overlap=overlap) # set the input vessel path self.in_vessel_path = input_parameters["in_vessel_path"] # set the output vessel path self.out_vessel_path = input_parameters["out_vessel_path"] # set initial material, solute, and overlap parameters materials = input_parameters["materials"] solutes = input_parameters["solutes"] overlap = input_parameters["overlap"] # set the remaining input parameters self.desired = input_parameters["desired"] # the desired material self.n_steps = input_parameters["n_steps"] # Time steps per action self.dt = input_parameters["dt"] # Time step of reaction (s) self.Ti = input_parameters["Ti"] # Initial temperature (K) self.Tmin = input_parameters[ "Tmin"] # Minimum temperature of the system (K) self.Tmax = input_parameters[ "Tmax"] # Maximum temperature of the system (K) self.dT = input_parameters[ "dT"] # Maximum change in temperature per action (K) self.Vi = input_parameters["Vi"] # Initial Volume (L) self.Vmin = input_parameters[ "Vmin"] # Minimum Volume of the system (L) self.Vmax = input_parameters[ "Vmax"] # Maximum Volume of the system (L) self.dV = input_parameters[ "dV"] # Maximum change in Volume per action (L) # initialize the reaction self.reaction = input_parameters["reaction"](overlap=overlap, materials=materials, solutes=solutes, desired=self.desired) # Maximum time (s) (20 is the registered max_episode_steps) self.tmax = self.n_steps * dt * 20 # initialize a step counter self.step_num = 1 # initialize vessels by providing a empty default vessel or loading an existing saved vessel self.n_init = np.zeros(self.reaction.nmax.shape[0], dtype=np.float32) if self.in_vessel_path is None: self.vessels = vessel.Vessel('default', temperature=self.Ti, v_max=self.Vmax, v_min=self.Vmin, Tmax=self.Tmax, Tmin=self.Tmin, default_dt=self.dt) else: with open(self.in_vessel_path, 'rb') as handle: v = pickle.load(handle) self.vessels = v # set up a state variable self.state = None # reset the inputted reaction before performing any steps self.reaction.reset(n_init=self.n_init) # Defining action and observation space for OpenAI Gym framework # shape[0] is the change in amount of each reactant # + 2 is for the change in T and V # all actions range between 0 () and 1 () # 0 = no reactant added and T, V are decreased by the maximum amount (-dT and -dV) # 1 = all reactant added and T, V are increased by the maximum amount (dT and dV) act_low = np.zeros(self.reaction.initial_in_hand.shape[0] + 2, dtype=np.float32) act_high = np.ones(self.reaction.initial_in_hand.shape[0] + 2, dtype=np.float32) self.action_space = gym.spaces.Box(low=act_low, high=act_high) # this an array denoting spectral signatures (varying # between 0.0 and 1.0) for a wide range of wavelengths absorb = self.reaction.get_spectra(Vi) # Observations have several attributes # + 4 indicates state variables time, temperature, volume, and pressure # initial_in_hand.shape[0] indicates the amount of each reactant # absorb.shape[0] indicates the numerous spectral signatures from get_spectra obs_low = np.zeros(self.reaction.initial_in_hand.shape[0] + 4 + absorb.shape[0], dtype=np.float32) obs_high = np.ones(self.reaction.initial_in_hand.shape[0] + 4 + absorb.shape[0], dtype=np.float32) self.observation_space = gym.spaces.Box(low=obs_low, high=obs_high) # Reset the environment upon calling the class self.reset()
import numpy as np import gym import gym.spaces from chemistrylab.extractworldgym.extractworld_v1_engine import ExtractWorldEnv from chemistrylab.chem_algorithms import material, util, vessel # initialize extraction vessel extraction_vessel = vessel.Vessel(label='extraction_vessel', ) # initialize materials H2O = material.H2O() Na = material.Na() Cl = material.Cl() Na.set_charge(1.0) Na.set_solute_flag(True) Na.set_polarity(2.0) Cl.set_charge(-1.0) Cl.set_solute_flag(True) Cl.set_polarity(2.0) # material_dict material_dict = { H2O.get_name(): [H2O, 30.0], Na.get_name(): [Na, 1.0], Cl.get_name(): [Cl, 1.0] } solute_dict = { Na.get_name(): { H2O.get_name(): 1.0 }, Cl.get_name(): {
def __init__(self, reaction=Reaction, materials=None, solutes=None, desired="", n_steps=50, dt=0.01, Ti=300, Tmin=250, Tmax=500, dT=50, Vi=0.002, Vmin=0.001, Vmax=0.005, dV=0.0005, overlap=False, vessel_path=None): ''' Constructor class method to pass thermodynamic variables to class methods. Parameters --------------- `reaction` : `class` A reaction class containing various methods that properly define a reaction to be carried out. `materials` : `list` (default=`None`) A list of dictionaries including initial material names, classes, and amounts. `solutes` : `list` (default=`None`) A list of dictionaries including initial solute names, classes, and amounts. `desired` : `str` (default="") A string indicating the desired output material. `n_steps` : `int` (default=`50`) The number of time steps to be taken during each action. `dt` : `float` (default=`0.01`) The amount of time taken in each time step. `Ti` : `int` (default=`300`) The initial temperature of the system in Kelvin. `Tmin` : `int` (default=`250`) The minimal temperature of the system in Kelvin. `Tmax` : `int` (default=`500`) The maximal temperature of the system in Kelvin. `dT` : `int` (default=`50`) The maximal allowed temperature change, in Kelvin, for a single action. `Vi` : `float` (default=`0.002`) The initial volume of the system in litres. `Vmin` : `float` (default=`0.001`) The minimal volume of the system in litres. `Vmax` : `float` (default=`0.005`) The maximal volume of the system in litres. `dV` : `float` (default=`0.0005`) The maximal allowed volume change, in litres, for a single action. `overlap` : `boolean` (default=`False`) Indicates if the spectral plots show overlapping signatures. `vessel_path` : `str` (default=`None`) A string indicating the path to a vessel intended to be loaded into this module. Returns --------------- None Raises --------------- None ''' self.name = "experiment_0" self.step_num = 1 self.n_steps = n_steps # Time steps per action self.dt = dt # Time step of reaction (s) self.tmax = n_steps * dt * 20 # Maximum time (s) (20 is the registered max_episode_steps) self.Ti = Ti # Initial temperature (K) self.Tmin = Tmin # Minimum temperature of the system (K) self.Tmax = Tmax # Maximum temperature of the system (K) self.dT = dT # Maximum change in temperature per action (K) self.Vi = Vi # Initial Volume (m**3) self.Vmin = Vmin # Minimum Volume of the system (m**3) self.Vmax = Vmax # Maximum Volume of the system (m**3) self.dV = dV # Maximum change in Volume per action (m**3) # initialize the reaction self.reaction = reaction(overlap=overlap, materials=materials, solutes=solutes, desired=desired) # set the maximum pressure Pmax = self.reaction.max_mol * R * Tmax / Vmin self.Pmax = Pmax # initialize vessels by providing a empty default vessel or loading an existing saved vessel self.n_init = np.zeros(self.reaction.nmax.shape[0], dtype=np.float32) self.vessel_path = vessel_path if vessel_path == None: self.vessels = vessel.Vessel('default', temperature=Ti, p_max=Pmax, v_max=Vmax * 1000, v_min=Vmin * 1000, Tmax=Tmax, Tmin=Tmin, default_dt=dt) else: with open(vessel_path, 'rb') as handle: b = pickle.load(handle) self.vessels = b for i in range(self.n_init.shape[0]): material_name = self.reaction.labels[i] material_class = self.reaction.material_classes[i] self.n_init[i] = self.vessels._material_dict[material_name][1] # reset the inputted reaction before performing any steps self.reaction.reset(n_init=self.n_init) # Defining action and observation space for OpenAI Gym framework # shape[0] is the change in amount of each reactant # + 2 is for the change in T and V # all actions range between 0 () and 1 () # 0 = no reactant added and T, V are decreased by the maximum amount (-dT and -dV) # 1 = all reactant added and T, V are increased by the maximum amount (dT and dV) act_low = np.zeros(self.reaction.initial_in_hand.shape[0] + 2, dtype=np.float32) act_high = np.ones(self.reaction.initial_in_hand.shape[0] + 2, dtype=np.float32) self.action_space = gym.spaces.Box(low=act_low, high=act_high) # this an array denoting spectral signatures (varying # between 0.0 and 1.0) for a wide range of wavelengths absorb = self.reaction.get_spectra(Vi) # Observations have several attributes # + 4 indicates state variables time, temperature, volume, and pressure # initial_in_hand.shape[0] indicates the amount of each reactant # absorb.shape[0] indicates the numerous spectral signatures from get_spectra obs_low = np.zeros(self.reaction.initial_in_hand.shape[0] + 4 + absorb.shape[0], dtype=np.float32) obs_high = np.ones(self.reaction.initial_in_hand.shape[0] + 4 + absorb.shape[0], dtype=np.float32) self.observation_space = gym.spaces.Box(low=obs_low, high=obs_high) # Reset the environment upon calling the class self.reset()
def reset(self, extraction_vessel): ''' Method to reset the environment. Parameters --------------- `extraction_vessel` : `vessel` (default=`None`) A vessel object containing state variables, materials, solutes, and spectral data. Returns --------------- `vessels` : `list` A list of all the vessel objects that contain materials and solutes. `external_vessels` : `list` A list of the external vessels, beakers, to be used in the extraction. `state` : `np.array` An array containing state variables, material concentrations, and spectral data. Raises --------------- None ''' # delete the extraction vessel's solute_dict and copy it into a list of vessels solute_dict = extraction_vessel._solute_dict extraction_vessel._solute_dict = {} vessels = [copy.deepcopy(extraction_vessel)] # create all the necessary beakers and add them to the list for i in range(self.n_empty_vessels): temp_vessel = vessel.Vessel(label='beaker_{}'.format(i + 1), v_max=self.max_vessel_volume, default_dt=0.05, n_pixels=self.n_vessel_pixels) vessels.append(temp_vessel) # generate a list of external vessels to contain solutes external_vessels = [] # generate a vessel to contain the main solute solute_vessel = vessel.Vessel( label='solute_vessel0', v_max=self.solute_volume, n_pixels=self.n_vessel_pixels, settling_switch=False, layer_switch=False, ) # create the material dictionary for the solute vessel solute_material_dict = {} solute_class = convert_to_class(materials=[self.solute])[0] solute_material_dict[self.solute] = [solute_class, self.solute_volume] # check for overflow solute_material_dict, _, _ = util.check_overflow( material_dict=solute_material_dict, solute_dict={}, v_max=solute_vessel.get_max_volume()) # instruct the vessel to update its material dictionary event = ['update material dict', solute_material_dict] solute_vessel.push_event_to_queue(feedback=[event], dt=0) # add the main solute vessel to the list of external vessels external_vessels.append(solute_vessel) # generate vessels for each solute in the extraction vessel for solute_name in solute_dict: # generate an empty vessel to be filled with a single solute solute_vessel = vessel.Vessel(label='solute_vessel{}'.format( len(external_vessels)), v_max=extraction_vessel.v_max, n_pixels=self.n_vessel_pixels, settling_switch=False, layer_switch=False) solute_material_dict = {} solute_material_dict[solute_name] = solute_dict[solute_name] # check for overflow solute_material_dict, _, _ = util.check_overflow( material_dict=solute_material_dict, solute_dict={}, v_max=solute_vessel.get_max_volume()) # instruct the vessel to update its material dictionary event = ['update material dict', solute_material_dict] solute_vessel.push_event_to_queue(feedback=[event], dt=0) # add this solute vessel to the list of external vessels external_vessels.append(solute_vessel) # generate the state state = util.generate_state(vessel_list=vessels, max_n_vessel=self.n_total_vessels) return vessels, external_vessels, state
def reset(self, vessels, initial_in_hand): """ Method to reset the environment and vessel back to its initial state. Empty the initial n array and reset the vessel's thermodynamic properties. Parameters --------------- `vessels` : `vessel.Vessel` A vessel containing initial materials. Returns --------------- `vessels` : `vessel.Vessel` A vessel that has been updated to have the proper thermodynamic properties. Raises --------------- None """ # open the provided vessel to get the material and solute dictionaries material_dict = vessels.get_material_dict() solute_dict = vessels.get_solute_dict() # acquire the amounts of reactant materials for i, material in enumerate(initial_in_hand): material_name = material['Material'] if material_name in self.reactants: self.initial_in_hand[i] = initial_in_hand[i]['Initial'] for i, material_name in enumerate(self.materials): if material_name in material_dict.keys(): self.initial_materials[i] = material_dict[material_name][1] # acquire the amounts of solute materials for i, solute_name in enumerate(solute_dict.keys()): if solute_name in self.solutes: self.initial_solutes[i] = solute_dict[solute_name][1] vessels = vessel.Vessel('react_vessel', materials=material_dict, solutes=solute_dict, temperature=self.Ti, v_max=self.Vmax, v_min=self.Vmin, Tmax=self.Tmax, Tmin=self.Tmin, default_dt=self.dt) # ensure the entire initial materials in hand array is available self.cur_in_hand = 1.0 * self.initial_in_hand # set the n array to contain initial values for i, material_amount in enumerate(self.initial_materials): self.n[i] = material_amount # reset the vessel parameters to their original values as specified in the reaction file vessels.set_v_min(self.Vmin, unit="l") vessels.set_v_max(self.Vmax, unit="l") vessels.set_volume(self.Vi, unit="l", override=True) vessels.temperature = self.Ti vessels.Tmin = self.Tmin vessels.Tmax = self.Tmax vessels.default_dt = self.dt return vessels
def wurtz_vessel(): """ Function to generate an input vessel for the wurtz extraction experiment. Parameters --------------- None Returns --------------- `extract_vessel` : `vessel` A vessel object containing state variables, materials, solutes, and spectral data. Raises --------------- None """ # initialize extraction vessel extraction_vessel = vessel.Vessel(label='extraction_vessel') # initialize DiEthylEther DiEthylEther = material.DiEthylEther() # initialize Na Na = material.Na() Na.set_charge(1.0) Na.set_solute_flag(True) Na.set_color(0.0) Na.set_polarity(2.0) Na.set_phase('l') # initialize Cl Cl = material.Cl() Cl.set_charge(-1.0) Cl.set_solute_flag(True) Cl.set_color(0.0) Cl.set_polarity(2.0) Cl.set_phase('l') # initialize Dodecane Dodecane = material.Dodecane() Dodecane.set_solute_flag(True) Dodecane.set_color(0.0) Dodecane.set_phase('l') # material_dict material_dict = { DiEthylEther.get_name(): [DiEthylEther, 4.0, 'mol'], Na.get_name(): [Na, 1.0, 'mol'], Cl.get_name(): [Cl, 1.0, 'mol'], Dodecane.get_name(): [Dodecane, 1.0, 'mol'] } # solute_dict solute_dict = { Na.get_name(): { DiEthylEther.get_name(): [DiEthylEther, 1.0, 'mol'] }, Cl.get_name(): { DiEthylEther.get_name(): [DiEthylEther, 1.0, 'mol'] }, Dodecane.get_name(): { DiEthylEther.get_name(): [DiEthylEther, 1.0, 'mol'] } } material_dict, solute_dict, _ = util.check_overflow( material_dict=material_dict, solute_dict=solute_dict, v_max=extraction_vessel.get_max_volume()) # set events and push them to the queue extraction_vessel.push_event_to_queue( events=None, feedback=[['update material dict', material_dict], ['update solute dict', solute_dict]], dt=0) extraction_vessel.push_event_to_queue(events=None, feedback=None, dt=-100000) return extraction_vessel