Example #1
0
    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
Example #2
0
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
Example #3
0
    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
Example #4
0
    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)
Example #5
0
    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(): {
        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(),
)

event_1 = ['update material dict', material_dict]
event_2 = ['update solute dict', solute_dict]
event_3 = ['fully mix']

extraction_vessel.push_event_to_queue(events=None,
                                      feedback=[event_1, event_2, event_3],
                                      dt=0)


class ExtractWorld_v1(ExtractWorldEnv):
    def __init__(self):
        super(ExtractWorld_v1, self).__init__(
Example #6
0
    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
Example #7
0
    def _drain_by_pixel(
            self,
            parameter,  # [target_vessel, n_pixel]
            dt):
        '''
        Method to drain a vessel gradually by pixel count.
        '''

        # extract the necessary parameters
        target_vessel = parameter[0]
        n_pixel = parameter[1]

        # collect data
        target_material_dict = target_vessel.get_material_dict()
        target_solute_dict = target_vessel.get_solute_dict()
        __, self_total_volume = util.convert_material_dict_to_volume(
            self._material_dict)

        # print the old and new dictionaries to the terminal
        print('-------{}: {} (old_material_dict)-------'.format(
            self.label, self._material_dict))
        print('-------{}: {} (old_solute_dict)-------'.format(
            self.label, self._solute_dict))
        print('-------{}: {} (old_material_dict)-------'.format(
            target_vessel.label, target_material_dict))
        print('-------{}: {} (old_solute_dict)-------'.format(
            target_vessel.label, target_solute_dict))

        # set the default reward to 0
        reward = 0

        # if this vessel is empty or the d_volume is equal to zero, do nothing
        if any([
                math.isclose(self_total_volume, 0.0, rel_tol=1e-6),
                math.isclose(n_pixel, 0.0, rel_tol=1e-6)
        ]):
            __ = target_vessel.push_event_to_queue(events=None,
                                                   feedback=None,
                                                   dt=dt)
            return reward

        # calculate pixels and create a dict to store how many pixels get drained of each color
        color_to_pixel = {
        }  # float as key may not be a good idea! maybe change this later
        (decimal, integer) = math.modf(n_pixel)  # split decimal and integer
        for i in range(int(integer)):
            color = round(self._layers[i].item(),
                          3)  # convert to float and round to 3 decimal
            if color not in color_to_pixel:
                color_to_pixel[color] = 1
            else:
                color_to_pixel[color] += 1
        if decimal > 0:
            color = round(self._layers[int(integer)].item(), 3)
            if color not in color_to_pixel:
                color_to_pixel[color] = decimal
            else:
                color_to_pixel[color] += decimal

        # create a dict to calculate the change of each solute for updating the material dict
        d_solute = {}
        for Solute in self._solute_dict:
            d_solute[Solute] = 0.0

        # M is the solvent that's drained out
        for M in copy.deepcopy(self._material_dict):
            # if the solvent's colour is in color_to_pixel (means it get drained)
            if self._material_dict[M][0]().get_color() in color_to_pixel:
                # calculate the d_mole of this solvent
                pixel_count = color_to_pixel[self._material_dict[M][0]
                                             ().get_color()]
                d_volume = (pixel_count / self.n_pixels) * self.v_max

                # convert volume to amount (mole)
                density = self._material_dict[M][0]().get_density()
                molar_mass = self._material_dict[M][0]().get_molar_mass()
                d_mole = util.convert_volume_to_mole(volume=d_volume,
                                                     density=density,
                                                     molar_mass=molar_mass)

                # if there is some of this solvent left
                if self._material_dict[M][1] - d_mole > 1e-6:
                    # calculate the drained ratio
                    d_percentage = d_mole / self._material_dict[M][1]

                    # update the vessel's material dictionary
                    self._material_dict[M][1] -= d_mole

                    # check if the solvent is in target vessel and update it's material dictionary
                    if M in target_material_dict:
                        target_material_dict[M][1] += d_mole
                    else:
                        target_material_dict[M] = [
                            copy.deepcopy(self._material_dict[M][0]), d_mole
                        ]

                    # update solute_dict for both vessels
                    for Solute in self._solute_dict:
                        if M in self._solute_dict[Solute]:
                            # calculate the amount of moles
                            d_mole = self._solute_dict[Solute][M] * d_percentage

                            # update the material dictionaries
                            self._solute_dict[Solute][M] -= d_mole
                            d_solute[Solute] += d_mole

                            # if all solutes are used up, eliminate the solute dictionary
                            if Solute not in target_solute_dict:
                                target_solute_dict[Solute] = {}

                            # update the target solute dictionary
                            if M in target_solute_dict[Solute]:
                                target_solute_dict[Solute][M] += d_mole
                            else:
                                target_solute_dict[Solute][M] = d_mole

                # if all materials are drained out
                else:
                    # calculate the d_mole of this solvent
                    d_mole = self._material_dict[M][1]

                    # check if it's in target vessel and update the material dictionary
                    if M in target_material_dict:
                        target_material_dict[M][1] += d_mole
                    else:
                        target_material_dict[M] = [
                            copy.deepcopy(self._material_dict[M][0]), d_mole
                        ]

                    self._material_dict.pop(M)
                    self._layers_position_dict.pop(M)

                    # update solute_dict for both vessels
                    for Solute in copy.deepcopy(self._solute_dict):
                        if M in self._solute_dict[Solute]:
                            # calculate the amount to drain
                            d_mole = self._solute_dict[Solute][M]

                            # store the change of solute in d_solute
                            d_solute[Solute] += d_mole

                            # if all solutes are used up, eliminate the solute dictionary
                            if Solute not in target_solute_dict:
                                target_solute_dict[Solute] = {}

                            # update the target solute dictionary
                            if M in target_solute_dict[Solute]:
                                target_solute_dict[Solute][M] += d_mole
                            else:
                                target_solute_dict[Solute][M] = d_mole

                            # pop this solvent from the solute
                            self._solute_dict[Solute].pop(M)

        for Solute in copy.deepcopy(self._solute_dict):
            empty_flag = True

            # pop solute from solute dict if it's empty
            if not self._solute_dict[Solute]:
                self._solute_dict.pop(Solute)
                empty_flag = False
            else:
                for Solvent in self._solute_dict[Solute]:
                    if abs(self._solute_dict[Solute][Solvent] - 0.0) > 1e-6:
                        empty_flag = False

            if empty_flag:
                self._solute_dict.pop(Solute)

        # use d_solute to update material dict for solute
        for M in d_solute:
            # if M still in solute dict, calculate the amount of it drained
            if M in self._solute_dict:
                d_mole = d_solute[M]
                self._material_dict[M][1] -= d_mole

                if M in target_material_dict:
                    target_material_dict[M][1] += d_mole
                else:
                    target_material_dict[M] = [
                        copy.deepcopy(self._material_dict[M][0]), d_mole
                    ]
            # if M no longer in solute dict, which means all of this solute is drained
            else:
                d_mole = d_solute[M]

                if M in target_material_dict:
                    target_material_dict[M][1] += d_mole
                else:
                    target_material_dict[M] = [
                        copy.deepcopy(self._material_dict[M][0]), d_mole
                    ]

                # pop it from material dict since all drained out
                self._material_dict.pop(M)

        # deal with overflow
        v_max = target_vessel.get_max_volume()
        target_material_dict, target_solute_dict, temp_reward = util.check_overflow(
            material_dict=target_material_dict,
            solute_dict=target_solute_dict,
            v_max=v_max)

        reward += temp_reward

        print('-------{}: {} (new_material_dict)-------'.format(
            self.label, self._material_dict))
        print('-------{}: {} (new_solute_dict)-------'.format(
            self.label, self._solute_dict))
        print('-------{}: {} (new_material_dict)-------'.format(
            target_vessel.label, target_material_dict))
        print('-------{}: {} (new_solute_dict)-------'.format(
            target_vessel.label, target_solute_dict))

        # update target vessel's material amount
        event_1 = ['update material dict', target_material_dict]

        # update target vessel's solute dict
        event_2 = ['update solute dict', target_solute_dict]

        # create a event to reset material's position and variance in target vessel
        event_3 = ['fully mix']

        # push event to target vessel
        __ = target_vessel.push_event_to_queue(
            events=None, feedback=[event_1, event_2, event_3], dt=dt)

        return reward
Example #8
0
    def _pour_by_volume(
            self,
            parameter,  # [target_vessel, d_volume]
            dt):
        '''
        Method to pour the contents of the vessel into another vessel.
        '''

        # extract the relevant parameters
        target_vessel = parameter[0]
        d_volume = parameter[1]

        # collect data from the target vessel
        target_material_dict = target_vessel.get_material_dict()
        target_solute_dict = target_vessel.get_solute_dict()
        __, self_total_volume = util.convert_material_dict_to_volume(
            self._material_dict)

        # set the default reward to 0
        reward = 0

        # if this vessel is empty or the d_volume is equal to zero, do nothing
        if any([
                math.isclose(self_total_volume, 0.0, rel_tol=1e-6),
                math.isclose(d_volume, 0.0, rel_tol=1e-6)
        ]):
            __ = target_vessel.push_event_to_queue(events=None,
                                                   feedback=None,
                                                   dt=dt)

            return reward

        # if this vessel has enough volume of material to pour
        if self_total_volume - d_volume > 1e-6:
            # calculate the percentage of amount of materials to be poured
            d_percentage = d_volume / self_total_volume

            for M in copy.deepcopy(self._material_dict):
                # calculate the change of amount(mole) of each material
                d_mole = self._material_dict[M][1] * d_percentage

                # update material dict for this vessel
                self._material_dict[M][1] -= d_mole

                # update material dict for the target vessel, if it's in target vessel
                if M in target_material_dict:
                    target_material_dict[M][1] += d_mole
                # if it's not in target vessel, create it in material dict
                else:
                    target_material_dict[M] = [
                        copy.deepcopy(self._material_dict[M][0]), d_mole
                    ]

            for Solute in copy.deepcopy(self._solute_dict):
                # if solute not in target vessel, create it in solute dict
                if Solute not in target_solute_dict:
                    target_solute_dict[Solute] = {}

                for Solvent in self._solute_dict[Solute]:
                    # calculate the change of amount in each solvent and update the solute dict
                    d_mole = self._solute_dict[Solute][Solvent] * d_percentage
                    self._solute_dict[Solute][Solvent] -= d_mole

                    # check if the solvent is in target material and update the vessel accordingly
                    if Solvent in target_solute_dict[Solute]:
                        target_solute_dict[Solute][Solvent] += d_mole
                    else:
                        target_solute_dict[Solute][Solvent] = d_mole

        # if this vessel has less liquid than calculated amount then everything gets poured out
        else:
            # update material_dict for both vessels
            for M in copy.deepcopy(self._material_dict):
                # pour all of this material
                d_mole = self._material_dict[M][1]

                # check if this material is in the target vessel and update the material dictionary
                if M in target_material_dict:
                    target_material_dict[M][1] += d_mole
                else:
                    target_material_dict[M] = [
                        copy.deepcopy(self._material_dict[M][0]), d_mole
                    ]

                # remove the material from this vessel
                self._material_dict.pop(M)

                # also remove the material from `self._layers_position_dict` if it's in the dict
                if M in self._layers_position_dict:
                    self._layers_position_dict.pop(M)

            # update solute_dict for both vessels
            for solute in copy.deepcopy(self._solute_dict):
                # if solute not in target vessel, create its entry
                if solute not in target_solute_dict:
                    target_solute_dict[solute] = {}

                for solvent in self._solute_dict[solute]:
                    # calculate the change of amount in each solvent
                    d_mole = self._solute_dict[solute][solvent]

                    # check if that solvent is in target material
                    if solvent in target_solute_dict[solute]:
                        target_solute_dict[solute][solvent] += d_mole
                    else:
                        target_solute_dict[solute][solvent] = d_mole

                # remove the solute from the solute dictionary
                self._solute_dict.pop(solute)  # pop the solute

        # deal with overflow
        v_max = target_vessel.get_max_volume()
        target_material_dict, target_solute_dict, temp_reward = util.check_overflow(
            material_dict=target_material_dict,
            solute_dict=target_solute_dict,
            v_max=v_max)

        # update the reward
        reward += temp_reward

        # update target vessel's material amount
        event_1 = ['update material dict', target_material_dict]

        # update target vessel's solute dict
        event_2 = ['update solute dict', target_solute_dict]

        # create a event to reset material's position and variance in target vessel
        event_3 = ['fully mix']

        # push event to target vessel
        __ = target_vessel.push_event_to_queue(
            events=None, feedback=[event_1, event_2, event_3], dt=dt)

        return reward
Example #9
0
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
Example #10
0
    def _pour_by_volume(
        self,
        parameter,  # [target_vessel, d_volume]
        dt,
    ):
        target_vessel = parameter[0]  # get the target vessel
        d_volume = parameter[1]  # must be greater than zero

        # collect data
        target_material_dict = target_vessel.get_material_dict()
        target_solute_dict = target_vessel.get_solute_dict()
        __, self_total_volume = util.convert_material_dict_to_volume(
            self._material_dict)

        reward = -1

        # if this vessel is empty or the d_volume is equal to zero, do nothing
        if math.isclose(self_total_volume, 0.0, rel_tol=1e-6) or math.isclose(
                d_volume, 0.0, rel_tol=1e-6):
            target_vessel.push_event_to_queue(events=None,
                                              feedback=None,
                                              dt=dt)
            return reward

        # if this vessel has enough volume of material to pour
        if self_total_volume - d_volume > 1e-6:
            # update material_dict for both vessels
            d_percentage = d_volume / self_total_volume  # calculate the percentage of amount of materials to be poured
            for M in copy.deepcopy(self._material_dict):
                d_mole = self._material_dict[M][
                    1] * d_percentage  # calculate the change of amount(mole) of each material
                self._material_dict[M][
                    1] -= d_mole  # update material dict for this vessel
                # update material dict for the target vessel
                if M in target_material_dict:  # if it's in target vessel
                    target_material_dict[M][1] += d_mole
                else:  # if it's not in target vessel
                    target_material_dict[M] = [
                        copy.deepcopy(self._material_dict[M][0]), d_mole
                    ]  # create it in material dict

            # update solute_dict for both vessels
            for Solute in copy.deepcopy(self._solute_dict):
                if Solute not in target_solute_dict:  # if solute not in target vessel
                    target_solute_dict[Solute] = {}  # create it in solute dict
                for Solvent in self._solute_dict[Solute]:
                    d_mole = self._solute_dict[Solute][
                        Solvent] * d_percentage  # calculate the change of amount in each solvent
                    self._solute_dict[Solute][Solvent] -= d_mole  # update self
                    if Solvent in target_solute_dict[
                            Solute]:  # check if that solvent is in target material
                        target_solute_dict[Solute][Solvent] += d_mole
                    else:
                        target_solute_dict[Solute][Solvent] = d_mole
        else:  # if this vessel has less liquid than calculated amount then everything gets poured out
            # update material_dict for both vessels
            for M in copy.deepcopy(self._material_dict):
                d_mole = self._material_dict[M][1]  # pour all of this material
                if M in target_material_dict:  # check if this material is in target vessel
                    target_material_dict[M][1] += d_mole
                else:
                    target_material_dict[M] = [
                        copy.deepcopy(self._material_dict[M][0]), d_mole
                    ]
                self._material_dict.pop(M)  # remove it from this vessel
                if M in self._layers_position_dict:  # also remove it from self._layers_position_dict if it's in the dict
                    self._layers_position_dict.pop(M)
            # update solute_dict for both vessels
            for Solute in copy.deepcopy(self._solute_dict):
                if Solute not in target_solute_dict:  # if solute not in target vessel
                    target_solute_dict[Solute] = {}
                for Solvent in self._solute_dict[Solute]:
                    d_mole = self._solute_dict[Solute][
                        Solvent]  # calculate the change of amount in each solvent
                    if Solvent in target_solute_dict[
                            Solute]:  # check if that solvent is in target material
                        target_solute_dict[Solute][Solvent] += d_mole
                    else:
                        target_solute_dict[Solute][Solvent] = d_mole
                self._solute_dict.pop(Solute)  # pop the Solute

        # deal with overflow
        v_max = target_vessel.get_max_volume()  # get v_max from target vessel
        target_material_dict, target_solute_dict, temp_reward = util.check_overflow(
            material_dict=target_material_dict,
            solute_dict=target_solute_dict,
            v_max=v_max,
        )
        reward += temp_reward
        # update target vessel's material amount
        event_1 = ['update material dict', target_material_dict]

        # update target vessel's solute dict
        event_2 = ['update solute dict', target_solute_dict]

        # create a event to reset material's position and variance in target vessel
        event_3 = ['fully mix']

        # push event to target vessel
        target_vessel.push_event_to_queue(events=None,
                                          feedback=[event_1, event_2, event_3],
                                          dt=dt)

        return reward
Example #11
0
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
Example #12
0
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