:py:mod:`gnome.weatherers.cleanup` ================================== .. py:module:: gnome.weatherers.cleanup .. autoapi-nested-parse:: oil removal from various cleanup options add these as weatherers Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: gnome.weatherers.cleanup.RemoveMass gnome.weatherers.cleanup.CleanUpBase gnome.weatherers.cleanup.Skimmer gnome.weatherers.cleanup.Burn gnome.weatherers.cleanup.ChemicalDispersion .. py:class:: RemoveMass Bases: :py:obj:`object` create a mixin for mass removal. These methods are used by CleanUpBase and also by manual_beaching. .. py:attribute:: valid_vol_units .. py:attribute:: valid_mass_units .. py:method:: _get_mass(substance, amount, units) return 'amount' in units of 'kg' for specified substance uses the density corresponding with API temperature .. py:method:: _set__timestep(time_step, model_time) For cleanup operations we may know the start time pretty precisely. Use this to set _timestep to less than time_step resolution. Mostly done for testing right now so if XXX amount is skimmed between active start and active stop, the rate * duration gives the correct amount. Object must be active before invoking this, else self._timestep will give invalid results .. py:method:: prepare_for_model_step(sc, time_step, model_time) Do sub timestep resolution here so numbers add up correctly Mark LEs to be skimmed - do them in order right now. Assume all LEs that are released together will be skimmed together since they would be closer to each other in position. Assumes: there is more mass in water than amount of mass to be skimmed. The LEs marked for Skimming are marked only once - code checks to see if any LEs are marked for skimming and if none are found, it marks them. .. py:class:: CleanUpBase(efficiency=1.0, **kwargs) Bases: :py:obj:`RemoveMass`, :py:obj:`gnome.weatherers.Weatherer` Just need to add a few internal methods for Skimmer + Burn common code Currently defined as a base class. add 'frac_water' to array_types and pass **kwargs to base class __init__ using super .. py:property:: efficiency - Efficiency can be None since it indicates that we use wind to compute efficiency. - If efficiency is not None, it must be a number greater than or equal to 0.0 and less than or equal to 1.0. .. py:method:: _update_LE_status_codes(sc, new_status, substance, mass_to_remove, oilwater_mix=True) Need to mark LEs to 'new_status'. It updates the 'fate_status' for 'surface_weather' LEs. Mark LEs based on mass. Mass to remove is assumed to be the oil/water mixture by default (oilwater_mix=True) so we need to find the oil_amount given the water_frac: volume = sc['mass']/API_density (1 - sc['frac_water']) * oil_water_vol = volume oil_water_vol = volume / (1 - sc['frac_water']) Now, do a cumsum of oil_water_mass and find where np.cumsum(oil_water_vol) >= vol_to_remove and change the status_codes of these LEs. Can just as easily multiple everything by API_density to get np.cumsum(oil_water_mass) >= mass_to_remove mass_to_remove = sc['mass'] / (1 - sc['frac_water']) This is why the input is 'mass_to_remove' instead of 'vol_to_remove' - less computation Note: For ChemicalDispersion, the mass_to_remove is not the mass of the oil/water mixture, but the mass of the oil. Use the oilwater_mix flag to indicate this is the case. .. py:method:: _avg_frac_oil(data) find weighted average of frac_water array, return (1 - avg_frac_water) since we want the average fraction of oil in this data .. py:class:: Skimmer(amount=0, units=None, water=None, **kwargs) Bases: :py:obj:`CleanUpBase` Just need to add a few internal methods for Skimmer + Burn common code Currently defined as a base class. initialize Skimmer object - calls base class __init__ using super() active_range is required cleanup operations must have a valid datetime - cannot use -inf and inf active_range is used to get the mass removal rate .. py:property:: units return units for amount skimmed .. py:attribute:: _schema .. py:attribute:: _ref_as :value: 'skimmer' .. py:attribute:: _req_refs :value: ['water'] .. py:method:: _validunits(value) checks if units are either valid_vol_units or valid_mass_units .. py:method:: prepare_for_model_run(sc) no need to call base class since no new array_types were added .. py:method:: prepare_for_model_step(sc, time_step, model_time) Do sub timestep resolution here so numbers add up correctly Mark LEs to be skimmed - do them in order right now. Assume all LEs that are released together will be skimmed together since they would be closer to each other in position. Assumes: there is more mass in water than amount of mass to be skimmed. The LEs marked for Skimming are marked only once - code checks to see if any LEs are marked for skimming and if none are found, it marks them. .. py:method:: _mass_to_remove(substance) use density at 15C, ie corresponding with API to do mass/volume conversion .. py:method:: weather_elements(sc, time_step, model_time) Assumes there is only ever 1 substance being modeled! remove mass equally from LEs marked to be skimmed .. py:class:: Burn(area=None, thickness=None, active_range=(InfDateTime('-inf'), InfDateTime('inf')), area_units='m^2', thickness_units='m', efficiency=1.0, wind=None, water=None, **kwargs) Bases: :py:obj:`CleanUpBase` Just need to add a few internal methods for Skimmer + Burn common code Currently defined as a base class. Set the area of boomed oil to be burned. Cleanup operations must have a valid datetime for active start, cannot use -inf. Cannot set active stop - burn automatically stops when oil/water thickness reaches 2mm. :param float area: area of boomed oil/water mixture to burn :param float thickness: thickness of boomed oil/water mixture :param datetime active_range: time when the burn starts is the only thing we track. However we give a range to be consistent with all other weatherers. :param str area_units: default is 'm^2' :param str thickness_units: default is 'm' :param float efficiency: burn efficiency, must be greater than 0 and less than or equal to 1.0 :param wind: gnome.environment.Wind object. Only used to set efficiency if efficiency is None. Efficiency is defined as: 1 - 0.07 * wind.get_value(model_time) where wind.get_value(model_time) is value of wind at model_time Kwargs passed onto base class: :param str name: name of object :param bool on: whether object is on or not for the run .. py:property:: area_units .. py:property:: active_range .. py:property:: thickness .. py:property:: thickness_units .. py:attribute:: _schema .. py:attribute:: _ref_as :value: 'burn' .. py:attribute:: _req_refs :value: ['water', 'wind'] .. py:attribute:: valid_area_units .. py:attribute:: valid_length_units .. py:method:: _log_thickness_warning() when thickness or thickness_units are updated, check to see that the value in SI units is > _min_thickness. If it is not, then log a warning .. py:method:: prepare_for_model_run(sc) resets internal _oilwater_thickness variable to initial thickness specified by user and active stop to 'inf' again. initializes sc.mass_balance['burned'] = 0.0 .. py:method:: prepare_for_model_step(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 .. py:method:: _init_rate_duration(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 .. py:method:: _set_burn_params(sc, substance) Once LEs are marked for burn, the frac_water does not change set burn rate for oil/water thickness, as well as volume burn rate for oil: If data contains LEs marked for burning, then: avg_frac_oil = mass_weighed_avg(1 - data['frac_water']) _oilwater_thick_burnrate = 0.000058 * avg_frac_oil _oil_vol_burnrate = _oilwater_thick_burnrate * avg_frac_oil * area The burn duration is also known if efficiency is constant. However, if efficiency is based on variable wind, then duration cannot be computed. .. py:method:: _set_efficiency(points, model_time) return burn efficiency either from efficiency attribute or computed from wind .. py:method:: weather_elements(sc, time_step, model_time) 1. figure out the mass to remove for current timestep based on rate and efficiency. Find fraction of total mass and remove equally from all 'mass_components' of LEs marked for burning. 2. update 'mass' array and the amount burned in mass_balance dict 3. append to _burn_duration for each timestep .. py:class:: ChemicalDispersion(fraction_sprayed, active_range=(InfDateTime('-inf'), InfDateTime('inf')), waves=None, efficiency=1.0, **kwargs) Bases: :py:obj:`CleanUpBase` Just need to add a few internal methods for Skimmer + Burn common code Currently defined as a base class. another mass removal mechanism. The volume specified gets dispersed with efficiency based on wave conditions. :param volume: volume of oil (not oil/water?) applied with surfactant :type volume: float :param units: volume units :type units: str :param active_range: Range of datetimes for when the mover should be active :type active_range: 2-tuple of datetimes :param waves: waves object - query to get height. It must contain get_value() method. Default is None to support object creation by WebClient before a waves object is defined :type waves: an object with same interface as gnome.environment.Waves Optional Argument: Either efficiency or waves must be set before running the model. If efficiency is not set, then use wave height to estimate an efficiency :param efficiency: efficiency of operation. :type efficiency: float between 0 and 1 remaining kwargs include 'on' and 'name' and these are passed to base class via super .. py:attribute:: _schema .. py:attribute:: _ref_as :value: 'chem_dispersion' .. py:attribute:: _req_refs :value: ['waves'] .. py:method:: prepare_for_model_run(sc) reset _rate to None. It gets set when LEs are marked to be dispersed. .. py:method:: prepare_for_model_step(sc, time_step, model_time) 1. invoke base class method (using super) to set active flag 2. mark LEs for removal 3. set internal _rate attribute for mass removal [kg/sec] .. py:method:: _set_efficiency(points, model_time) .. py:method:: weather_elements(sc, time_step, model_time) for now just take away 0.1% at every step