def __init__(self, area, **kwargs): self.area = area super(ConstantArea, self).__init__(**kwargs) self.array_types.update({ 'area': gat('area'), 'fay_area': gat('fay_area') })
def __init__(self, waves=None, **kwargs): if 'arctic' not in kwargs: self.arctic = False # default is a temperate conditions (>6 deg C) else: self.arctic = kwargs.pop('arctic') self.waves = waves super(Biodegradation, self).__init__(**kwargs) self.array_types.update({ 'mass': gat('mass'), 'mass_components': gat('mass_components'), 'droplet_avg_size': gat('droplet_avg_size'), 'positions': gat('positions'), 'yield_factor': gat('yield_factor'), }) # # Original bio degradation formula: # # m(j, t+1) = m(j, t0) * exp(-K(j) * A(t) / M(t)) # # where # m(j, t + 1) - mass of pseudocomponent j at time step t + 1 # K(j) - biodegradation rate constant for pseudocomponent j # A(t) - droplet surface area at time step t # M(t) - droplet mass at time step t # # Since # # A(t) / M(t) = 6 / (d(t) * ro(t)) # # where # d(t) - droplet diameter at time step t # ro(t) - droplet density at time step t # # follows this formula for bio degradation: # # m(j, t+1) = m(j, t0) * exp(-6 * K(j) / (d(t) * ro(t))) # # and then interative bio degradation formula: # # m(j, t+1) = m(j, t) * exp(6 * K(j) * # (1 / (d(t-1) * ro(t-1)) - 1 / (d(t) * ro(t)))) # # where # d(t-1) - droplet diameter at previous (t-1) time step # ro(t-1) - droplet density at previous (t-1) time step # # So we will keep previous time step specific surface value # (squre meter per kilogram) or yield_factor = 1 / (d * ro) # self.prev_yield_factor = None
def __init__(self, release_time=None, num_elements=0, release_mass=0, **kwargs): self.num_elements = num_elements self.release_time = asdatetime(release_time) self.release_mass = release_mass self.rewind() super(Release, self).__init__(**kwargs) self.array_types.update({ 'positions': gat('positions'), 'mass': gat('mass'), 'init_mass': gat('mass') })
def __init__(self, distribution=None, **kwargs): """ Set the rise velocity parameters to be sampled from a distribution. :param distribution: An object capable of generating a probability distribution. :type distribution: Right now, we have: * UniformDistribution * NormalDistribution * LogNormalDistribution * WeibullDistribution New distribution classes could be made. The only requirement is they need to have a set_values() method which accepts a NumPy array. (presumably, this function will also modify the array in some way) """ super(InitRiseVelFromDist, self).__init__(**kwargs) if distribution: self.distribution = distribution else: raise TypeError('InitRiseVelFromDist requires a distribution for ' 'rise velocities') self.array_types['rise_vel'] = gat('rise_vel') self.name = 'rise_vel'
def __init__(self): """ update array_types """ super(InitMassFromPlume, self).__init__() self.array_types['mass'] = gat('mass') self.name = 'mass'
def __init__(self, name=None, water=None, **kwargs): oil_info = name if name in _sample_oils: oil_info = _sample_oils[name] elif isinstance(name, six.string_types): # check if it's json from save file or from client if kwargs.get('component_density', False): oil_info = kwargs else: from oil_library import get_oil_props if kwargs.get('adios_oil_id', False): # init the oilprops from dictionary, old form oil_obj = get_oil_props(kwargs) else: # use name to get oil from oil library oil_obj = get_oil_props(name) oil_info = oil_obj.get_gnome_oil() kwargs['name'] = name #this is important; it passes name up to GnomeId to be handled there! else: raise ValueError('Must provide an oil name or OilLibrary.Oil ' 'to GnomeOil init') Oil.__init__(self, **oil_info) # because passing oilLibrary kwargs makes problem up the tree, # only pass up the kwargs specified in the schema keys = self._schema().get_nodes_by_attr('all') if 'windage_range' in kwargs: keys.append('windage_range') if 'windage_persist' in kwargs: keys.append('windage_persist') k2 = dict([(key, kwargs.get(key)) for key in keys]) read_only_attrs = GnomeOil._schema().get_nodes_by_attr('read_only') for n in read_only_attrs: k2.pop(n, None) k2.pop('water') Substance.__init__(self, **k2) self.water = water # add the array types that this substance DIRECTLY initializes self.array_types.update({'density': gat('density'), 'viscosity': gat('viscosity'), 'mass_components': gat('mass_components')}) self.array_types['mass_components'].shape = (self.num_components,) self.array_types['mass_components'].initial_value = (self.mass_fraction,)
def __init__(self, waves=None, wind=None, **kwargs): ''' :param waves: waves object for obtaining wave_height, etc. at a given time ''' self.waves = waves self.wind = wind if waves is not None and wind is not None: make_default_refs = False else: make_default_refs = True super(Dissolution, self).__init__(make_default_refs=make_default_refs, **kwargs) self.array_types.update({ 'area': gat('area'), 'mass': gat('mass'), 'density': gat('density'), 'positions': gat('positions'), 'viscosity': gat('viscosity'), 'partition_coeff': gat('partition_coeff'), 'droplet_avg_size': gat('droplet_avg_size') })
def __init__(self, water=None, thickness_limit=None, **kwargs): ''' initialize object - invoke super, add required data_arrays. ''' super(FayGravityViscous, self).__init__(**kwargs) self.spreading_const = (1.53, 1.21) # need water temp to get initial viscosity of oil so thickness_limit # can be set # fixme: can use nominal viscosity! self.water = water self.array_types.update({ 'fay_area': gat('fay_area'), 'area': gat('area'), 'bulk_init_volume': gat('bulk_init_volume'), 'age': gat('age'), 'density': gat('density'), 'frac_coverage': gat('frac_coverage'), 'spill_num': gat('spill_num') }) # relative_buoyancy - use density at release time. For now # temperature is fixed so just compute once and store. When temperature # varies over time, may want to do something different self._init_relative_buoyancy = None self.thickness_limit = thickness_limit self.is_first_step = True
def __init__(self, water=None, wind=None, **kwargs): ''' :param conditions: gnome.environment.Conditions object which contains things like water temperature :param wind: wind object for obtaining speed at specified time :type wind: Wind API, specifically must have get_value(time) method ''' self.water = water self.wind = wind if water is not None and wind is not None: make_default_refs = False else: make_default_refs = True super(Evaporation, self).__init__(make_default_refs=make_default_refs, **kwargs) self.array_types.update({ 'positions': gat('positions'), 'area': gat('area'), 'evap_decay_constant': gat('evap_decay_constant'), 'frac_water': gat('frac_water'), 'frac_lost': gat('frac_lost'), 'frac_evap': gat('frac_evap'), 'init_mass': gat('init_mass') })
def __init__(self, **kwargs): ''' Base weatherer class; defines the API for all weatherers Passes optional arguments to base (Process) class via super. See base class for optional arguments: `gnome.movers.mover.Process` adds 'mass_components', 'mass' to array_types since all weatherers need these. ''' super(Weatherer, self).__init__(**kwargs) # arrays that all weatherers will update - use this to ask self.array_types.update({ 'mass_components': gat('mass_components'), 'fate_status': gat('fate_status'), 'mass': gat('mass'), 'init_mass': gat('init_mass') })
def __init__(self, efficiency=1.0, **kwargs): ''' add 'frac_water' to array_types and pass **kwargs to base class __init__ using super ''' self._efficiency = None self.efficiency = efficiency super(CleanUpBase, self).__init__(**kwargs) self.array_types.update({'frac_water': gat('frac_water')})
def test_LEData_prep(): arrtypes = {'area': gat('area')} dat = LEData() dat.prepare_for_model_run(arrtypes, 0) assert 'area' in dat._array_types assert dat['area'].shape == (0, ) assert dat['positions'].shape == (0, 3) assert dat._bufs['area'].shape == (100, ) assert dat._bufs['positions'].shape == (100, 3) assert len(dat) == 0
def __init__(self, distribution=None, water_density=1020.0, water_viscosity=1.0e-6, **kwargs): """ Set the droplet size from a distribution. Use the C++ get_rise_velocity function exposed via cython (rise_velocity_from_drop_size) to obtain rise_velocity from droplet size. Even though the droplet size is not changing over time, it is still stored in data array, as it can be useful for post-processing (called 'droplet_diameter') :param distribution: An object capable of generating a probability distribution. :type distribution: Right now, we have: * UniformDistribution * NormalDistribution * LogNormalDistribution * WeibullDistribution New distribution classes could be made. The only requirement is they need to have a set_values() method which accepts a NumPy array. (presumably, this function will also modify the array in some way) :param water_density: 1020.0 [kg/m3] :type water_density: float :param water_viscosity: 1.0e-6 [m^2/s] :type water_viscosity: float """ super(InitRiseVelFromDropletSizeFromDist, self).__init__(**kwargs) if distribution: self.distribution = distribution else: raise TypeError('InitRiseVelFromDropletSizeFromDist requires a ' 'distribution for droplet sizes') self.water_viscosity = water_viscosity self.water_density = water_density self.array_types.update({'rise_vel': gat('rise_vel'), 'droplet_diameter': gat('droplet_diameter')}) self.name = 'rise_vel'
def __init__(self, uncertain_duration=3, uncertain_time_delay=0, uncertain_speed_scale=2., uncertain_angle_scale=0.4, **kwargs): """ This is simply a base class for WindMover and GridWindMover for the common properties. The classes that inherit from this should define the self.mover object correctly so it has the required attributes. Input args with defaults: :param uncertain_duration: (seconds) the randomly generated uncertainty array gets recomputed based on 'uncertain_duration' :param uncertain_time_delay: when does the uncertainly kick in. :param uncertain_speed_scale: Scale for uncertainty in wind speed non-dimensional number :param uncertain_angle_scale: Scale for uncertainty in wind direction. Assumes this is in radians It calls super in the __init__ method and passes in the optional parameters (kwargs) """ super(WindMoversBase, self).__init__(**kwargs) self.uncertain_duration = uncertain_duration self.uncertain_time_delay = uncertain_time_delay self.uncertain_speed_scale = uncertain_speed_scale # also sets self._uncertain_angle_units self.uncertain_angle_scale = uncertain_angle_scale self.array_types.update({ 'windages': gat('windages'), 'windage_range': gat('windage_range'), 'windage_persist': gat('windage_persist') })
def __init__(self, standard_density=1000.0, **kwargs): ''' Non-weathering substance class for use with ElementType. - Right now, we consider our substance to have default properties similar to water, which we can of course change by passing something in. :param standard_density=1000.0: The density of the substance, assumed to be measured at 15 C. :type standard_density: Floating point decimal value :param pour_point=273.15: The pour_point of the substance, assumed to be measured in degrees Kelvin. :type pour_point: Floating point decimal value ''' super(NonWeatheringSubstance, self).__init__(**kwargs) self.standard_density = standard_density self.array_types.update({ 'density': gat('density'), 'fate_status': gat('fate_status')})
def __init__(self, windage_range=(0.01, 0.04), windage_persist=900, *args, **kwargs): """ Initializes the windages, windage_range, windage_persist data arrays. Initial values for windages use infinite persistence. These are updated by the WindMover for particles with non-zero persistence. Optional arguments: :param windage_range=(0.01, 0.04): the windage range of the elements default is (0.01, 0.04) from 1% to 4%. :type windage_range: tuple: (min, max) :param windage_persist=-1: Default is 900s, so windage is updated every 900 sec. -1 means the persistence is infinite so it is only set at the beginning of the run. :type windage_persist: integer seconds """ super(InitWindages, self).__init__(*args, **kwargs) self.windage_persist = windage_persist self.windage_range = windage_range self.array_types.update({'windages': gat('windages'), 'windage_range': gat('windage_range'), 'windage_persist': gat('windage_persist')})
def __init__(self, **kwargs): """ Uses super to invoke base class __init__ method. Optional parameters (kwargs) used to initialize CyRiseVelocityMover :param water_density: Default is 1020 kg/m3 :param water_viscosity: Default is 1.e-6 Remaining kwargs are passed onto Mover's __init__ using super. See Mover documentation for remaining valid kwargs. """ self.mover = CyRiseVelocityMover() super(RiseVelocityMover, self).__init__(**kwargs) self.array_types['rise_vel'] = gat('rise_vel')
def rewind(self): ''' Called by model.rewind() Reset variables set during prepare_for_model_run() to init conditions Make sure all child classes call parent rewind() first! ''' self._model_start_time = None self._dt_since_lastoutput = None self._write_step = True self._is_first_output = True self._surf_conc_computed = True self._middle_of_run = False if self.surface_conc: self.array_types['surface_concentration'] = gat( 'surface_concentration')
def __init__(self, water=None, wind=None, **kwargs): ''' initialize wind to (0, 0) if it is None ''' super(Langmuir, self).__init__(**kwargs) self.array_types.update({ 'fay_area': gat('fay_area'), 'area': gat('area'), 'bulk_init_volume': gat('bulk_init_volume'), 'age': gat('age'), 'positions': gat('positions'), 'spill_num': gat('spill_num'), 'frac_coverage': gat('frac_coverage'), 'density': gat('density') }) self.wind = wind # need water object to find relative buoyancy self.water = water
def test_LEData_extend(): arrtypes = {'area': gat('area')} dat = LEData() dat.prepare_for_model_run(arrtypes, 10) assert len(dat['area']) == 0 dat.extend_data_arrays(5) assert len(dat['area']) == 5 assert np.all(dat['area'] == 0) dat['area'][:] = 42 assert np.all(dat['area'] == 42) assert len(dat._bufs['area']) == 100 dat.extend_data_arrays(1000) assert dat._bufs['area'].shape == (2010, ) assert dat._bufs['positions'].shape == (2010, 3) assert len(dat['area']) == 1005 assert np.all(dat['area'][0:5] == 42) assert np.all(dat['area'][5:] == 0)
def __init__(self, waves=None, water=None, **kwargs): ''' :param conditions: gnome.environment.Conditions object which contains things like water temperature :param waves: waves object for obtaining wave_height, etc at given time ''' self.waves = waves self.water = water super(NaturalDispersion, self).__init__(**kwargs) self.array_types.update({ 'viscosity': gat('viscosity'), 'mass': gat('mass'), 'density': gat('density'), 'positions': gat('positions'), 'area': gat('area'), 'frac_water': gat('frac_water'), 'droplet_avg_size': gat('droplet_avg_size'), })
r = RiseVelocityMover() #r.water_density = 1 #r.water_viscosity = 1.1e-6 #assert r.water_density == 1 #assert r.water_viscosity == 1.1e-6 time_step = 15 * 60 # seconds rel_time = datetime(2012, 8, 20, 13) # yyyy/month/day/hr/min/sec initializers = [InitRiseVelFromDist(distribution=UniformDistribution())] sc = sample_sc_release( 5, (3., 6., 0.), rel_time, uncertain=False, arr_types={'rise_vel': gat('rise_vel')}, substance=NonWeatheringSubstance(initializers=initializers)) initializers = [InitRiseVelFromDist(distribution=UniformDistribution())] u_sc = sample_sc_release( 5, (3., 6., 0.), rel_time, uncertain=True, arr_types={'rise_vel': gat('rise_vel')}, substance=NonWeatheringSubstance(initializers=initializers)) model_time = rel_time @pytest.mark.parametrize("test_sc", [sc, u_sc]) def test_one_move(test_sc): """ calls one step for movement - just checks that it doesn't fail for any step
def __init__(self, *args, **kwargs): super(TamocRiseVelocityMover, self).__init__(*args, **kwargs) self.array_types.update({'density': gat('density'), 'droplet_diameter': gat('droplet_diameter')})
def __init__(self, waves=None, **kwargs): ''' :param conditions: gnome.environment.Conditions object which contains things like water temperature :param waves: waves object for obtaining emulsification wind speed at specified time :type waves: get_emulsification_wind(model_time) ''' self.waves = waves self._bw = 0 if waves is not None: kwargs['make_default_refs'] = \ kwargs.pop('make_default_refs', False) super(Emulsification, self).__init__(**kwargs) self.array_types.update({ 'age': gat('age'), 'bulltime': gat('bulltime'), 'frac_water': gat('frac_water'), 'density': gat('density'), 'viscosity': gat('viscosity'), 'positions': gat('positions'), 'oil_density': gat('oil_density'), 'oil_viscosity': gat('oil_viscosity'), 'mass': gat('mass'), 'interfacial_area': gat('interfacial_area'), 'frac_evap': gat('frac_evap') })
Only contains tests for ArrayType since the remaining array_types classes are trivial. They are tested in the integrated_tests ''' import numpy as np from gnome.basic_types import world_point_type, oil_status, \ status_code_type from gnome.array_types import ArrayType from gnome.array_types import gat, reset_to_defaults from pytest import mark, raises from testfixtures import log_capture age = gat('age') mass = gat('mass') mass_components = gat('mass_components') def test_reset_to_defaults(): ''' will reset the object that found in array_types._default_values and ignore the one not found in this dict. ''' ival = age.initial_value age.initial_value = 100 reset_to_defaults(age) assert age.initial_value == ival
def __init__(self, filename=None, wind=None, time_offset=0, uncertain_duration=3, uncertain_time_delay=0, uncertain_speed_scale=2., uncertain_angle_scale=0.4, scale_value=1, default_num_method='RK2', **kwargs): """ Initialize a PyWindMover :param filename: absolute or relative path to the data file(s): could be a string or list of strings in the case of a multi-file dataset :param wind: Environment object representing wind to be used. If this is not specified, a GridWind object will attempt to be instantiated from the file :param active_range: Range of datetimes for when the mover should be active :type active_range: 2-tuple of datetimes :param scale_value: Value to scale wind data :param uncertain_duration: how often does a given uncertain element get reset :param uncertain_time_delay: when does the uncertainly kick in. :param uncertain_cross: Scale for uncertainty perpendicular to the flow :param uncertain_along: Scale for uncertainty parallel to the flow :param time_offset: Time zone shift if data is in GMT :param num_method: Numerical method for calculating movement delta. Choices:('Euler', 'RK2', 'RK4') Default: RK2 """ (super(PyWindMover, self).__init__(default_num_method=default_num_method, **kwargs)) self.wind = wind self.make_default_refs = False self.filename = filename if self.wind is None: if filename is None: raise ValueError("must provide a filename or wind object") else: self.wind = GridWind.from_netCDF(filename=self.filename, **kwargs) self.uncertain_duration = uncertain_duration self.uncertain_time_delay = uncertain_time_delay self.uncertain_speed_scale = uncertain_speed_scale self.scale_value = scale_value self.time_offset = time_offset # also sets self._uncertain_angle_units self.uncertain_angle_scale = uncertain_angle_scale self.array_types.update({ 'windages': gat('windages'), 'windage_range': gat('windage_range'), 'windage_persist': gat('windage_persist') })
def __init__(self, water=None, **kwargs): ''' initialize object. :param water: requires a water object :type water: gnome.environment.Water Options arguments kwargs: these get passed to base class via super ''' super(WeatheringData, self).__init__(**kwargs) self.water = water self.array_types = { 'fate_status': gat('fate_status'), 'positions': gat('positions'), 'status_codes': gat('status_codes'), 'density': gat('density'), 'viscosity': gat('viscosity'), 'mass_components': gat('mass_components'), 'mass': gat('mass'), 'oil_density': gat('oil_density'), 'oil_viscosity': gat('oil_viscosity'), 'init_mass': gat('init_mass'), 'frac_water': gat('frac_water'), 'frac_lost': gat('frac_lost'), # change to frac_dissolved 'frac_evap': gat('frac_evap'), 'age': gat('age') } # following used to update viscosity self.visc_curvfit_param = 1.5e3 # units are sec^0.5 / m self.visc_f_ref = 0.84