Module pychnosz.models.supcrt92_fortran
SUPCRT92 water model with Fortran backend.
This implementation uses the original H2O92 Fortran subroutine for exact compatibility with R CHNOSZ. Falls back to Python approximations if the Fortran library is not available.
Functions
def water_SUPCRT92(property: str | List[str],
T: float | numpy.ndarray = 298.15,
P: float | str | numpy.ndarray = 1.0,
**kwargs) ‑> float | numpy.ndarray | Dict[str, Any]-
Expand source code
def water_SUPCRT92(property: Union[str, List[str]], T: Union[float, np.ndarray] = 298.15, P: Union[float, np.ndarray, str] = 1.0, **kwargs) -> Union[float, np.ndarray, Dict[str, Any]]: """ Calculate water properties using SUPCRT92 model. This function provides the same interface as the original Python implementation but with Fortran backend support for high accuracy. Parameters ---------- property : str or list of str Property or list of properties to calculate T : float or array Temperature in Kelvin P : float, array, or 'Psat' Pressure in bar, or 'Psat' for saturation pressure **kwargs Additional options (e.g., Psat_floor) Returns ------- float, array, or dict Calculated properties Examples -------- >>> # Basic usage >>> rho = water_SUPCRT92('rho', 298.15, 1.0) >>> print(f"Density: {rho:.3f} g/cm³") >>> # Multiple properties >>> props = water_SUPCRT92(['rho', 'epsilon'], 298.15, 1.0) >>> print(f"ρ = {props['rho']:.3f}, ε = {props['epsilon']:.1f}") >>> # Saturation pressure >>> Psat = water_SUPCRT92('Psat', 373.15, 'Psat') >>> print(f"Psat at 100°C: {Psat:.2f} bar") """ return supcrt92_water.calculate(property, T, P, **kwargs)Calculate water properties using SUPCRT92 model.
This function provides the same interface as the original Python implementation but with Fortran backend support for high accuracy.
Parameters
property:strorlistofstr- Property or list of properties to calculate
T:floatorarray- Temperature in Kelvin
P:float, array,or'Psat'- Pressure in bar, or 'Psat' for saturation pressure
**kwargs- Additional options (e.g., Psat_floor)
Returns
float, array,ordict- Calculated properties
Examples
>>> # Basic usage >>> rho = water_SUPCRT92('rho', 298.15, 1.0) >>> print(f"Density: {rho:.3f} g/cm³")>>> # Multiple properties >>> props = water_SUPCRT92(['rho', 'epsilon'], 298.15, 1.0) >>> print(f"ρ = {props['rho']:.3f}, ε = {props['epsilon']:.1f}")>>> # Saturation pressure >>> Psat = water_SUPCRT92('Psat', 373.15, 'Psat') >>> print(f"Psat at 100°C: {Psat:.2f} bar")
Classes
class SUPCRT92Water-
Expand source code
class SUPCRT92Water: """ SUPCRT92 water model with Fortran backend. This class provides an interface to the original SUPCRT92 Fortran subroutines for calculating water properties. If the Fortran library is not available, it falls back to Python approximations. The Fortran implementation gives exact compatibility with R CHNOSZ and includes all 23+ thermodynamic properties. """ def __init__(self): """ Initialize SUPCRT92 water model. SUPCRT92 requires the compiled FORTRAN interface for accuracy and compatibility with R CHNOSZ. No pure Python fallback is provided. """ if not HAS_FORTRAN: raise ImportError( f"SUPCRT92 water model requires compiled FORTRAN interface. " f"Error: {_fortran_error}. " f"Please compile the FORTRAN subroutines using: " f"python compile_fortran.py. " f"See setup_fortran_instructions.md for details." ) # Initialize Fortran interface (required) try: self._fortran_interface = get_h2o92_interface() except Exception as e: raise RuntimeError(f"Failed to initialize FORTRAN interface: {e}") from e def calculate(self, properties: Union[str, List[str]], T: Union[float, np.ndarray] = 298.15, P: Union[float, np.ndarray, str] = 1.0, **kwargs) -> Union[float, np.ndarray, Dict[str, Any]]: """ Calculate water properties using SUPCRT92 model. Parameters ---------- properties : str or list of str Property or list of properties to calculate T : float or array Temperature in Kelvin P : float, array, or 'Psat' Pressure in bar, or 'Psat' for saturation pressure **kwargs Additional options (e.g., Psat_floor) Returns ------- float, array, or dict Calculated properties """ # Handle input types if isinstance(properties, str): properties = [properties] single_prop = True else: single_prop = False # Convert inputs to arrays T = np.atleast_1d(np.asarray(T, dtype=float)) # Always use FORTRAN backend (no fallback) return self._calculate_fortran(properties, T, P, single_prop, **kwargs) def _calculate_fortran(self, properties: List[str], T: np.ndarray, P: Union[np.ndarray, str], single_prop: bool, **kwargs) -> Union[float, np.ndarray, Dict[str, Any]]: """Calculate properties using Fortran backend.""" # Handle pressure input if isinstance(P, str) and P == 'Psat': P_vals = 'Psat' else: P = np.atleast_1d(np.asarray(P, dtype=float)) if len(P) < len(T): P = np.resize(P, len(T)) elif len(T) < len(P): T = np.resize(T, len(P)) P_vals = P # Use batched calculation for better performance try: results = self._fortran_interface.calculate_properties_batch( T, P_vals, properties ) except Exception as e: warnings.warn(f"Batch Fortran calculation failed: {e}") # Fallback to individual calculations if batch fails results = {} for prop in properties: results[prop] = np.full_like(T, np.nan) for i in range(len(T)): T_i = T[i] # Skip invalid points if np.isnan(T_i): continue if isinstance(P_vals, str): P_i = P_vals else: P_i = P_vals[i] if np.isnan(P_i): continue try: # Call Fortran interface props_i = self._fortran_interface.calculate_properties( T_i, P_i, properties ) # Store results for prop in properties: if prop in props_i: results[prop][i] = props_i[prop] except Exception as e: warnings.warn(f"Fortran calculation failed at T={T_i:.1f}K, P={P_i}: {e}") continue # Handle Psat_floor for saturation pressure if 'Psat' in results and 'Psat_floor' in kwargs: Psat_floor = kwargs['Psat_floor'] if Psat_floor is not None: results['Psat'] = np.maximum(results['Psat'], Psat_floor) # Return results if single_prop: result = results[properties[0]] return result[0] if len(result) == 1 else result else: # Convert single-element arrays to scalars if appropriate if len(T) == 1: for key in results: if len(results[key]) == 1: results[key] = results[key][0] return results def available_properties(self) -> List[str]: """ Get list of available properties. Returns ------- List[str] List of available property names """ if self._use_fortran: return self._fortran_interface.available_properties() else: return self._python_backend.available_properties() @property def backend(self) -> str: """Get the active backend ('fortran' or 'python').""" return 'fortran' if self._use_fortran else 'python' @property def has_fortran(self) -> bool: """Check if Fortran backend is available.""" return HAS_FORTRANSUPCRT92 water model with Fortran backend.
This class provides an interface to the original SUPCRT92 Fortran subroutines for calculating water properties. If the Fortran library is not available, it falls back to Python approximations.
The Fortran implementation gives exact compatibility with R CHNOSZ and includes all 23+ thermodynamic properties.
Initialize SUPCRT92 water model.
SUPCRT92 requires the compiled FORTRAN interface for accuracy and compatibility with R CHNOSZ. No pure Python fallback is provided.
Instance variables
prop backend : str-
Expand source code
@property def backend(self) -> str: """Get the active backend ('fortran' or 'python').""" return 'fortran' if self._use_fortran else 'python'Get the active backend ('fortran' or 'python').
prop has_fortran : bool-
Expand source code
@property def has_fortran(self) -> bool: """Check if Fortran backend is available.""" return HAS_FORTRANCheck if Fortran backend is available.
Methods
def available_properties(self) ‑> List[str]-
Expand source code
def available_properties(self) -> List[str]: """ Get list of available properties. Returns ------- List[str] List of available property names """ if self._use_fortran: return self._fortran_interface.available_properties() else: return self._python_backend.available_properties()Get list of available properties.
Returns
List[str]- List of available property names
def calculate(self,
properties: str | List[str],
T: float | numpy.ndarray = 298.15,
P: float | str | numpy.ndarray = 1.0,
**kwargs) ‑> float | numpy.ndarray | Dict[str, Any]-
Expand source code
def calculate(self, properties: Union[str, List[str]], T: Union[float, np.ndarray] = 298.15, P: Union[float, np.ndarray, str] = 1.0, **kwargs) -> Union[float, np.ndarray, Dict[str, Any]]: """ Calculate water properties using SUPCRT92 model. Parameters ---------- properties : str or list of str Property or list of properties to calculate T : float or array Temperature in Kelvin P : float, array, or 'Psat' Pressure in bar, or 'Psat' for saturation pressure **kwargs Additional options (e.g., Psat_floor) Returns ------- float, array, or dict Calculated properties """ # Handle input types if isinstance(properties, str): properties = [properties] single_prop = True else: single_prop = False # Convert inputs to arrays T = np.atleast_1d(np.asarray(T, dtype=float)) # Always use FORTRAN backend (no fallback) return self._calculate_fortran(properties, T, P, single_prop, **kwargs)Calculate water properties using SUPCRT92 model.
Parameters
properties:strorlistofstr- Property or list of properties to calculate
T:floatorarray- Temperature in Kelvin
P:float, array,or'Psat'- Pressure in bar, or 'Psat' for saturation pressure
**kwargs- Additional options (e.g., Psat_floor)
Returns
float, array,ordict- Calculated properties