Example #1
0
 def test_get_material_position(self):
     vessel = Vessel("test",
                     materials={
                         'C6H14': [material.C6H14, 1, 'mol'],
                         'H2O': [material.H2O, 1, 'mol']
                     })
     vessel.get_material_position("H2O")
Example #2
0
 def test__mix(self):
     vessel = Vessel("test",
                     materials={
                         'Na': [material.Na, 1, 'mol'],
                         'H2O': [material.H2O, 1, 'mol']
                     })
     event = ['mix', 10]
     vessel.push_event_to_queue(feedback=[event], dt=0)
Example #3
0
 def test__update_material_dict(self):
     vessel = Vessel("test")
     material_dict = {
         'H2O': [material.H2O, 100, 'mol'],
         'C6H14': [material.C6H14, 30, 'mol']
     }
     event = ['update material dict', material_dict]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     self.assertIn('H2O', vessel.get_material_dict())
Example #4
0
 def test__update_solute_dict(self):
     vessel = Vessel("test",
                     materials={
                         'Na': [material.Na, 100, 'mol'],
                         'H2O': [material.H2O, 1, 'mol']
                     })
     solute_dict = {'Na': {'H2O': [material.H2O, 100, 'mol']}}
     event = ['update solute dict', solute_dict]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     self.assertIn('Na', vessel.get_solute_dict())
Example #5
0
 def test_save_load(self):
     vessel = Vessel("test",
                     materials={
                         'Na': [material.Na, 1, 'mol'],
                         'H2O': [material.H2O, 1, 'mol']
                     })
     vessel.save_vessel("test")
     new_vessel = Vessel("test")
     new_vessel.load_vessel("test.pickle")
     os.remove("test.pickle")
Example #6
0
 def test__pour_by_volume(self):
     vessel = Vessel("test", materials={"H2O": [material.H2O, 100, 'mol']})
     initial_volume = vessel.get_current_volume()
     event = ['pour by volume', Vessel('test_2'), 0.1]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     final_volume = vessel.get_current_volume()
     self.assertLess(final_volume[1], initial_volume[1])
Example #7
0
 def test_heat_change(self):
     vessel = Vessel("test", materials={'H2O': [material.H2O, 100, 'mol']})
     new_vessel = Vessel("test_2",
                         materials={'H2O': [material.H2O, 100, 'mol']})
     temp = vessel.get_temperature()
     event = ["change_heat", 10, new_vessel]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     self.assertLess(temp, vessel.get_temperature())
Example #8
0
 def create_new_vessel(self):
     """
     This function simple creates a new vessel and adds it to the shelf
     Returns
     -------
     None
     """
     index = self.open_slot
     assert index < self.max_num_vessels
     self.vessels.append(Vessel(label=index))
     self.open_slot += 1
Example #9
0
 def test__drain_by_pixel_less(self):
     vessel = Vessel("test",
                     materials={
                         'C6H14': [material.C6H14, 1, 'mol'],
                         'H2O': [material.H2O, 1, 'mol']
                     })
     initial_volume = vessel.get_current_volume()
     vessel2 = Vessel('test_2')
     event = ['drain by pixel', vessel2, 10]
     vessel.push_event_to_queue(events=[event], dt=1)
     final_volume = vessel.get_current_volume()
     self.assertLess(final_volume[1], initial_volume[1])
Example #10
0
 def __init__(self,
              max_num_vessels: int,
              vessel_paths: [np.array, list] = None):
     """
     initializes the shelf class
     Parameters
     ----------
     max_num_vessels: int: the maximum number of vessels that the shelf can store
     vessel_paths: a list of paths to vessel pickle files that are to be initialized into the shelf
     """
     # the next available slot for inserting a vessel
     self.open_slot = 0
     # maximum number of vessels that can be stored in the shelf
     self.max_num_vessels = max_num_vessels
     # a list that keeps all the vessels
     self.vessels = []
     if vessel_paths:
         for i, path in enumerate(vessel_paths):
             # function to load vessels from the path
             self.vessels[i] = Vessel(label=i)
             self.vessels[i].load_vessel(path)
         self.open_slot = len(vessel_paths)
Example #11
0
    def update_vessel(self, new_vessel: vessel.Vessel):
        """
        Method to initialize a vessel and reset the environment to properly populate the vessel.

        Parameters
        ---------------
        `new_vessel` : `vessel.Vessel`
            The vessel that has been requested to be updated.

        Returns
        ---------------
        None

        Raises
        ---------------
        None
        """

        # set up a new, empty n array intended to contain the vessel materials
        new_n = np.zeros(self.reaction.nmax.shape[0], dtype=np.float32)

        # acquire the appropriate material dictionary from the inputted vessel
        mat_dict = util.convert_material_dict_units(
            new_vessel.get_material_dict())

        # iterate through the material dictionary populating the n array
        for i, mat in enumerate(self.reaction.materials):
            if mat in mat_dict:
                amount = mat_dict[mat][1]
                new_n[i] = amount

        # set the inputted vessel as the vessels variable
        self.vessels = new_vessel

        # modify the vessel appropriately and reset the reaction environment
        self.vessels = self.reaction.reset(self.vessels)
Example #12
0
    def perform_action(self, action, vessels: vessel.Vessel, t, n_steps,
                       step_num):
        """
        Update the environment with processes defined in `action`.

        Parameters
        ---------------
        `action` : `np.array`
            An array containing elements describing the changes to be made, during the current
            step, to each modifiable thermodynamic variable and reactant used in the reaction.
        `vessels` : `vessel.Vessel`
            A vessel containing initial materials to be used in a series of reactions.
        `n_steps` : `int`
            The number of increments into which the action is split.

        Returns
        ---------------
        `vessels` : `vessel.Vessel`
            A vessel that has been updated to have the proper materials and
            thermodynamic properties.

        Raises
        ---------------
        None
        """

        self.perform_compatibility_check(action=action,
                                         vessels=vessels,
                                         n_steps=n_steps,
                                         step_num=step_num)

        # deconstruct the action
        temperature_change, volume_change, delta_n_array = self.action_deconstruct(
            action=action)

        # deconstruct the vessel: acquire the vessel temperature and volume and create the n array
        temperature, volume = self.vessel_deconstruct(vessels=vessels)
        current_volume = vessels.get_current_volume()[-1]

        # perform the complete action over a series of increments
        if self.solver != 'newton':
            n_steps = 1
        for __ in range(n_steps):
            # split the overall temperature change into increments,
            # ensure it does not exceed the maximal and minimal temperature values
            temperature += temperature_change / n_steps
            temperature = np.min([
                np.max([temperature, vessels.get_Tmin()]),
                vessels.get_Tmax()
            ])

            # split the overall volume change into increments,
            # ensure it does not exceed the maximal and minimal volume values
            volume += volume_change / n_steps
            volume = np.min([
                np.max([volume, vessels.get_min_volume()]),
                vessels.get_max_volume()
            ])

            # split the overall molar changes into increments
            for j, delta_n in enumerate(delta_n_array):
                dn = delta_n / n_steps
                self.n[j] += dn
                self.cur_in_hand[j] -= dn

                # set a penalty for trying to add unavailable material (tentatively set to 0)
                # reward -= 0

                # if the amount that is in hand is below a certain threshold set it to 0
                if self.cur_in_hand[j] < self.threshold:
                    self.cur_in_hand[j] = 0.0

            # perform the reaction and update the molar concentrations of the reactants and products
            self.update(self.n / current_volume, temperature, current_volume,
                        t, vessels.get_defaultdt(), n_steps)

        # create a new reaction vessel containing the final materials
        vessels = self.update_vessel(temperature, volume)

        return vessels
Example #13
0
    def plot_full_render(self, first_render, wave_data_dict, plot_data_state,
                         plot_data_mol, plot_data_concentration, n_steps,
                         vessels: vessel.Vessel, step_num):
        '''
        Method to plot thermodynamic variables and spectral data.
        Plots a significant amount of data for a more in-depth
        understanding of the information portrayed.

        Parameters
        ---------------
        `first_render` : `boolean`
            Indicates whether a plot has been already rendered
        `wave_data_dict` : `dict`
            A dictionary containing all the wave data
        `plot_data_state` : `list`
            A list containing the states to be plotted such as time,
            temperature, volume, pressure, and reactant amounts
        `plot_data_mol` : `list`
            A list containing the molar amounts of reactants and products
        `plot_data_concentration` : `list`
            A list containing the concentration of reactants and products
        `n_steps` : `int`
            The number of increments into which the action is split
        `vessels` : `vessel.Vessel`
            A vessel containing methods to obtain thermodynamic data
        `step_num` : `int`
            The step number the environment is currently on

        Returns
        ---------------
        None

        Raises
        ---------------
        None
        '''

        num_list = [
            plot_data_state[0][0], plot_data_state[1][0],
            plot_data_state[2][0], plot_data_state[3][0]
        ] + self.get_ni_num()

        reactants = []
        for reactant in self.reactants:
            name = reactant.replace("[", "").replace("]", "")
            short_name = name[0:5]
            reactants.append(short_name)

        label_list = ['t', 'T', 'V', 'P'] + reactants

        spectra_len = wave_data_dict["spectra_len"]
        absorb = wave_data_dict["absorb"]
        wave = wave_data_dict["wave"]
        wave_min = wave_data_dict["wave_min"]
        wave_max = wave_data_dict["wave_max"]

        peak = CharacterizationBench().get_spectra_peak(
            vessels, materials=self.materials)
        dash_spectra = CharacterizationBench().get_dash_line_spectra(
            vessels, materials=self.materials)

        # The first render is required to initialize the figure
        if first_render:
            plt.close('all')
            plt.ion()
            self._plot_fig, self._plot_axs = plt.subplots(3,
                                                          3,
                                                          figsize=(24, 12))

            # Time vs. Molar_Amount graph ********************** Index: (0, 0)
            self._plot_lines_amount = np.zeros((self.n.shape[0], 2, 20))
            for i in range(self.n.shape[0]):
                self._plot_lines_amount[i][0][step_num -
                                              1:] = (plot_data_state[0][0])
                self._plot_lines_amount[i][1][step_num -
                                              1:] = (plot_data_mol[i][0])
                self._plot_axs[0, 0].plot(self._plot_lines_amount[i][0],
                                          self._plot_lines_amount[i][1],
                                          label=self.materials[i])
            self._plot_axs[0, 0].set_xlim(
                [0.0, vessels.get_defaultdt() * n_steps])
            self._plot_axs[0, 0].set_ylim([0.0, np.mean(plot_data_mol)])
            self._plot_axs[0, 0].set_xlabel('Time (s)')
            self._plot_axs[0, 0].set_ylabel('Molar Amount (mol)')
            self._plot_axs[0, 0].legend()

            # Time vs. Molar_Concentration graph *************** Index: (0, 1)
            self._plot_lines_concentration = np.zeros((self.n.shape[0], 2, 20))
            total_conc = 0
            for i in range(self.n.shape[0]):
                total_conc += plot_data_concentration[i][0]
            for i in range(self.n.shape[0]):
                self._plot_lines_concentration[i][0][step_num - 1:] = (
                    plot_data_state[0][0])
                self._plot_lines_concentration[i][1][step_num - 1:] = (
                    plot_data_concentration[i][0])
                self._plot_axs[0, 1].plot(self._plot_lines_concentration[i][0],
                                          self._plot_lines_concentration[i][1],
                                          label=self.materials[i])

                self._plot_axs[2, 0].plot(
                    self._plot_lines_concentration[i][0],
                    self._plot_lines_concentration[i][1] / total_conc,
                    label=self.materials[i])

            self._plot_axs[0, 1].set_xlim(
                [0.0, vessels.get_defaultdt() * n_steps])
            self._plot_axs[0,
                           1].set_ylim([0.0,
                                        np.mean(plot_data_concentration)])
            self._plot_axs[0, 1].set_xlabel('Time (s)')
            self._plot_axs[0, 1].set_ylabel('Molar Concentration (mol/L)')
            self._plot_axs[0, 1].legend()

            # Time vs. Temperature + Time vs. Volume graph *************** Index: (0, 2)
            self._plot_lines_temp = np.zeros((1, 2, 20))
            self._plot_lines_temp[0][0][step_num -
                                        1:] = (plot_data_state[0][0])
            self._plot_lines_temp[0][1][step_num -
                                        1:] = (plot_data_state[1][0])
            self._plot_axs[0, 2].plot(self._plot_lines_temp[0][0],
                                      self._plot_lines_temp[0][1],
                                      label='T')
            self._plot_lines_vol = np.zeros((1, 2, 20))
            self._plot_lines_vol[0][0][step_num - 1:] = (plot_data_state[0][0])
            self._plot_lines_vol[0][1][step_num - 1:] = (plot_data_state[2][0])
            self._plot_axs[0, 2].plot(self._plot_lines_vol[0][0],
                                      self._plot_lines_vol[0][1],
                                      label='V')
            self._plot_axs[0, 2].set_xlim(
                [0.0, vessels.get_defaultdt() * n_steps])
            self._plot_axs[0, 2].set_ylim([0, 1.2])
            self._plot_axs[0, 2].set_xlabel('Time (s)')
            self._plot_axs[0, 2].set_ylabel('T and V (map to range [0, 1])')
            self._plot_axs[0, 2].legend()

            # Time vs. Pressure graph *************** Index: (1, 0)
            self._plot_lines_pressure = np.zeros((1, 2, 20))
            self._plot_lines_pressure[0][0][step_num -
                                            1:] = (plot_data_state[0][0])
            self._plot_lines_pressure[0][1][step_num -
                                            1:] = (plot_data_state[3][0])
            self._plot_axs[1, 0].plot(self._plot_lines_pressure[0][0],
                                      self._plot_lines_pressure[0][1],
                                      label='V')
            self._plot_axs[1, 0].set_xlim(
                [0.0, vessels.get_defaultdt() * n_steps])
            self._plot_axs[1, 0].set_ylim([0, vessels.get_pmax()])
            self._plot_axs[1, 0].set_xlabel('Time (s)')
            self._plot_axs[1, 0].set_ylabel('Pressure (kPa)')

            # Solid Spectra graph *************** Index: (1, 1)
            __ = self._plot_axs[1, 1].plot(
                wave,  # wavelength space (ranging from wave_min to wave_max)
                absorb  # absorb spectra
            )[0]

            # dash spectra
            for spectra in dash_spectra:
                self._plot_axs[1, 1].plot(wave, spectra, linestyle='dashed')

            # include the labelling when plotting spectral peaks
            for i in range(len(peak)):
                self._plot_axs[1, 1].scatter(peak[i][0],
                                             peak[i][1],
                                             label=peak[i][2])

            self._plot_axs[1, 1].set_xlim([wave_min, wave_max])
            self._plot_axs[1, 1].set_ylim([0, 1.2])
            self._plot_axs[1, 1].set_xlabel('Wavelength (nm)')
            self._plot_axs[1, 1].set_ylabel('Absorbance')
            self._plot_axs[1, 1].legend()

            # bar chart plotting the time, tempurature, pressure, and amount of each
            # species left in hand *************** Index: (1, 2)
            __ = self._plot_axs[1, 2].bar(range(len(num_list)),
                                          num_list,
                                          tick_label=label_list)[0]
            self._plot_axs[1, 2].set_ylim([0, 1])

            self._plot_axs[2, 0].set_xlim(
                [0.0, vessels.get_defaultdt() * n_steps])
            self._plot_axs[2, 0].set_ylim([0.0, 1.0])
            self._plot_axs[2, 0].set_xlabel('Time (s)')
            self._plot_axs[2, 0].set_ylabel('Purity')
            self._plot_axs[2, 0].legend()

            # draw and show the full graph
            self._plot_fig.canvas.draw()
            plt.show()

        # All other renders serve to update the existing figure with the new current state;
        # it is assumed that the above actions have already been carried out
        else:
            # set data for the Time vs. Molar_Amount graph *************** Index: (0, 0)
            curent_time = plot_data_state[0][-1]

            # update the lines data
            total_conc = 0
            for i in range(self.n.shape[0]):
                total_conc += plot_data_concentration[i][0]
            for i in range(self.n.shape[0]):
                # populate the lines amount array with the updated number of mols
                self._plot_lines_amount[i][0][step_num -
                                              1:] = (plot_data_state[0][0])
                self._plot_lines_amount[i][1][step_num -
                                              1:] = (plot_data_mol[i][0])
                self._plot_axs[0, 0].lines[i].set_xdata(
                    self._plot_lines_amount[i][0])
                self._plot_axs[0, 0].lines[i].set_ydata(
                    self._plot_lines_amount[i][1])

                # populate the lines concentration array with the updated number of concentration
                self._plot_lines_concentration[i][0][step_num - 1:] = (
                    plot_data_state[0][0])
                self._plot_lines_concentration[i][1][step_num - 1:] = (
                    plot_data_concentration[i][0])
                self._plot_axs[0, 1].lines[i].set_xdata(
                    self._plot_lines_concentration[i][0])
                self._plot_axs[0, 1].lines[i].set_ydata(
                    self._plot_lines_concentration[i][1])

                self._plot_axs[2, 0].lines[i].set_xdata(
                    self._plot_lines_concentration[i][0])
                self._plot_axs[2, 0].lines[i].set_ydata(
                    self._plot_lines_concentration[i][1] / total_conc)

            # reset each plot's x-limit because the latest action occurred at a greater time-value
            self._plot_axs[0, 0].set_xlim([0.0, curent_time])
            self._plot_axs[0, 1].set_xlim([0.0, curent_time])

            # reset each plot's y-limit in order to fit and show all materials on the graph
            self._plot_axs[0, 0].set_ylim([0.0, np.mean(plot_data_mol)])
            self._plot_axs[0,
                           1].set_ylim([0.0,
                                        np.mean(plot_data_concentration)])

            # set data for Time vs. Temp and Time vs. Volume graphs *************** Index: (0, 2)
            self._plot_lines_temp[0][0][step_num -
                                        1:] = (plot_data_state[0][0])
            self._plot_lines_temp[0][1][step_num -
                                        1:] = (plot_data_state[1][0])
            self._plot_lines_vol[0][0][step_num - 1:] = (plot_data_state[0][0])
            self._plot_lines_vol[0][1][step_num - 1:] = (plot_data_state[2][0])

            self._plot_axs[0,
                           2].lines[0].set_xdata(self._plot_lines_temp[0][0])
            self._plot_axs[0,
                           2].lines[0].set_ydata(self._plot_lines_temp[0][1])
            self._plot_axs[0, 2].lines[1].set_xdata(self._plot_lines_vol[0][0])
            self._plot_axs[0, 2].lines[1].set_ydata(self._plot_lines_vol[0][1])

            # reset xlimit since t extend
            self._plot_axs[0, 2].set_xlim([0.0, curent_time])

            # set data for Time vs. Pressure graph *************** Index: (1, 0)
            self._plot_lines_pressure[0][0][step_num -
                                            1:] = (plot_data_state[0][0])
            self._plot_lines_pressure[0][1][step_num -
                                            1:] = (plot_data_state[3][0])
            self._plot_axs[1, 0].lines[0].set_xdata(
                self._plot_lines_pressure[0][0])
            self._plot_axs[1, 0].lines[0].set_ydata(
                self._plot_lines_pressure[0][1])

            self._plot_axs[1, 0].set_xlim([0.0, curent_time
                                           ])  # reset xlime since t extend
            self._plot_axs[1,
                           0].set_ylim([0.0,
                                        np.max(plot_data_state[3]) * 1.1])

            # reset the Solid Spectra graph
            self._plot_axs[1, 1].cla()
            __ = self._plot_axs[1, 1].plot(
                wave,  # wavelength space (ranging from wave_min to wave_max)
                absorb,  # absorb spectra
            )[0]

            # obtain the new dash spectra data
            for __, item in enumerate(dash_spectra):
                self._plot_axs[1, 1].plot(wave, item, linestyle='dashed')

            # reset the spectra peak labelling
            for i in range(len(peak)):
                self._plot_axs[1, 1].scatter(peak[i][0],
                                             peak[i][1],
                                             label=peak[i][2])

            self._plot_axs[1, 1].set_xlim([wave_min, wave_max])
            self._plot_axs[1, 1].set_ylim([0, 1.2])
            self._plot_axs[1, 1].set_xlabel('Wavelength (nm)')
            self._plot_axs[1, 1].set_ylabel('Absorbance')
            self._plot_axs[1, 1].legend()

            # bar chart
            self._plot_axs[1, 2].cla()
            __ = self._plot_axs[1, 2].bar(
                range(len(num_list)),
                num_list,
                tick_label=label_list,
            )[0]
            self._plot_axs[1, 2].set_ylim([0, 1])

            # re-draw the graph
            self._plot_fig.canvas.draw()
            plt.pause(0.000001)
Example #14
0
 def test_return_vessel_to_shelf(self):
     test_vessel = Vessel('test')
     shelf = Shelf(100)
     shelf.return_vessel_to_shelf(test_vessel)
     self.assertEqual(shelf.open_slot, 1)
     self.assertEqual(len(shelf.vessels), 1)
Example #15
0
 def test_analyze(self):
     char_bench = CharacterizationBench()
     vessel = Vessel("test", materials={'Na': [material.Na, 1, 'mol']})
     analysis = char_bench.analyze(vessel, 'spectra')
     self.assertEqual(len(analysis[0]), 200)
Example #16
0
 def test__update_temperature(self):
     vessel = Vessel("test")
     initial_temp = vessel.get_temperature()
     event = ['temperature change', 400, True]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     self.assertEqual(vessel.get_temperature(), 400)
Example #17
0
 def test_wait(self):
     vessel = Vessel("test", materials={'H2O': [material.H2O, 100, 'mol']})
     new_vessel = Vessel("test_2",
                         materials={'H2O': [material.H2O, 100, 'mol']})
     temp = vessel.get_temperature()
     event = ["change_heat", 10, new_vessel]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     self.assertLess(temp, vessel.get_temperature())
     event = ["wait", temp, new_vessel, True]
     vessel.push_event_to_queue(feedback=[event], dt=0)
     self.assertEqual(temp, vessel.get_temperature())
     event = ["wait", temp + 30, new_vessel, False]
     vessel.push_event_to_queue(feedback=[event], dt=10)
     self.assertLess(temp, vessel.get_temperature())
Example #18
0
    def plotting_step(self, t, tmax, vessels: vessel.Vessel):
        '''
        Set up a method to handle the acquisition of the necessary plotting parameters
        from an input vessel.

        Parameters
        ---------------
        `t` : `float`
            Current amount of time
        `tmax` : `float`
            Maximum time allowed
        `vessels` : `vessel.Vessel`
            A vessel containing methods to acquire the necessary parameters

        Returns
        ---------------
        `plot_data_state` : `list`
            A list containing the states to be plotted such as time,
            temperature, volume, pressure, and reactant amounts
        `plot_data_mol` : `list`
            A list containing the molar amounts of reactants and products
        `plot_data_concentration` : `list`
            A list containing the concentration of reactants and products

        Raises
        ---------------
        None
        '''

        # acquire the necessary parameters from the vessel
        T = vessels.get_temperature()
        V = vessels.get_volume()
        # V = 0.0025

        # create containers to hold the plotting parameters
        plot_data_state = [[], [], [], []]
        plot_data_mol = [[] for _ in range(self.n.shape[0])]
        plot_data_concentration = [[] for _ in range(self.n.shape[0])]

        # Record time data
        plot_data_state[0].append(t / tmax)

        # record temperature data
        Tmin = vessels.get_Tmin()
        Tmax = vessels.get_Tmax()
        plot_data_state[1].append((T - Tmin) / (Tmax - Tmin))

        # record volume data
        Vmin = vessels.get_min_volume()
        Vmax = vessels.get_max_volume()
        plot_data_state[2].append((V - Vmin) / (Vmax - Vmin))

        # record pressure data
        P = vessels.get_pressure()
        plot_data_state[3].append(P / vessels.get_pmax())

        # calculate and record the molar concentrations of the reactants and products
        C = vessels.get_concentration(materials=self.materials)
        for j in range(self.n.shape[0]):
            plot_data_mol[j].append(self.n[j])
            plot_data_concentration[j].append(C[j])

        return plot_data_state, plot_data_mol, plot_data_concentration