Example #1
0
    def dissolve_oil(self, data, substance, **kwargs):
        '''
            Here is where we calculate the dissolved oil.
            We will outline the steps as we go along, but off the top of
            my head:
            - recalculate the partition coefficient (K_ow)
              TODO: This requires a molar average of the aromatic components.
            - use VDROP to calculate the shift in the droplet distribution
            - for each droplet size category:
                - calculate the water phase transfer velocity (k_w) (Stokes)
                - calculate the mass xfer rate coefficient (beta)
                - calculate the water column time fraction (f_wc)
                - calculate the volume dissolved
            - subtract the mass of smallest droplets in our distribution
              that are below a threshold.
        '''
        fmass = data['mass_components']

        arom_mask = substance._sara['type'] == 'Aromatics'
        mol_wt = substance.molecular_weight
        rho = substance.component_density

        assert mol_wt.shape == rho.shape

        # calculate the partition coefficient (K_ow) for all aromatics.
        # K_ow for non-aromatics should be masked to 0.0
        K_ow_comp = arom_mask * LeeHuibers.partition_coeff(mol_wt, rho)

        for idx, m in enumerate(fmass):
            K_ow = (np.sum(m * K_ow_comp / mol_wt) /
                    np.sum(m / mol_wt))

            data['partition_coeff'][idx] = K_ow

        diss = np.zeros((len(data['mass'])), dtype=np.float64)
        return diss
Example #2
0
def test_lee_huibers():
    assert np.isclose(LeeHuibers.partition_coeff(92.1, 866.0), 1000)
def test_lee_huibers():
    assert np.isclose(LeeHuibers.partition_coeff(92.1, 866.0), 1000)
Example #4
0
    def dissolve_oil(self, data, substance, **kwargs):
        '''
            Here is where we calculate the dissolved oil.
            We will outline the steps as we go along, but off the top of
            my head:
            - recalculate the partition coefficient (K_ow)
            - droplet distribution per LE should be calculated by the
              natural dispersion process and saved in the data arrays before
              the dissolution weathering process.
            - for each LE:
                (Note: right now the natural dispersion process only
                       calculates a single average droplet size. But we still
                       treat it as an iterable.)
                - for each droplet size category:
                    - calculate the water phase transfer velocity (k_w)
                    - calculate the mass xfer rate coefficient (beta)
                    - calculate the water column time fraction (f_wc)
                    - calculate the mass dissolved during refloat period
                - calculate the mass dissolved from the slick during the
                  calm period.
            - the mass dissolved in the water column and the slick is summed
              per mass fraction (should only be aromatic fractions)
            - the sum of dissolved masses are compared to the existing mass
              fractions and adjusted to make sure we don't dissolve more
              mass than exists in the mass fractions.
        '''
        model_time = kwargs.get('model_time')
        time_step = kwargs.get('time_step')

        fmasses = data['mass_components']
        droplet_avg_sizes = data['droplet_avg_size']
        areas = data['area']

        arom_mask = substance._sara['type'] == 'Aromatics'

        mol_wt = substance.molecular_weight
        rho = substance.component_density

        assert mol_wt.shape == rho.shape

        # calculate the partition coefficient (K_ow) for all aromatics
        # for each LE.
        # K_ow for non-aromatics are masked to 0.0
        K_ow_comp = arom_mask * LeeHuibers.partition_coeff(mol_wt, rho)
        data['partition_coeff'] = ((fmasses * K_ow_comp / mol_wt).sum(axis=1) /
                                   (fmasses / mol_wt).sum(axis=1))

        avg_rhos = self.oil_avg_density(fmasses, rho)
        water_rhos = np.zeros(avg_rhos.shape) + self.waves.water.get('density')

        k_w_i = Stokes.water_phase_xfer_velocity(water_rhos - avg_rhos,
                                                 droplet_avg_sizes)

        total_volumes = self.oil_total_volume(fmasses, rho)
        X_i, S_RA_volumes = self.state_variable(fmasses, rho, arom_mask)

        beta_i = self.beta_coeff(k_w_i, data['partition_coeff'], S_RA_volumes)

        dX_dt_i = beta_i * X_i / (X_i + 1.0) ** (1.0 / 3.0)

        f_wc_i = self.water_column_time_fraction(model_time, k_w_i)
        T_wc_i = f_wc_i * time_step

        T_calm_i = self.calm_between_wave_breaks(model_time, time_step, T_wc_i)

        assert np.alltrue(T_calm_i <= float(time_step))
        assert np.alltrue(T_wc_i <= float(time_step))
        assert np.alltrue(T_wc_i + T_calm_i <= float(time_step))

        aromatic_masses_i = fmasses * arom_mask
        aromatic_fractions_i = (aromatic_masses_i.T /
                                aromatic_masses_i.sum(axis=1)).T

        #
        # OK, here it is, the mass dissolved in the water column.
        #
        mass_dissolved_in_wc = np.nan_to_num((aromatic_fractions_i.T *
                                              dX_dt_i * T_wc_i).T)

        oil_concentrations = self.oil_concentration(fmasses, rho)

        N_s_i = self.slick_subsurface_mass_xfer_rate(model_time,
                                                     oil_concentrations,
                                                     K_ow_comp,
                                                     areas,
                                                     arom_mask)

        #
        # OK, here it is, the mass dissolved in the slick.
        #
        mass_dissolved_in_slick = (N_s_i.T * T_calm_i).T

        mass_dissolved_in_wc = np.vstack(mass_dissolved_in_wc)
        mass_dissolved_in_slick = np.vstack(mass_dissolved_in_slick)
        total_mass_dissolved = mass_dissolved_in_wc + mass_dissolved_in_slick

        # adjust any masses that might go negative
        total_mass_dissolved += np.clip(fmasses - total_mass_dissolved,
                                        -np.inf, 0.0)

        return total_mass_dissolved