예제 #1
0
    def get_mass(self, units=None):

        """
        Return the mass released during the spill.
        User can also specify desired output units in the function.
        If units are not specified, then return in 'SI' units ('kg')
        If volume is given, then use density to find mass. Density is always
        at 15degC, consistent with API definition
        """

        if self.amount is None:
            return self.amount

        # first convert amount to 'kg'
        if self.units in self.valid_mass_units:
            mass = uc.convert('Mass', self.units, 'kg', self.amount)
        elif self.units in self.valid_vol_units:
            water_temp = self.water.get('temperature')
            rho = self.element_type.substance.density_at_temp(water_temp)
            vol = uc.convert('Volume', self.units, 'm^3', self.amount)

            mass = rho * vol
        else:
            raise ValueError("{} is not a valid mass or Volume unit"
                             .format(self.units))

        if units is None or units == 'kg':
            return mass
        else:
            self._check_units(units)
            return uc.convert('Mass', 'kg', units, mass)
예제 #2
0
    def get_mass(self, units=None):
        """
        Return the mass released during the spill.
        User can also specify desired output units in the function.
        If units are not specified, then return in 'SI' units ('kg')
        If volume is given, then use density to find mass. Density is always
        at 15degC, consistent with API definition
        """
        # fixme: This really should be re-factored to always store mass.
        if self.amount is None:
            return self.amount

        if self.units in self.valid_mass_units:
            # first convert amount to 'kg'
            mass = uc.convert('Mass', self.units, 'kg', self.amount)
        elif self.units in self.valid_vol_units:
            # need to convert to mass
                # DO NOT change this back!
                # for the UI to be consistent, the conversion needs to use standard
                #  density -- not the current water temp.
                # water_temp = self.water.get('temperature')
                # ideally substance would have a "standard_density" attribute for this.
            std_rho = self.element_type.standard_density

            vol = uc.convert('Volume', self.units, 'm^3', self.amount)
            mass = std_rho * vol
        else:
            raise ValueError("{} is not a valid mass or Volume unit"
                             .format(self.units))

        if units is None or units == 'kg':
            return mass
        else:
            self._check_units(units)
            return uc.convert('Mass', 'kg', units, mass)
예제 #3
0
    def at(self, points, time, units=None, extrapolate=False, **kwargs):
        '''
        Interpolates this property to the given points at the given time with the units specified
        :param points: A Nx2 array of lon,lat points
        :param time: A datetime object. May be None; if this is so, the variable is assumed to be gridded
        but time-invariant
        :param units: The units that the result would be converted to
        '''
        value = None
        if len(self.time) == 1:
            # single time time series (constant)
            value = np.full((points.shape[0], 1), self.data, dtype=np.float64)
            if units is not None and units != self.units:
                value = unit_conversion.convert(self.units, units, value)
            return value

        if not extrapolate:
            self.time.valid_time(time)
        t_index = self.time.index_of(time, extrapolate)
        if time > self.time.max_time:
            value = self.data[-1]
        if time <= self.time.min_time:
            value = self.data[0]
        if value is None:
            t_alphas = self.time.interp_alpha(time, extrapolate)

            d0 = self.data[t_index - 1]
            d1 = self.data[t_index]
            value = d0 + (d1 - d0) * t_alphas
        if units is not None and units != self.units:
            value = unit_conversion.convert(self.units, units, value)

        return np.full((points.shape[0], 1), value, dtype=np.float64)
예제 #4
0
    def _init_rate_duration(self, avg_frac_oil=1):
        '''
        burn duration based on avg_frac_oil content for LEs marked for burn
        __init__ invokes this to initialize all parameters assuming
        frac_water = 0.0
        '''
        # burn rate constant is defined as a thickness rate in m/sec
        _si_area = uc.convert('Area', self.area_units, 'm^2', self.area)

        # rate if efficiency is 100 %
        self._oilwater_thick_burnrate = self._burn_constant * avg_frac_oil
        self._oil_vol_burnrate = (self._burn_constant *
                                  avg_frac_oil ** 2 *
                                  _si_area)

        # burn duration is known once rate is known
        # reset current thickness to initial thickness whenever model is rerun
        self._oilwater_thickness = uc.convert('Length',
                                              self.thickness_units, 'm',
                                              self.thickness)

        burn_duration = ((self._oilwater_thickness - self._min_thickness) /
                         self._oilwater_thick_burnrate)

        self._active_range = (self.active_range[0],
                              self.active_range[0] +
                              timedelta(seconds=burn_duration))
예제 #5
0
    def at(self, points, time, units=None, extrapolate=False):
        '''
        Interpolates this property to the given points at the given time with the units specified
        :param points: A Nx2 array of lon,lat points
        :param time: A datetime object. May be None; if this is so, the variable is assumed to be gridded
        but time-invariant
        :param units: The units that the result would be converted to
        '''
        value = None
        if len(self.time) == 1:
            # single time time series (constant)
            value = np.full((points.shape[0], 1), self.data)
            value = unit_conversion.convert(self.units, units, value)
            return value

        if not extrapolate:
            self.time.valid_time(time)
        t_index = self.time.index_of(time, extrapolate)
        if time > self.time.max_time:
            value = self.data[-1]
        if time <= self.time.min_time:
            value = self.data[0]
        if value is None:
            t_alphas = self.time.interp_alpha(time, extrapolate)

            d0 = self.data[t_index - 1]
            d1 = self.data[t_index]
            value = d0 + (d1 - d0) * t_alphas
        if units is not None and units != self.units:
            value = unit_conversion.convert(self.units, units, value)

        return np.full((points.shape[0], 1), value)
예제 #6
0
    def _get_mass(self, substance, amount, units):
        '''
        return 'amount' in units of 'kg' for specified substance
        uses the density corresponding with API temperature
        '''
        if units in self.valid_mass_units:
            rm_mass = uc.convert('Mass', units, 'kg', amount)
        else:   # amount must be in volume units
            rm_vol = uc.convert('Volume', units, 'm^3', amount)
            rm_mass = substance.get_density() * rm_vol

        return rm_mass
예제 #7
0
    def _get_mass(self, substance, amount, units):
        '''
        return 'amount' in units of 'kg' for specified substance
        uses the density corresponding with API temperature
        '''
        if units in self.valid_mass_units:
            rm_mass = uc.convert('Mass', units, 'kg', amount)
        else:  # amount must be in volume units
            rm_vol = uc.convert('Volume', units, 'm^3', amount)
            rm_mass = substance.get_density() * rm_vol

        return rm_mass
예제 #8
0
파일: wind.py 프로젝트: simomartini/PyGnome
    def _convert_units(self, data, coord_sys, from_unit, to_unit):
        '''
        method to convert units for the 'value' stored in the
        date/time value pair
        '''
        if from_unit != to_unit:
            data[:, 0] = uc.convert('Velocity', from_unit, to_unit, data[:, 0])

            if coord_sys == coord_systems.uv:
                data[:, 1] = uc.convert('Velocity', from_unit, to_unit,
                                        data[:, 1])

        return data
예제 #9
0
    def _convert_units(self, data, coord_sys, from_unit, to_unit):
        '''
        method to convert units for the 'value' stored in the
        date/time value pair
        '''
        if from_unit != to_unit:
            data[:, 0] = uc.convert('Velocity', from_unit, to_unit, data[:, 0])

            if coord_sys == coord_systems.uv:
                data[:, 1] = uc.convert('Velocity', from_unit, to_unit,
                                        data[:, 1])

        return data
예제 #10
0
    def _convert_units(self, data, ts_format, from_unit, to_unit):
        '''
        method to convert units for the 'value' stored in the
        date/time value pair
        '''
        if from_unit != to_unit:
            data[:, 0] = uc.convert('Velocity', from_unit, to_unit, data[:, 0])

            if ts_format == basic_types.ts_format.uv:
                # TODO: avoid clobbering the 'ts_format' namespace
                data[:, 1] = uc.convert('Velocity', from_unit, to_unit,
                                        data[:, 1])

        return data
예제 #11
0
    def _convert_units(self, data, ts_format, from_unit, to_unit):
        '''
        method to convert units for the 'value' stored in the
        date/time value pair
        '''
        if from_unit != to_unit:
            data[:, 0] = uc.convert('Velocity', from_unit, to_unit, data[:, 0])

            if ts_format == basic_types.ts_format.uv:
                # TODO: avoid clobbering the 'ts_format' namespace
                data[:, 1] = uc.convert('Velocity', from_unit, to_unit,
                                        data[:, 1])

        return data
예제 #12
0
def test_new_api_oneshot():
    """
    just to make sure basic API works!

    and these are a few that have caused problems...
    """

    assert isclose(unit_conversion.convert('meter', 'foot', 1), 3.28083989501)

    assert isclose(unit_conversion.convert('API', 'SG', 10), 1)

    assert isclose(unit_conversion.convert('meter second-1', 'knot', 1),
                   1.94384)

    assert isclose(unit_conversion.convert('m/s', 'knot', 1), 1.94384)
예제 #13
0
def test_new_api_oneshot():
    """
    just to make sure basic API works!

    and these are a few that have caused problems...
    """

    assert isclose(unit_conversion.convert('meter', 'foot', 1), 3.28083989501)

    assert isclose(unit_conversion.convert('API', 'SG', 10), 1)

    assert isclose(unit_conversion.convert('meter second-1', 'knot', 1),
                   1.94384)

    assert isclose(unit_conversion.convert('m/s', 'knot', 1), 1.94384)
예제 #14
0
    def at_temp(self, temp, unit='K'):
        """
        density(s) at the provided temperature(s)

        :param temp: scalar or sequence of temp in K

        :param unit='K': unit of temperature

        densities will be returned as kg/m^3
        """
        temp = np.asarray(temp)
        scaler = True if temp.shape == () else False
        temp.shape = (-1, )

        if unit != 'K':
            temp = uc.convert(unit, 'K', temp)

        densities = np.interp(temp,
                              self.temps,
                              self.densities,
                              left=-np.inf,
                              right=np.inf)

        left = (densities == -np.inf)
        densities[left] = self.densities[0] + (self.k_rho_default *
                                               (temp[left] - self.temps[0]))

        right = (densities == np.inf)
        densities[right] = self.densities[-1] + (
            self.k_rho_default * (temp[right] - self.temps[-1]))

        return densities if not scaler else densities[0]
예제 #15
0
    def _get_mass(self, substance, amount, units):
        """
        return 'amount' in units of 'kg' for specified substance
        uses the density corresponding with API temperature
        """
        if units in self.valid_mass_units:
            rm_mass = uc.convert("Mass", units, "kg", amount)
        else:
            # amount must be in volume units
            water_temp = self.water.get("temperature")
            rho = substance.density_at_temp(water_temp)
            rm_vol = uc.convert("Volume", units, "m^3", amount)

            rm_mass = rho * rm_vol

        return rm_mass
예제 #16
0
def sample_oil_to_mock_oil(max_cuts=None, **kwargs):
    '''
    make an Oil object from _sample_oils
    Currently, this has only been tested on sample oils, but should be made
    more general. Assume the kwargs are attributes of Oil object

    This adds following attributes:
    'densities' list containing only one density
    'cuts' list containing equal mass in saturates/aromatics for max cuts
    'resins' and 'asphaltene_content' to None
    '''
    if max_cuts is None:
        max_cuts = 5

    oil = Oil(**kwargs)

    # need to add densities list
    oil.densities = [Density(kg_m_3=uc.convert('density', 'api', 'kg/m^3',
                                               oil.api),
                             ref_temp_k=288.15)]

    if 'kvis' in kwargs:
        for k in kwargs['kvis']:
            oil.kvis.append(KVis(**k))

    add_resin_fractions(None, oil)
    add_asphaltene_fractions(None, oil)

    # add cuts - all mass goes into saturates/aromatics for now
    mass_left = 1.0
    mass_left -= sum([f.fraction for f in oil.sara_fractions
                      if f.sara_type in ('Resins', 'Asphaltenes')])

    oil.cuts = []
    prev_mass_frac = 0.0

    summed_boiling_points = []
    for t, f in get_boiling_points_from_api(max_cuts, mass_left, oil.api):
        added_to_sums = False

        for idx, [ut, summed_value] in enumerate(summed_boiling_points):
            if np.isclose(t, ut):
                summed_boiling_points[idx][1] += f
                added_to_sums = True
                break

        if added_to_sums is False:
            summed_boiling_points.append([t, f])

    for t_i, fraction in summed_boiling_points:
        oil.cuts.append(Cut(fraction=prev_mass_frac + fraction,
                            vapor_temp_k=t_i))
        prev_mass_frac += fraction

    add_molecular_weights(None, oil)
    add_saturate_aromatic_fractions(None, oil)
    add_component_densities(None, oil)
    adjust_resin_asphaltene_fractions(None, oil)

    return oil
예제 #17
0
 def test_prepare_for_model_run(self):
     ''' check _oilwater_thickness, _burn_duration is reset'''
     self.burn._oilwater_thickness = 0.002   # reached terminal thickness
     self.burn.prepare_for_model_run(self.sc)
     assert (self.burn._oilwater_thickness ==
             uc.convert('Length', self.burn.thickness_units, 'm',
                        self.burn.thickness))
예제 #18
0
    def convert_to(self, new_unit):
        """
        Convert this Measurement object to the specified new unit

        The object is mutated in place.

        If the conversion can not be performed, an Exception will
        be raised, and the object not altered.

        This will also return the object (self) -- but that is a
        deprecated feature -- do not use it!

        If you want a new object, use `converted_to` instead
        """

        new_vals = {
            att: None
            for att in ('value', 'min_value', 'max_value',
                        'standard_deviation')
        }

        for attr in new_vals.keys():
            val = getattr(self, attr)

            if val is not None:
                new_val = convert(self.unit_type, self.unit, new_unit, val)
                new_vals[attr] = new_val

        # if this was all successful
        new_vals['unit'] = new_unit

        self.__dict__.update(new_vals)

        return None
예제 #19
0
    def get(self, attr, unit=None):
        '''
        return value in desired unit. If None, then return the value in SI
        units. The user_unit are given in 'units' attribute and each attribute
        carries the value in as given in these user_units.
        '''
        val = getattr(self, attr)

        if unit is None:
            # Note: salinity only have one units since we don't
            # have any conversions for them in unit_conversion yet - revisit
            # this per requirements
            if (attr not in self._si_units
                    or self._si_units[attr] == self._units[attr]):
                return val
            else:
                unit = self._si_units[attr]

        if unit in self._units_type[attr][1]:
            return uc.convert(self._units_type[attr][0], self.units[attr],
                              unit, val)
        else:
            # log to file if we have logger
            ex = uc.InvalidUnitError((unit, self._units_type[attr][0]))
            self.logger.error(str(ex))
            raise ex
예제 #20
0
def show_uncategorized_oils(session):
    oils = (session.query(Oil)
            .filter(Oil.categories == None)
            .all())

    fd = open('temp.txt', 'w')
    fd.write('adios_oil_id\t'
             'product_type\t'
             'api\t'
             'viscosity\t'
             'pour_point\t'
             'name\n')

    logger.info('{0} oils uncategorized.'.format(len(oils)))

    for o in oils:
        o_estim = OilWithEstimation(o)
        if o.api >= 0:
            if o.api < 15:
                category_temp = 273.15 + 50
            else:
                category_temp = 273.15 + 38

            viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                                   o_estim.kvis_at_temp(category_temp))
        else:
            viscosity = None

        fd.write('{0.imported.adios_oil_id}\t'
                 '{0.imported.product_type}\t'
                 '{0.api}\t'
                 '{1}\t'
                 '({0.pour_point_min_k}, {0.pour_point_max_k})\t'
                 '{0.name}\n'
                 .format(o, viscosity))
예제 #21
0
def link_refined_fuel_oil_6(session):
    '''
       Category Name:
       - Fuel Oil #6/Bunker/Heavy Fuel Oil/Group V
       Sample Oils:
       - Bunker C
       - Residual Oil
       Density Criteria:
       - API < 15
       Kinematic Viscosity Criteria:
       - 200.0 <= v cSt @ 50 degrees Celcius
    '''
    top, categories = get_categories_by_names(session, 'Refined',
                                              ('Fuel Oil 6 (HFO)',
                                               'Bunker',
                                               'Heavy Fuel Oil',
                                               'Group V'))

    oils = get_oils_by_api(session, 'Refined',
                           api_min=0.0, api_max=15.0)

    count = 0
    category_temp = 273.15 + 50
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity >= 200.0:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'
                .format(count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #22
0
    def get(self, attr, unit=None):
        '''
        return value in desired unit. If None, then return the value in SI
        units. The user_unit are given in 'units' attribute and each attribute
        carries the value in as given in these user_units.
        '''
        val = getattr(self, attr)

        if unit is None:
            # Note: salinity only have one units since we don't
            # have any conversions for them in unit_conversion yet - revisit
            # this per requirements
            if (attr not in self._si_units or
                    self._si_units[attr] == self._units[attr]):
                return val
            else:
                unit = self._si_units[attr]

        if unit in self._units_type[attr][1]:
            return uc.convert(self._units_type[attr][0], self.units[attr],
                              unit, val)
        else:
            # log to file if we have logger
            ex = uc.InvalidUnitError((unit, self._units_type[attr][0]))
            self.logger.error(str(ex))
            raise ex
예제 #23
0
def link_refined_fuel_oil_2(session):
    '''
       Category Name:
       - Fuel oil #2/Diesel/Heating Oil
       Sample Oils:
       - Diesel
       - Heating Oil
       - No. 2 Distillate
       Density Criteria:
       - 30 <= API < 39
       Kinematic Viscosity Criteria:
       - 2.5 < v <= 4.0 cSt @ 38 degrees Celcius
    '''
    top, categories = get_categories_by_names(session, 'Refined',
                                              ('Fuel Oil 2',
                                               'Diesel',
                                               'Heating Oil'))

    oils = get_oils_by_api(session, 'Refined',
                           api_min=30.0, api_max=39.0)

    count = 0
    category_temp = 273.15 + 38
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity > 2.5 or viscosity <= 4.0:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'
                .format(count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #24
0
def link_refined_ifo(session):
    '''
       Category Name:
       - Intermediate Fuel Oil
       Sample Oils:
       - IFO 180
       - Fuel Oil #4
       - Marine Diesel
       Density Criteria:
       - 15 <= API < 30
       Kinematic Viscosity Criteria:
       - 4.0 < v < 200.0 cSt @ 38 degrees Celcius
    '''
    top, categories = get_categories_by_names(session, 'Refined',
                                              ('Intermediate Fuel Oil',))

    oils = get_oils_by_api(session, 'Refined',
                           api_min=15.0, api_max=30.0)

    count = 0
    category_temp = 273.15 + 38
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity > 4.0 or viscosity < 200.0:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'
                .format(count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #25
0
 def test_prepare_for_model_run(self):
     ''' check _oilwater_thickness, _burn_duration is reset'''
     self.burn._oilwater_thickness = 0.002   # reached terminal thickness
     self.burn.prepare_for_model_run(self.sc)
     assert (self.burn._oilwater_thickness ==
             uc.convert('Length', self.burn.thickness_units, 'm',
                        self.burn.thickness))
예제 #26
0
def show_uncategorized_oils(session):
    oils = (session.query(Oil).filter(Oil.categories == None).all())

    fd = open('temp.txt', 'w')
    fd.write('adios_oil_id\t'
             'product_type\t'
             'api\t'
             'viscosity\t'
             'pour_point\t'
             'name\n')

    logger.info('{0} oils uncategorized.'.format(len(oils)))

    for o in oils:
        o_estim = OilWithEstimation(o)
        if o.api >= 0:
            if o.api < 15:
                category_temp = 273.15 + 50
            else:
                category_temp = 273.15 + 38

            viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                                   o_estim.kvis_at_temp(category_temp))
        else:
            viscosity = None

        fd.write('{0.imported.adios_oil_id}\t'
                 '{0.imported.product_type}\t'
                 '{0.api}\t'
                 '{1}\t'
                 '({0.pour_point_min_k}, {0.pour_point_max_k})\t'
                 '{0.name}\n'.format(o, viscosity))
예제 #27
0
def link_refined_fuel_oil_1(session):
    '''
       Category Name:
       - Fuel oil #1/gasoline/kerosene
       Sample Oils:
       - gasoline
       - kerosene
       - JP-4
       - avgas
       Density Criteria:
       - API >= 35
       Kinematic Viscosity Criteria:
       - v <= 2.5 cSt @ 38 degrees Celcius
    '''
    top, categories = get_categories_by_names(
        session, 'Refined',
        ('Light Products (Fuel Oil 1)', 'Gasoline', 'Kerosene'))

    oils = get_oils_by_api(session, 'Refined', api_min=35.0)

    category_temp = 273.15 + 38

    count = 0
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity <= 2.5:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'.format(
        count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #28
0
    def test_update_active_start(self):
        '''
        active stop should be updated if we update active start or thickness
        '''
        burn = Burn(self.area,
                    self.thick,
                    active_range=(active_start, InfDateTime('inf')),
                    name='test_burn',
                    on=False)   # this is ignored!

        # use burn constant for test - it isn't stored anywhere
        duration = ((uc.convert('Length', burn.thickness_units, 'm',
                                burn.thickness) -
                     burn._min_thickness) /
                    burn._burn_constant)

        assert (burn.active_range[1] ==
                burn.active_range[0] + timedelta(seconds=duration))

        # after changing active start, active stop should still match the
        # duration.
        burn.active_range = (burn.active_range[0] + timedelta(days=1),
                             burn.active_range[1])
        assert (burn.active_range[1] ==
                burn.active_range[0] + timedelta(seconds=duration))
예제 #29
0
def test_wind_circ_fixture(wind_circ):
    """
    check timeseries of wind object created in 'wind_circ'
    """
    wm = wind_circ['wind']

    # output is in knots

    gtime_val = wm.get_wind_data(coord_sys='uv').view(dtype=np.recarray)
    assert np.all(gtime_val.time == wind_circ['uv'].time)
    assert np.allclose(gtime_val.value,
                       wind_circ['uv'].value,
                       rtol=rtol,
                       atol=atol)

    # output is in meter per second

    gtime_val = (wm.get_wind_data(
        coord_sys='uv', units='meter per second').view(dtype=np.recarray))
    expected = unit_conversion.convert('Velocity', wm.units,
                                       'meter per second',
                                       wind_circ['uv'].value)

    assert np.all(gtime_val.time == wind_circ['uv'].time)
    assert np.allclose(gtime_val.value, expected, rtol=rtol, atol=atol)
예제 #30
0
def link_refined_fuel_oil_6(session):
    '''
       Category Name:
       - Fuel Oil #6/Bunker/Heavy Fuel Oil/Group V
       Sample Oils:
       - Bunker C
       - Residual Oil
       Density Criteria:
       - API < 15
       Kinematic Viscosity Criteria:
       - 200.0 <= v cSt @ 50 degrees Celcius
    '''
    top, categories = get_categories_by_names(
        session, 'Refined',
        ('Fuel Oil 6 (HFO)', 'Bunker', 'Heavy Fuel Oil', 'Group V'))

    oils = get_oils_by_api(session, 'Refined', api_min=0.0, api_max=15.0)

    count = 0
    category_temp = 273.15 + 50
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity >= 200.0:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'.format(
        count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #31
0
def link_refined_ifo(session):
    '''
       Category Name:
       - Intermediate Fuel Oil
       Sample Oils:
       - IFO 180
       - Fuel Oil #4
       - Marine Diesel
       Density Criteria:
       - 15 <= API < 30
       Kinematic Viscosity Criteria:
       - 4.0 < v < 200.0 cSt @ 38 degrees Celcius
    '''
    top, categories = get_categories_by_names(session, 'Refined',
                                              ('Intermediate Fuel Oil', ))

    oils = get_oils_by_api(session, 'Refined', api_min=15.0, api_max=30.0)

    count = 0
    category_temp = 273.15 + 38
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity > 4.0 or viscosity < 200.0:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'.format(
        count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #32
0
def link_refined_fuel_oil_2(session):
    '''
       Category Name:
       - Fuel oil #2/Diesel/Heating Oil
       Sample Oils:
       - Diesel
       - Heating Oil
       - No. 2 Distillate
       Density Criteria:
       - 30 <= API < 39
       Kinematic Viscosity Criteria:
       - 2.5 < v <= 4.0 cSt @ 38 degrees Celcius
    '''
    top, categories = get_categories_by_names(
        session, 'Refined', ('Fuel Oil 2', 'Diesel', 'Heating Oil'))

    oils = get_oils_by_api(session, 'Refined', api_min=30.0, api_max=39.0)

    count = 0
    category_temp = 273.15 + 38
    for o in oils:
        o_estim = OilWithEstimation(o)
        viscosity = uc.convert('Kinematic Viscosity', 'm^2/s', 'cSt',
                               o_estim.kvis_at_temp(category_temp))

        if viscosity > 2.5 or viscosity <= 4.0:
            o.categories.extend(categories)
            count += 1

    logger.info('{0} oils added to {1} -> {2}.'.format(
        count, top.name, [n.name for n in categories]))
    transaction.commit()
예제 #33
0
    def Calculate(self, depth, gas_oil_ratio,
                  oil_jet_velocity=None, oil_jet_density=None,
                  source_pressure=None,
                  output_metric=False):
        if oil_jet_velocity and oil_jet_density:
            # N/m^2  or Pa units (Pascals)
            # equavelent to 950 psi
            source_pressure = (oil_jet_density * (oil_jet_velocity ** 2)) / 2
        elif not source_pressure:
            raise ValueError('need either '
                             'oil_jet_velocity and oil_jet_density, '
                             'or source_pressure')

        if self.metric_inputs:
            depth = convert('Length', 'meter', 'foot', depth)
            gas_oil_ratio = Volume.CubicMeterRatioToScfPerStb(gas_oil_ratio)
            source_pressure = Force.PascalsToPsi(source_pressure)

        # Start-Equation 1.5, page 8
        # Calculating ambient pressure outside leak at depth in psi.
        # We will go off the document, but here are some considerations
        # regarding this calculation:
        # - The ambient atmospheric pressure at sea level is not constant.
        #   It varies with the weather, but averages around 100 kPa
        #   One bar is 100kPa or approximately ambient pressure at sea level
        # - One atmosphere(atm) is also approximately the ambient pressure
        #   at sea level and is equal to 14.7 psi or 1.01325 bar
        # - Ambient water pressure increases linearly with depth.
        #   Roughly, each 10 meters (33 ft) of depth adds another bar
        #   to the ambient pressure.  Assuming the density of sea water
        #   to be 1025 kg/m^3 (in fact it is slightly variable),
        #   pressure increases by 1 atm with each 10 m of depth
        ambient_pressure_at_depth = self.ambient_pressure_at_sea_level + (0.446533 * depth);

        # Start-Equation 1.4, page 8
        # The relative pressure, deltaPrel, difference over the leak point is
        relative_pressure_delta = source_pressure / ambient_pressure_at_depth

        # Start- Table 1.3, page 11
        # Maximum released volume fraction, frel
        max_release_fraction, max_release_occurrence = self.release_fraction_lu[relative_pressure_delta]

        # Start-Section 1.3.5
        #
        # Table 1.4 GOR reduction factors, page 11
        gor_reduction_factor = self.gor_reduction_factor_lu.get_gas_oil_reduction_factor(gas_oil_ratio,
                                                                                         max_release_occurrence)

        if output_metric:
            source_pressure = Force.PsiToPascals(source_pressure)
            ambient_pressure_at_depth = Force.PsiToPascals(ambient_pressure_at_depth)
            max_release_occurrence = Volume.ScfPerStbToCubicMeterRatio(max_release_occurrence)

        return self.gor_results(source_pressure,
                                ambient_pressure_at_depth,
                                relative_pressure_delta,
                                max_release_fraction,
                                max_release_occurrence,
                                gor_reduction_factor)
예제 #34
0
    def convert_to_internal_volume(self):
        data = self.timeseries['value']
        from_unit = self.units
        to_unit = 'cubic meter'

        if from_unit != to_unit:
            data[:, 0] = uc.convert('Volume', from_unit, to_unit, data[:, 0])
            self.units = to_unit
예제 #35
0
    def convert_to_internal_volume(self):
        data = self.timeseries['value']
        from_unit = self.units
        to_unit = 'cubic meter'

        if from_unit != to_unit:
            data[:, 0] = uc.convert('Volume', from_unit, to_unit, data[:, 0])
            self.units = to_unit
예제 #36
0
    def get_mass(self, units=None):
        '''
        Return the mass released during the spill.
        User can also specify desired output units in the function.
        If units are not specified, then return in 'SI' units ('kg')
        If volume is given, then use density to find mass. Density is always
        at 15degC, consistent with API definition
        '''
        # first convert amount to 'kg'
        if self.units in self.valid_mass_units:
            mass = uc.convert('Mass', self.units, 'kg', self.amount_released)

        if units is None or units == 'kg':
            return mass
        else:
            self._check_units(units)
            return uc.convert('Mass', 'kg', units, mass)
예제 #37
0
def test_old_api(unit_type, unit1, unit2, value, new_value):
    """
    this is a parameterized test
    of all the known values, with the old API
    """
    # now do the test:
    assert isclose(unit_conversion.convert(unit_type, unit1, unit2, value),
                   new_value)
예제 #38
0
def test_old_api(unit_type, unit1, unit2, value, new_value):
    """
    this is a parameterized test
    of all the known values, with the old API
    """
    # now do the test:
    assert isclose(unit_conversion.convert(unit_type, unit1, unit2, value),
                   new_value)
예제 #39
0
def test_invalid_unit_convert():
    with pytest.raises(ValueError):
        unit_conversion.convert("length", "flintstones", "meters", 1.0)
    with pytest.raises(ValueError):
        unit_conversion.convert("length", "feet", "flintstones", 1.0)

    with pytest.raises(ValueError):
        unit_conversion.convert("temperature", "feet", "C", 1.0)
    with pytest.raises(ValueError):
        unit_conversion.convert("temperature", "f", "feet", 1.0)
예제 #40
0
    def test_weather_elements(self, thick, avg_frac_water, units):
        '''
        weather elements and test. frac_water is 0. Test thickness in units
        other than 'm'.

        1) tests the expected burned mass equals 'burned' amount stored in
           mass_balance
        2) also tests the mass_remaining is consistent with what we expect
        3) tests the mass of LEs set for burn equals the mass of oil given
           avg_frac_water and the thickness, and area. Since we cannot have
           a fraction of an LE, the difference should be within the mass of
           one LE.

        Also sets the 'frac_water' to 0.5 for one of the tests just to ensure
        it works.
        '''
        self.spill.set('num_elements', 500)
        thick_si = uc.convert('Length', units, 'm', thick)
        area = (0.5 * self.volume)/thick_si
        burn = Burn(area, thick, active_start, thickness_units=units,
                    efficiency=1.0)

        # return the initial value of burn._oil_thickness - this is starting
        # thickness of the oil
        self._weather_elements_helper(burn, avg_frac_water)

        # following should finally hold true for entire run
        assert np.allclose(amount, self.sc.mass_balance['burned'] +
                           self.sc['mass'].sum(), atol=1e-6)

        # want mass of oil thickness * area gives volume of oil-water so we
        # need to scale this by (1 - avg_frac_water)
        exp_burned = ((thick_si - burn._min_thickness) * (1 - avg_frac_water) *
                      burn.area * self.op.get_density())
        assert np.isclose(self.sc.mass_balance['burned'], exp_burned)

        mask = self.sc['fate_status'] & fate.burn == fate.burn

        # given LEs are discrete elements, we cannot add a fraction of an LE
        mass_per_le = self.sc['init_mass'][mask][0]
        exp_init_oil_mass = (burn.area * thick_si * (1 - avg_frac_water) *
                             self.op.get_density())
        assert (self.sc['init_mass'][mask].sum() - exp_init_oil_mass <
                mass_per_le and
                self.sc['init_mass'][mask].sum() - exp_init_oil_mass >= 0.0)

        exp_mass_remain = (burn._oilwater_thickness * (1 - avg_frac_water) *
                           burn.area * self.op.get_density())
        mass_remain_for_burn_LEs = self.sc['mass'][mask].sum()
        # since we don't adjust the thickness anymore need to use min_thick
        min_thick = .002
        exp_mass_remain = min_thick * (1 - avg_frac_water) * burn.area * self.op.get_density()
        assert np.allclose(exp_mass_remain, mass_remain_for_burn_LEs)

        duration = (burn.active_stop-burn.active_start).total_seconds()/3600
        print ('Current Thickness: {0:.3f}, '
               'Duration (hrs): {1:.3f}').format(burn._oilwater_thickness,
                                                 duration)
예제 #41
0
def plume(distribution_type='droplet_size',
          distribution='weibull',
          windage_range=(.01, .04),
          windage_persist=900,
          substance_name=None,
          density=None,
          density_units='kg/m^3',
          **kwargs):
    """
    Helper function returns an ElementType object containing 'rise_vel'
    and 'windages'
    initializer with user specified parameters for distribution.

    See below docs for details on the parameters.
    
    NOTE: substance_name or density must be provided 

    :param str distribution_type: default 'droplet_size' available options:

        1. 'droplet_size': Droplet size is samples from the specified
        distribution. Rise velocity is calculated.

        2.'rise_velocity': rise velocity is directly sampled from the specified
        distribution. No droplet size is computed.

    :param distribution='weibull':
    :param windage_range=(.01, .04):
    :param windage_persist=900:
    :param substance_name='oil_conservative':
    :param float density = None:
    :param str density_units='kg/m^3':
    """
    if density is not None:
        # Assume density is at 15 K - convert density to api
        api = uc.convert('density', density_units, 'API', density)
        if substance_name is not None:
            substance = build_oil_props({'name':substance_name, 'api': api}, 2)
        else:
            substance = build_oil_props({'api': api}, 2)
    elif substance_name is not None:
        # model 2 cuts if fake oil
        substance = get_oil_props(substance_name, 2)
    else:
        ex = ValueError()
        ex.message = ("plume substance density and/or name must be provided")
        raise ex
        

    if distribution_type == 'droplet_size':
        return ElementType([InitRiseVelFromDropletSizeFromDist(
                                distribution=distribution, **kwargs),
                            InitWindages(windage_range, windage_persist)],
                           substance)
    elif distribution_type == 'rise_velocity':
        return ElementType([InitRiseVelFromDist(distribution=distribution,
                                                **kwargs),
                            InitWindages(windage_range, windage_persist)],
                           substance)
예제 #42
0
def test_invalid_unit_convert():
    with pytest.raises(unit_conversion.InvalidUnitError):
        unit_conversion.convert("length", "flintstones", "meters", 1.0)
    with pytest.raises(unit_conversion.InvalidUnitError):
        unit_conversion.convert("length", "feet", "flintstones", 1.0)

    with pytest.raises(unit_conversion.InvalidUnitError):
        unit_conversion.convert("temperature", "feet", "C", 1.0)
    with pytest.raises(unit_conversion.InvalidUnitError):
        unit_conversion.convert("temperature", "f", "feet", 1.0)
예제 #43
0
def test_OilProps_sample_oil(oil, density, units):
    """ compare expected values with values stored in OilProps - make sure
    data entered correctly and unit conversion is correct """

    o = get_oil_props(oil)
    d = uc.convert('density', units, 'kg/m^3', density)

    assert o.name == oil
    assert np.isclose(o.density_at_temp(273.15 + 15), d)
예제 #44
0
def test_OilProps_sample_oil(oil, density, units):
    """ compare expected values with values stored in OilProps - make sure
    data entered correctly and unit conversion is correct """

    o = get_oil_props(oil)
    d = uc.convert('density', units, 'kg/m^3', density)

    assert o.name == oil
    assert np.isclose(get_density(o, 273.15 + 15), d)
예제 #45
0
 def _at_2D(self, pts, data, slices=None, **kwargs):
     cur_dim = len(data.shape) - len(slices) if slices is not None else len(data.shape)
     if slices is not None and cur_dim != 2:
         raise ValueError("Data dimensions are incorrect! dimension is {0}".format(len(data.shape) - len(slices)))
     _hash = kwargs['_hash'] if '_hash' in kwargs else None
     units = kwargs['units'] if 'units' in kwargs else None
     value = self.grid.interpolate_var_to_points(pts, data, _hash=_hash[0], slices=slices, _memo=True)
     if units is not None and units != self.units:
         value = unit_conversion.convert(self.units, units, value)
     return value
예제 #46
0
 def _get_density(self, salinity, temp):
     '''
     use lru cache so we don't recompute if temp is not changing
     '''
     temp_c = uc.convert('Temperature', self.units['temperature'], 'C',
                         temp)
     # sea level pressure in decibar - don't expect atmos_pressure to change
     # also expect constants to have SI units
     rho = gsw.rho(salinity, temp_c, constants.atmos_pressure * 0.0001)
     return rho
예제 #47
0
    def find_density_near_15C(self):
        """
        Returns the density (in kg/m3)

        It will interpolate and extrapolate as needed
        """
        try:
            return Density(self.oil).at_temp(uc.convert("C", "K", 15))
        except ValueError:
            return None
예제 #48
0
    def at_temp(self, temp, kvis_units='m^2/s', temp_units="K"):
        """
        Compute the kinematic viscosity of the oil as a function of temperature

        :param temp_k: temperatures to compute at: can be scalar or array
                       of values.  Should be in Kelvin

        viscosity as a function of temp is given by:
        v = A exp(k_v2 / T)

        with constants determined from measured data
        """
        temp = np.asarray(temp)
        temp = uc.convert('temperature', temp_units, 'K', temp)

        kvisc = self._visc_A * np.exp(self._k_v2 / temp)

        kvisc = uc.convert('kinematic viscosity', 'm^2/s', kvis_units, kvisc)
        return kvisc
예제 #49
0
    def test_weather_elements(self, thick, avg_frac_water, units):
        '''
        weather elements and test. frac_water is 0. Test thickness in units
        other than 'm'.

        1) tests the expected burned mass equals 'burned' amount stored in
           mass_balance
        2) also tests the mass_remaining is consistent with what we expect
        3) tests the mass of LEs set for burn equals the mass of oil given
           avg_frac_water and the thickness, and area. Since we cannot have
           a fraction of an LE, the difference should be within the mass of
           one LE.

        Also sets the 'frac_water' to 0.5 for one of the tests just to ensure
        it works.
        '''
        self.spill.set('num_elements', 500)
        thick_si = uc.convert('Length', units, 'm', thick)
        area = (0.5 * self.volume)/thick_si
        burn = Burn(area, thick, active_start, thickness_units=units,
                    efficiency=1.0)

        # return the initial value of burn._oil_thickness - this is starting
        # thickness of the oil
        self._weather_elements_helper(burn, avg_frac_water)

        # following should finally hold true for entire run
        assert np.allclose(amount, self.sc.mass_balance['burned'] +
                           self.sc['mass'].sum(), atol=1e-6)

        # want mass of oil thickness * area gives volume of oil-water so we
        # need to scale this by (1 - avg_frac_water)
        exp_burned = ((thick_si - burn._min_thickness) * (1 - avg_frac_water) *
                      burn.area * self.op.get_density())
        assert np.isclose(self.sc.mass_balance['burned'], exp_burned)

        mask = self.sc['fate_status'] & fate.burn == fate.burn

        # given LEs are discrete elements, we cannot add a fraction of an LE
        mass_per_le = self.sc['init_mass'][mask][0]
        exp_init_oil_mass = (burn.area * thick_si * (1 - avg_frac_water) *
                             self.op.get_density())
        assert (self.sc['init_mass'][mask].sum() - exp_init_oil_mass <
                mass_per_le and
                self.sc['init_mass'][mask].sum() - exp_init_oil_mass >= 0.0)

        exp_mass_remain = (burn._oilwater_thickness * (1 - avg_frac_water) *
                           burn.area * self.op.get_density())
        mass_remain_for_burn_LEs = self.sc['mass'][mask].sum()
        assert np.allclose(exp_mass_remain, mass_remain_for_burn_LEs)

        duration = (burn.active_stop-burn.active_start).total_seconds()/3600
        print ('Current Thickness: {0:.3f}, '
               'Duration (hrs): {1:.3f}').format(burn._oilwater_thickness,
                                                 duration)
예제 #50
0
def test_amount_mass_vol(amount, units):
    '''
    ensure mass is being returned correctly when 'amount' is initialized wtih
    'mass' or 'volume'
    '''
    spill = Spill(Release(datetime.now()),
                  amount=amount,
                  units=units,
                  substance=test_oil)
    assert spill.amount == amount
    assert spill.units == units

    if units in Spill.valid_vol_units:
        exp_mass = (spill.get('substance').get_density() *
                    uc.convert('Volume', units, 'm^3', spill.amount))
    else:
        exp_mass = uc.convert('Mass', units, 'kg', spill.amount)
    assert spill.get_mass() == exp_mass
    exp_mass_g = exp_mass * 1000
    assert spill.get_mass('g') == exp_mass_g
예제 #51
0
def test_new_api(unit_type, unit1, unit2, value, new_value):
    """
    this is a parameterized test
    of all the known values, but with the new API
    """
    # filter out the ones that we know are eliminated
    if unit_conversion.Simplify(unit_type) in ('concentrationinwater',
                                               'oilconcentration'):
        return
    # now do the test:
    assert isclose(unit_conversion.convert(unit1, unit2, value), new_value)
예제 #52
0
def test_new_api(unit_type, unit1, unit2, value, new_value):
    """
    this is a parameterized test
    of all the known values, but with the new API
    """
    # filter out the ones that we know are eliminated
    if unit_conversion.Simplify(unit_type) in ('concentrationinwater',
                                               'oilconcentration'):
        return
    # now do the test:
    assert isclose(unit_conversion.convert(unit1, unit2, value), new_value)
예제 #53
0
    def _get_density(self, salinity, temp):
        '''
        use lru cache so we don't recompute if temp is not changing
        '''
        temp_c = uc.convert('Temperature', self.units['temperature'], 'C',
                            temp)
        # sea level pressure in decibar - don't expect atmos_pressure to change
        # also expect constants to have SI units
        rho = gsw.rho(salinity, temp_c, constants.atmos_pressure * 0.0001)

        return rho
예제 #54
0
def test_amount_mass_vol(amount, units):
    '''
    ensure mass is being returned correctly when 'amount' is initialized wtih
    'mass' or 'volume'
    '''
    spill = Spill(Release(datetime.now()),
                  amount=amount,
                  units=units,
                  substance=test_oil)
    assert spill.amount == amount
    assert spill.units == units

    if units in Spill.valid_vol_units:
        exp_mass = (spill.get('substance').get_density() *
                    uc.convert('Volume', units, 'm^3', spill.amount))
    else:
        exp_mass = uc.convert('Mass', units, 'kg', spill.amount)
    assert spill.get_mass() == exp_mass
    exp_mass_g = exp_mass * 1000
    assert spill.get_mass('g') == exp_mass_g
예제 #55
0
    def check_for_valid_api(self):
        """
        check is the API value is already valid
        """
        API = self.oil.metadata.API

        density_at_15 = self.find_density_near_15C()

        if uc.convert("density", "kg/m^3", "API", density_at_15) == API:
            return True
        else:
            return False
예제 #56
0
    def at(self, points, time, units=None, depth=-1, extrapolate=False):
        '''
        Find the value of the property at positions P at time T

        :param points: Coordinates to be queried (P)
        :param time: The time at which to query these points (T)
        :param depth: Specifies the depth level of the variable
        :param units: units the values will be returned in (or converted to)
        :param extrapolate: if True, extrapolation will be supported
        :type points: Nx2 array of double
        :type time: datetime.datetime object
        :type depth: integer
        :type units: string such as ('m/s', 'knots', etc)
        :type extrapolate: boolean (True or False)
        :return: returns a Nx1 array of interpolated values
        :rtype: double
        '''

        sg = False
        m = True
        if self.time is None:
            # special case! prop has no time variance
            v0 = self.grid.interpolate_var_to_points(points, self.data, slices=None, slice_grid=sg, _memo=m)
            return v0

        t_alphas = s0 = s1 = value = None
        if not extrapolate:
            self.time.valid_time(time)
        t_index = self.time.index_of(time, extrapolate)
        if len(self.time) == 1:
            value = self.grid.interpolate_var_to_points(points, self.data, slices=[0], _memo=m)
        else:
            if time > self.time.max_time:
                value = self.data[-1]
            if time <= self.time.min_time:
                value = self.data[0]
            if extrapolate and t_index == len(self.time.time):
                s0 = [t_index]
                value = self.grid.interpolate_var_to_points(points, self.data, slices=s0, _memo=m)
            else:
                t_alphas = self.time.interp_alpha(time, extrapolate)
                s1 = [t_index]
                s0 = [t_index - 1]
                if len(self.data.shape) == 4:
                    s0.append(depth)
                    s1.append(depth)
                v0 = self.grid.interpolate_var_to_points(points, self.data, slices=s0, slice_grid=sg, _memo=m)
                v1 = self.grid.interpolate_var_to_points(points, self.data, slices=s1, slice_grid=sg, _memo=m)
                value = v0 + (v1 - v0) * t_alphas

        if units is not None and units != self.units:
            value = unit_conversion.convert(self.units, units, value)
        return value
예제 #57
0
    def prepare_for_model_step(self, sc, time_step, model_time):
        '''
        1. set 'active' flag based on active start, and model_time
        2. Mark LEs to be burned - do them in order right now. Assume all LEs
           that are released together will be burned together since they would
           be closer to each other in position.
           Assumes: there is more mass in water than amount of mass to be
           burned. The LEs marked for Burning are marked only once -
           during the very first step that the object becomes active
        '''
        super(Burn, self).prepare_for_model_step(sc, time_step, model_time)
        if not self.active:
            return

        # if initial oilwater_thickness is < _min_thickness, then stop
        # don't want to deal with active start being equal to active stop, need
        # this incase user sets a bad initial value
        if self._oilwater_thickness <= self._min_thickness:
            self._active = False
            return

        # only when it is active, update the status codes
        if (sc['fate_status'] == bt_fate.burn).sum() == 0:
            substance = self._get_substance(sc)

            _si_area = uc.convert('Area', self.area_units, 'm^2', self.area)
            _si_thickness = uc.convert('Length', self.thickness_units, 'm',
                                       self.thickness)

            mass_to_remove = (self.efficiency *
                              self._get_mass(substance,
                                             _si_area * _si_thickness, 'm^3'))

            self._update_LE_status_codes(sc, bt_fate.burn,
                                         substance, mass_to_remove)

            self._set_burn_params(sc, substance)

            # set timestep after active stop is set
            self._set__timestep(time_step, model_time)
예제 #58
0
    def get_density(self, temp=None, out=None):
        '''
        return density at a temperature
        do we want to do any unit conversions here?
        todo: memoize function

        :param temp: temperature in Kelvin. Could be an ndarray, list or scalar
        :type temp: scalar, list, tuple or ndarray - assumes it is in Kelvin
        '''
        if temp:
            return get_density(self._r_oil, temp, out)
        else:
            return uc.convert('density', 'API', 'kg/m^3', self.api)