Source code for TidalPy.rheology.partial_melt.partialmelt

from typing import TYPE_CHECKING, Tuple

import numpy as np

from TidalPy.logger import get_logger
from TidalPy.exceptions import (BadValueError, IncorrectMethodToSetStateProperty, InitiatedPropertyChangeError,
                                OuterscopePropertySetError)
from TidalPy.utilities.performance import njit
from TidalPy.utilities.classes.model import LayerModelHolder

from . import known_model_const_args, known_model_live_args, known_models

if TYPE_CHECKING:
    from TidalPy.utilities.types import FloatArray
    from TidalPy.rheology import Rheology
    from TidalPy.structures.layers import PhysicalLayerType

log = get_logger("TidalPy")

[docs] @njit(cacheable=True) def calculate_melt_fraction(temperature: float, solidus: float, liquidus: float) -> float: """ Calculates the partial melt volume fraction based on the material's solidus and liquidus - NonArray Only Parameters ---------- temperature : float Temperature of the layer or material [K] solidus : float Solidus temperature of the material [K] liquidus : float Liquidus temperature of the material [K] Returns ------- partial_melt_volume_frac : float Volumetric Melt Fraction [m3 m-3] """ if solidus >= liquidus: raise BadValueError('Solidus temperature can not be larger to equal to the liquidus temperature.') partial_melt_volume_frac = (temperature - solidus) / (liquidus - solidus) # Check for over/under-shoots if partial_melt_volume_frac < 0.: partial_melt_volume_frac = 0. elif partial_melt_volume_frac > 1.: partial_melt_volume_frac = 1. return partial_melt_volume_frac
[docs] @njit(cacheable=True) def calculate_melt_fraction_array(temperature: np.ndarray, solidus: float, liquidus: float) -> np.ndarray: """ Calculates the partial melt volume fraction based on the material's solidus and liquidus - Arrays Only Parameters ---------- temperature : np.ndarray Temperature of the layer or material [K] solidus : float Solidus temperature of the material [K] liquidus : float Liquidus temperature of the material [K] Returns ------- partial_melt_volume_frac : np.ndarray Volumetric Melt Fraction [m3 m-3] """ if solidus >= liquidus: raise BadValueError('Solidus temperature can not be larger to equal to the liquidus temperature.') partial_melt_volume_frac = (temperature - solidus) / (liquidus - solidus) # Check for over/under-shoots partial_melt_volume_frac[partial_melt_volume_frac < 0.] = 0. partial_melt_volume_frac[partial_melt_volume_frac > 1.] = 1. return partial_melt_volume_frac
[docs] @njit(cacheable=True) def calculate_temperature_frommelt(melt_frac: float, solidus: float, liquidus: float) -> float: """ Calculates the temperature from the volumetric melt fraction - NonArray Only Parameters ---------- melt_frac : float Volumetric Melt Fraction [m3 m-3] solidus : float Material/Layer solidus temperature [K] liquidus : float Material/Layer liquidus temperature [K] Returns ------- temp_at_melt : float Temperature at melt fraction [K] """ # Check for over/under-shoots if melt_frac < 0.: melt_frac = 0. elif melt_frac > 1.: melt_frac = 1. temp_at_melt = melt_frac * (liquidus - solidus) + solidus return temp_at_melt
[docs] @njit(cacheable=True) def calculate_temperature_frommelt_array(melt_frac: np.ndarray, solidus: float, liquidus: float) -> np.ndarray: """ Calculates the temperature from the volumetric melt fraction - Arrays Only Parameters ---------- melt_frac : np.ndarray Volumetric Melt Fraction [m3 m-3] solidus : float Material/Layer solidus temperature [K] liquidus : float Material/Layer liquidus temperature [K] Returns ------- temp_at_melt : np.ndarray Temperature at melt fraction [K] """ # Check for over/under-shoots melt_frac[melt_frac < 0.] = 0. melt_frac[melt_frac > 1.] = 1. temp_at_melt = melt_frac * (liquidus - solidus) + solidus return temp_at_melt
[docs] class PartialMelt(LayerModelHolder): """ PartialMelt Partial melting provides a further temperature dependence to both viscosity and shear modulus. Depending upon the specific partial-melt model, the higher the temperature, the higher the partial melt fraction, and the lower the viscosity and shear modulus of the material. See Also -------- TidalPy.utilities.methods.model.LayerModelHolder TidalPy.rheology.Rheology """ known_models = known_models known_model_const_args = known_model_const_args known_model_live_args = known_model_live_args model_config_key = 'partial_melting' def __init__( self, layer: 'PhysicalLayerType', rheology_class: 'Rheology', model_name: str = None, store_config_in_layer: bool = True, initialize: bool = True ): """ Constructor for ComplexCompliance class Parameters ---------- layer : PhysicalLayerType The layer instance which the complex compliance should perform calculations on. rheology_class : Rheology Rheology class instance where the complex compliance model is stored. model_name : str = None The user-provided complex compliance name. store_config_in_layer: bool = True Flag that determines if the final complex compliance model's configuration dictionary should be copied into the `layer.config` dictionary. initialize : bool = True Determines if initial reinit should be performed on the model (loading in data from its `self.config`). """ super().__init__(layer, model_name, store_config_in_layer, initialize=False) # Initialized properties self._rheology_class = rheology_class # Configuration properties self.solidus = None self.liquidus = None self.use_partial_melt = None # State properties self._melt_fraction = None self._postmelt_viscosity = None self._postmelt_shear_modulus = None self._postmelt_compliance = None if initialize: self.reinit(initial_init=True)
[docs] def reinit(self, initial_init: bool = False): """ Reinit method for the PartialMelting class Model will look at the user-provided configurations and pull out model information including constants Parameters ---------- initial_init : bool = False Must be set to `True` if this is the first time this method has been called (additional steps may be preformed during the first reinit call). """ # Load in configurations self.solidus = self.config.get('solidus', None) self.liquidus = self.config.get('liquidus', None) if self.model == 'off': self.use_partial_melt = False else: self.use_partial_melt = True if self.solidus is None or self.liquidus is None: log.debug(f'Solidus or Liquidus not provided in configurations for {self}.') super().reinit(initial_init)
[docs] def clear_state(self): """ Clears the current state of the class without destroying data set by initialization. """ super().clear_state() self._melt_fraction = None self._postmelt_viscosity = None self._postmelt_shear_modulus = None self._postmelt_compliance = None
def _calculate(self) -> Tuple['FloatArray', 'FloatArray', 'FloatArray']: """ Wrapper for the partial melting function. First the partial melt will be updated based on the provided temperature. Then changes to the shear modulus and viscosity are updated. Returns ------- melt_fraction : FloatArray Volumetric Melt Fraction [m3 m-3] postmelt_viscosity : FloatArray Post melting effective viscosity [Pa s] postmelt_shear_modulus : FloatArray Post melting shear modulus [Pa] """ if self.use_partial_melt: if type(self.temperature) is np.ndarray: melt_fraction = calculate_melt_fraction_array(self.temperature, self.solidus, self.liquidus) postmelt_viscosity, postmelt_shear_modulus = \ self.func_array(melt_fraction, *self.live_inputs, *self.inputs) else: melt_fraction = calculate_melt_fraction(self.temperature, self.solidus, self.liquidus) postmelt_viscosity, postmelt_shear_modulus = \ self.func(melt_fraction, *self.live_inputs, *self.inputs) else: melt_fraction = np.zeros_like(self.temperature) postmelt_viscosity, postmelt_shear_modulus = self.premelt_viscosity, self.premelt_shear self._melt_fraction = melt_fraction self._postmelt_viscosity = postmelt_viscosity self._postmelt_shear_modulus = postmelt_shear_modulus self._postmelt_compliance = 1. / postmelt_shear_modulus return melt_fraction, postmelt_viscosity, postmelt_shear_modulus # Wrappers for user convenience
[docs] def calculate_melt_fraction(self, temperature: 'FloatArray') -> 'FloatArray': if type(temperature) is np.ndarray: return calculate_melt_fraction_array(temperature, self.solidus, self.liquidus) else: return calculate_melt_fraction(temperature, self.solidus, self.liquidus)
[docs] def calculate_temperature_frommelt(self, melt_fraction: 'FloatArray') -> 'FloatArray': if type(melt_fraction) is np.ndarray: return calculate_temperature_frommelt_array(melt_fraction, self.solidus, self.liquidus) else: return calculate_temperature_frommelt(melt_fraction, self.solidus, self.liquidus)
# # Initialized properties @property def rheology_class(self) -> 'Rheology': """ The rheology class instance where the complex compliance model is stored """ return self._rheology_class @rheology_class.setter def rheology_class(self, value): raise InitiatedPropertyChangeError # # State properties @property def postmelt_viscosity(self) -> 'FloatArray': """ Material's solid viscosity after the effects of partial melting have been applied """ return self._postmelt_viscosity @postmelt_viscosity.setter def postmelt_viscosity(self, value): raise IncorrectMethodToSetStateProperty @property def postmelt_shear_modulus(self) -> 'FloatArray': """ Material's shear modulus (rigidity) after the effects of partial melting have been applied """ return self._postmelt_shear_modulus @postmelt_shear_modulus.setter def postmelt_shear_modulus(self, value): raise IncorrectMethodToSetStateProperty @property def postmelt_compliance(self) -> 'FloatArray': """ Material's compliance (inverse of rigidity) after the effects of partial melting have been applied """ return self._postmelt_compliance @postmelt_compliance.setter def postmelt_compliance(self, value): raise IncorrectMethodToSetStateProperty @property def melt_fraction(self) -> 'FloatArray': """ Layer's volumetric melt fraction """ return self._melt_fraction @melt_fraction.setter def melt_fraction(self, value): raise IncorrectMethodToSetStateProperty # # Outer-scope properties @property def temperature(self): """ Outer-scope wrapper for `layer.temperature` """ return self.layer.temperature @temperature.setter def temperature(self, value): raise OuterscopePropertySetError @property def premelt_viscosity(self): """ Outer-scope wrapper for `layer.premelt_viscosity` """ return self.rheology_class.premelt_viscosity @premelt_viscosity.setter def premelt_viscosity(self, value): raise OuterscopePropertySetError @property def premelt_shear(self): """ Outer-scope wrapper for `layer.premelt_shear` """ return self.rheology_class.premelt_shear @premelt_shear.setter def premelt_shear(self, value): raise OuterscopePropertySetError @property def liquid_viscosity(self): """ Outer-scope wrapper for `layer.liquid_viscosity` """ return self.rheology_class.liquid_viscosity @liquid_viscosity.setter def liquid_viscosity(self, value): raise OuterscopePropertySetError