2High-level PlantHydraulics interface for PyHelios.
4This module provides a user-friendly interface to the plant hydraulics modeling
5capabilities with graceful plugin handling and informative error messages.
11from dataclasses
import dataclass
12from typing
import List, Optional, Sequence, Union
14from .plugins.registry
import get_plugin_registry
15from .wrappers
import UPlantHydraulicsWrapper
as hydraulics_wrapper
16from .Context
import Context, check_context_alive
17from .exceptions
import HeliosError
19logger = logging.getLogger(__name__)
23 """Exception raised for PlantHydraulics-specific errors."""
31 "PistachioFemale",
"pistachiofemale",
"pistachio_female",
"Pistachio_Female",
"Pistachio_female",
32 "pistachio",
"Pistachio",
33 "Elderberry",
"elderberry",
"blue_elderberry",
34 "Western_Redbud",
"western_redbud",
"Redbud",
"redbud",
39 if not isinstance(species, str):
40 raise ValueError(f
"{method_name}() species must be a string, got {type(species).__name__}")
41 if species
not in AVAILABLE_SPECIES:
43 f
"{method_name}() unknown species '{species}'. "
44 f
"Available species: {', '.join(AVAILABLE_SPECIES)}"
50 if isinstance(value, bool)
or not isinstance(value, numbers.Real):
51 raise ValueError(f
"{method_name}() {name} must be a number, got {type(value).__name__}")
52 if not math.isfinite(value):
53 raise ValueError(f
"{method_name}() {name} must be finite, got {value}")
57def _validate_int(value, name: str, method_name: str, minimum: int) -> int:
58 if isinstance(value, bool)
or not isinstance(value, numbers.Integral):
59 raise ValueError(f
"{method_name}() {name} must be an integer, got {type(value).__name__}")
61 raise ValueError(f
"{method_name}() {name} must be >= {minimum}, got {value}")
66 if not isinstance(value, bool):
67 raise ValueError(f
"{method_name}() {name} must be a bool, got {type(value).__name__}")
72 if isinstance(UUIDs, (str, bytes))
or not hasattr(UUIDs,
'__iter__'):
73 raise ValueError(f
"{method_name}() UUIDs must be a list of integers, got {type(UUIDs).__name__}")
74 uuid_list = [
_validate_int(uuid,
'UUID', method_name, 0)
for uuid
in UUIDs]
76 raise ValueError(f
"{method_name}() UUIDs cannot be empty")
83 Hydraulic conductance of a leaf, stem or root as a function of water potential.
85 Conductance follows K = saturated_conductance / (1 + |psi / potential_at_half_saturated|^sensitivity).
86 It is constant at saturated_conductance when potential_at_half_saturated or sensitivity is zero.
89 saturated_conductance: Conductance at a water potential of zero (mol/m²/s/MPa). Must be > 0.
90 potential_at_half_saturated: Water potential at which conductance is half its saturated value (MPa).
91 sensitivity: Steepness of the decline in conductance around potential_at_half_saturated (unitless).
92 temperature_dependence: If True, conductance is scaled by (T/298.15)^7.
94 saturated_conductance: float = 0.5
95 potential_at_half_saturated: float = 0.0
96 sensitivity: float = 0.0
97 temperature_dependence: bool =
False
99 def validate(self, method_name: str =
"HydraulicConductance") ->
None:
100 """Raise ValueError if any parameter is outside its valid range."""
103 raise ValueError(f
"{method_name}() saturated_conductance must be > 0, got {saturated}")
106 if sensitivity < 0.0:
107 raise ValueError(f
"{method_name}() sensitivity must be >= 0, got {sensitivity}")
110 def to_list(self) -> List[float]:
111 """Flat layout expected by the native interface."""
119 Hydraulic capacitance of a leaf, stem or root, from pressure-volume curve parameters.
121 A fixed_constant_capacitance greater than zero gives a constant capacitance. Use
122 HydraulicCapacitance.constant() to build one; its pressure-volume curve parameters are the defaults.
124 For a leaf, the model always computes relative water content, turgor pressure and osmotic
125 potential from the pressure-volume curve parameters, so a constant leaf capacitance means those
126 outputs come from the default curve. For a stem or root, capacitance is used only by
127 non-steady-state runs, which require a constant; their pressure-volume curve parameters are
131 osmotic_potential_at_full_turgor: Osmotic potential at full turgor (MPa). Must be < 0.
132 relative_water_content_at_turgor_loss: Relative water content at the turgor loss point (unitless), in (0, 1).
133 cell_wall_elasticity_exponent: Exponent of the turgor pressure versus relative water content relationship (unitless).
134 saturated_specific_water_content: Specific water content at a relative water content of 1 (mol/m²).
135 fixed_constant_capacitance: Constant capacitance (mol/m²/MPa), or -1 to use the pressure-volume curve.
137 osmotic_potential_at_full_turgor: float = -2.0
138 relative_water_content_at_turgor_loss: float = 0.8
139 cell_wall_elasticity_exponent: float = 1.0
140 saturated_specific_water_content: float = 1.0
141 fixed_constant_capacitance: float = -1.0
144 def constant(cls, capacitance: float) ->
'HydraulicCapacitance':
146 Create a constant hydraulic capacitance.
149 capacitance: Constant capacitance (mol/m²/MPa). Must be > 0.
151 value =
_validate_float(capacitance,
'capacitance',
'HydraulicCapacitance.constant')
153 raise ValueError(f
"HydraulicCapacitance.constant() capacitance must be > 0, got {value}")
154 return cls(fixed_constant_capacitance=value)
157 """True if this is a constant capacitance rather than a pressure-volume curve."""
160 def validate(self, method_name: str =
"HydraulicCapacitance") ->
None:
161 """Raise ValueError if any parameter is outside its valid range."""
163 if fixed <= 0.0
and fixed != -1.0:
165 f
"{method_name}() fixed_constant_capacitance must be > 0, or -1 to use the "
166 f
"pressure-volume curve parameters, got {fixed}"
170 raise ValueError(f
"{method_name}() osmotic_potential_at_full_turgor must be < 0, got {osmotic}")
172 'relative_water_content_at_turgor_loss', method_name)
173 if not 0.0 < turgor_loss < 1.0:
175 f
"{method_name}() relative_water_content_at_turgor_loss must be between 0 and 1 (exclusive), "
179 if elasticity <= 0.0:
180 raise ValueError(f
"{method_name}() cell_wall_elasticity_exponent must be > 0, got {elasticity}")
183 raise ValueError(f
"{method_name}() saturated_specific_water_content must be > 0, got {saturated}")
185 def to_list(self) -> List[float]:
186 """Flat layout expected by the native interface."""
192def _make_conductance(method_name, saturated_conductance, potential_at_half_saturated, sensitivity,
193 temperature_dependence) -> HydraulicConductance:
194 if potential_at_half_saturated
is None:
195 if sensitivity
is not None:
196 raise ValueError(f
"{method_name}() sensitivity requires potential_at_half_saturated")
200 5.0
if sensitivity
is None else sensitivity, temperature_dependence)
201 conductance.validate(method_name)
205def _make_capacitance(method_name, first, relative_water_content_at_turgor_loss, cell_wall_elasticity_exponent,
206 saturated_specific_water_content=None) -> HydraulicCapacitance:
207 if relative_water_content_at_turgor_loss
is None:
208 if cell_wall_elasticity_exponent
is not None or saturated_specific_water_content
is not None:
210 f
"{method_name}() a constant capacitance takes a single value; give "
211 f
"relative_water_content_at_turgor_loss to use pressure-volume curve parameters"
215 raise ValueError(f
"{method_name}() capacitance must be > 0, got {value}")
219 osmotic_potential_at_full_turgor=first,
220 relative_water_content_at_turgor_loss=relative_water_content_at_turgor_loss,
221 cell_wall_elasticity_exponent=1.0
if cell_wall_elasticity_exponent
is None else cell_wall_elasticity_exponent,
222 saturated_specific_water_content=1.0
if saturated_specific_water_content
is None else saturated_specific_water_content,
224 capacitance.validate(method_name)
230 Hydraulic conductance and capacitance parameters of the leaf, stem and root compartments.
232 A new instance holds the model defaults: a constant conductance of 0.5 mol/m²/s/MPa for each
233 compartment, and pressure-volume curve parameters of -2 MPa osmotic potential at full turgor,
234 0.8 relative water content at turgor loss and an elasticity exponent of 1.
237 LeafHydraulicConductance, StemHydraulicConductance, RootHydraulicConductance: HydraulicConductance
238 LeafHydraulicCapacitance: HydraulicCapacitance, or None when the leaf capacitance comes from the
239 species library (see leaf_capacitance_species)
240 StemHydraulicCapacitance, RootHydraulicCapacitance: HydraulicCapacitance
241 leaf_capacitance_species: Species name whose library leaf capacitance is used, or None
244 >>> coeffs = PlantHydraulicsModelCoefficients()
245 >>> coeffs.setLeafHydraulicConductance(0.05, -1.5, 2.0)
246 >>> coeffs.setStemHydraulicConductance(0.5)
247 >>> coeffs.setLeafHydraulicCapacitanceFromLibrary("pistachio")
257 self.leaf_capacitance_species: Optional[str] =
None
260 leaf_capacitance = (f
"library '{self.leaf_capacitance_species}'" if self.leaf_capacitance_species
261 else repr(self.LeafHydraulicCapacitance))
262 return (f
"PlantHydraulicsModelCoefficients(LeafHydraulicConductance={self.LeafHydraulicConductance!r}, "
263 f
"StemHydraulicConductance={self.StemHydraulicConductance!r}, "
264 f
"RootHydraulicConductance={self.RootHydraulicConductance!r}, "
265 f
"LeafHydraulicCapacitance={leaf_capacitance}, "
266 f
"StemHydraulicCapacitance={self.StemHydraulicCapacitance!r}, "
267 f
"RootHydraulicCapacitance={self.RootHydraulicCapacitance!r})")
272 potential_at_half_saturated: Optional[float] =
None,
273 sensitivity: Optional[float] =
None,
274 temperature_dependence: bool =
False) ->
None:
276 Set leaf hydraulic conductance, constant or as a function of leaf water potential.
279 saturated_conductance: Conductance at a water potential of zero (mol/m²/s/MPa). Typical range 0.001 to 1.
280 With no other arguments this is a constant conductance.
281 potential_at_half_saturated: Water potential at which conductance is half its saturated value (MPa).
282 sensitivity: Steepness of the decline in conductance with water potential (unitless).
283 Defaults to 5 when potential_at_half_saturated is given.
284 temperature_dependence: If True, conductance is scaled by (T/298.15)^7.
287 'setLeafHydraulicConductance', saturated_conductance, potential_at_half_saturated, sensitivity,
288 temperature_dependence)
291 """Toggle the temperature dependence of leaf hydraulic conductance, K(T) = K*(T/298.15)^7."""
293 temperature_dependence,
'temperature_dependence',
'setLeafHydraulicConductanceTemperatureDependence')
296 potential_at_half_saturated: Optional[float] =
None,
297 sensitivity: Optional[float] =
None,
298 temperature_dependence: bool =
False) ->
None:
300 Set stem hydraulic conductance, constant or as a function of stem water potential.
303 saturated_conductance: Conductance at a water potential of zero (mol/m²/s/MPa). Typical range 0.001 to 1.
304 With no other arguments this is a constant conductance.
305 potential_at_half_saturated: Water potential at which conductance is half its saturated value (MPa).
306 sensitivity: Steepness of the decline in conductance with water potential (unitless).
307 Defaults to 5 when potential_at_half_saturated is given.
308 temperature_dependence: If True, conductance is scaled by (T/298.15)^7.
311 'setStemHydraulicConductance', saturated_conductance, potential_at_half_saturated, sensitivity,
312 temperature_dependence)
315 """Toggle the temperature dependence of stem hydraulic conductance, K(T) = K*(T/298.15)^7."""
317 temperature_dependence,
'temperature_dependence',
'setStemHydraulicConductanceTemperatureDependence')
320 potential_at_half_saturated: Optional[float] =
None,
321 sensitivity: Optional[float] =
None,
322 temperature_dependence: bool =
False) ->
None:
324 Set root hydraulic conductance, constant or as a function of root water potential.
327 saturated_conductance: Conductance at a water potential of zero (mol/m²/s/MPa). Typical range 0.001 to 1.
328 With no other arguments this is a constant conductance.
329 potential_at_half_saturated: Water potential at which conductance is half its saturated value (MPa).
330 sensitivity: Steepness of the decline in conductance with water potential (unitless).
331 Defaults to 5 when potential_at_half_saturated is given.
332 temperature_dependence: If True, conductance is scaled by (T/298.15)^7.
335 'setRootHydraulicConductance', saturated_conductance, potential_at_half_saturated, sensitivity,
336 temperature_dependence)
339 """Toggle the temperature dependence of root hydraulic conductance, K(T) = K*(T/298.15)^7."""
341 temperature_dependence,
'temperature_dependence',
'setRootHydraulicConductanceTemperatureDependence')
346 relative_water_content_at_turgor_loss: Optional[float] =
None,
347 cell_wall_elasticity_exponent: Optional[float] =
None,
348 saturated_specific_water_content: Optional[float] =
None) ->
None:
350 Set leaf hydraulic capacitance, constant or from pressure-volume curve parameters.
352 Called with a single argument, that value is a constant capacitance (mol/m²/MPa, typical range
353 0.005 to 0.5). Otherwise the arguments are pressure-volume curve parameters.
355 The model computes leaf relative water content, turgor pressure and osmotic potential from
356 the pressure-volume curve parameters. A constant capacitance resets those parameters to
357 their defaults (-2 MPa, 0.8, 1) and otherwise only changes the optional
358 "hydraulic_capacitance" output.
361 osmotic_potential_at_full_turgor: Osmotic potential at full turgor (MPa), or the constant
362 capacitance (mol/m²/MPa) when it is the only argument.
363 relative_water_content_at_turgor_loss: Relative water content at the turgor loss point (unitless).
364 Typical range 0.7 to 0.95.
365 cell_wall_elasticity_exponent: Exponent of the turgor pressure versus relative water content
366 relationship (unitless). Typical range 1 to 2. Defaults to 1.
367 saturated_specific_water_content: Saturated specific water content (mol/m²). Defaults to 1.
370 'setLeafHydraulicCapacitance', osmotic_potential_at_full_turgor, relative_water_content_at_turgor_loss,
371 cell_wall_elasticity_exponent, saturated_specific_water_content)
376 Set leaf hydraulic capacitance from the species library of pressure-volume curve parameters.
378 The library values are held by the native plugin and applied when the coefficients are passed
379 to PlantHydraulicsModel.setModelCoefficients(). LeafHydraulicCapacitance stays None unless it
380 is later replaced by setLeafHydraulicCapacitance().
383 species: Species name. See pyhelios.PlantHydraulics.AVAILABLE_SPECIES.
386 ValueError: If the species is not in the library
392 relative_water_content_at_turgor_loss: Optional[float] =
None,
393 cell_wall_elasticity_exponent: Optional[float] =
None) ->
None:
395 Set stem hydraulic capacitance, constant or from pressure-volume curve parameters.
397 Called with a single argument, that value is a constant capacitance (typical range 0.005 to 2).
398 Stem capacitance is used only by non-steady-state runs, which require it to be constant;
399 pressure-volume curve parameters are accepted but never used by the model.
402 osmotic_potential_at_full_turgor: Osmotic potential at full turgor (MPa), or the constant
403 capacitance when it is the only argument.
404 relative_water_content_at_turgor_loss: Relative water content at the turgor loss point (unitless).
405 cell_wall_elasticity_exponent: Exponent of the turgor pressure versus relative water content
406 relationship (unitless). Defaults to 1.
409 'setStemHydraulicCapacitance', osmotic_potential_at_full_turgor, relative_water_content_at_turgor_loss,
410 cell_wall_elasticity_exponent)
413 relative_water_content_at_turgor_loss: Optional[float] =
None,
414 cell_wall_elasticity_exponent: Optional[float] =
None) ->
None:
416 Set root hydraulic capacitance, constant or from pressure-volume curve parameters.
418 Called with a single argument, that value is a constant capacitance (typical range 0.005 to 2).
419 Root capacitance is used only by non-steady-state runs, which require it to be constant;
420 pressure-volume curve parameters are accepted but never used by the model.
423 osmotic_potential_at_full_turgor: Osmotic potential at full turgor (MPa), or the constant
424 capacitance when it is the only argument.
425 relative_water_content_at_turgor_loss: Relative water content at the turgor loss point (unitless).
426 cell_wall_elasticity_exponent: Exponent of the turgor pressure versus relative water content
427 relationship (unitless). Defaults to 1.
430 'setRootHydraulicCapacitance', osmotic_potential_at_full_turgor, relative_water_content_at_turgor_loss,
431 cell_wall_elasticity_exponent)
433 def validate(self, method_name: str =
"PlantHydraulicsModelCoefficients") ->
None:
434 """Raise ValueError if any compartment's parameters are missing, mistyped or out of range."""
435 for label
in (
'Leaf',
'Stem',
'Root'):
436 conductance = getattr(self, f
'{label}HydraulicConductance')
437 if not isinstance(conductance, HydraulicConductance):
439 f
"{method_name}() {label}HydraulicConductance must be a HydraulicConductance, "
440 f
"got {type(conductance).__name__}"
442 conductance.validate(method_name)
446 for label
in (
'Leaf',
'Stem',
'Root'):
447 capacitance = getattr(self, f
'{label}HydraulicCapacitance')
450 if not isinstance(capacitance, HydraulicCapacitance):
452 f
"{method_name}() {label}HydraulicCapacitance must be a HydraulicCapacitance, "
453 f
"got {type(capacitance).__name__}"
455 capacitance.validate(method_name)
456 if label !=
'Leaf' and capacitance.saturated_specific_water_content != 1.0:
458 f
"{method_name}() {label}HydraulicCapacitance.saturated_specific_water_content cannot be set; "
459 f
"the model uses it only for leaves"
462 def to_list(self) -> List[float]:
463 """Flat layout expected by the native interface (see pyhelios_wrapper_planthydraulics.h)."""
468 values += [float(capacitance.osmotic_potential_at_full_turgor),
469 float(capacitance.relative_water_content_at_turgor_loss),
470 float(capacitance.cell_wall_elasticity_exponent),
471 float(capacitance.fixed_constant_capacitance)]
475 def from_list(cls, values: Sequence[float]) ->
'PlantHydraulicsModelCoefficients':
476 """Build coefficients from the flat layout written by to_list()."""
477 if len(values) != hydraulics_wrapper.COEFFICIENT_SIZE:
479 f
"PlantHydraulicsModelCoefficients.from_list() expects {hydraulics_wrapper.COEFFICIENT_SIZE} "
480 f
"values, got {len(values)}"
482 v = [float(value)
for value
in values]
484 for index, label
in enumerate((
'Leaf',
'Stem',
'Root')):
485 block = v[4 * index:4 * index + 4]
486 setattr(coeffs, f
'{label}HydraulicConductance',
496 High-level interface for plant hydraulics modeling.
498 The model computes the water potential of the root, stem and leaf compartments of a plant from
499 the transpiration of its leaves and a soil water potential set by the user. Stems and roots are
500 each one compartment per plant; leaf water potential, turgor pressure, osmotic potential and
501 relative water content are computed for each leaf primitive.
503 Leaves are grouped into plants by a "plantID", read from the object data of a primitive's parent
504 object or from the primitive's own data. run() groups the primitives it is given that have no
505 plantID into a new plant (see run()).
507 Input primitive data (float):
508 - "latent_flux" (W/m²): transpiration, e.g. from EnergyBalanceModel. A leaf without it
509 transpires nothing, and the plant's transpiration is the area-weighted mean over the
510 primitives that do have it (zero if none do).
511 - "temperature" (K, default 300): surface temperature, used for a temperature-dependent
513 - "air_temperature" (K, default 298.15): stem temperature; the root is taken to be 5 K
514 cooler. Used for a temperature-dependent stem or root conductance, and read from one
515 primitive only, the one with the lowest UUID in the plant.
516 - "water_potential" (MPa, default -0.001): leaf water potential at which a water-potential
517 dependent leaf conductance is evaluated. It is also an output, so repeated runs start
518 from the previous result.
519 - "relative_water_content" (default 1.0): initial leaf relative water content, read by
520 non-steady-state runs only
522 Water-potential dependent conductances are evaluated once per run at the water potentials from
523 before the run (for the stem and root, those stored from the model's previous run of the plant,
524 or -0.001 MPa), so a steady-state run is not iterated to a self-consistent solution.
526 Output primitive data:
527 - "water_potential" (MPa), "turgor_pressure" (MPa), "osmotic_potential" (MPa),
528 "relative_water_content" (unitless)
530 Steady-state runs (timespan=0) are the supported mode; non-steady-state runs are under
531 construction in the native plugin.
534 - Cross-platform support (Windows, Linux, macOS)
536 - No special dependencies
537 - Plant hydraulics plugin compiled into PyHelios
540 >>> with Context() as context:
541 ... # with: from pyhelios import Context; from pyhelios.types import vec2, vec3
542 ... leaf = context.addPatch(center=vec3(0, 0, 1), size=vec2(0.1, 0.1))
543 ... context.setPrimitiveDataFloat(leaf, "latent_flux", 100.0)
545 ... with PlantHydraulicsModel(context) as hydraulics:
546 ... coeffs = PlantHydraulicsModelCoefficients()
547 ... coeffs.setLeafHydraulicCapacitanceFromLibrary("pistachio")
548 ... hydraulics.setModelCoefficients(coeffs)
550 ... hydraulics.run([leaf])
551 ... psi_stem = hydraulics.getStemWaterPotential(leaf)
554 def __init__(self, context: Context):
556 Initialize PlantHydraulicsModel with graceful plugin handling.
559 context: Helios Context instance
562 TypeError: If context is not a Context instance
563 PlantHydraulicsModelError: If the plant hydraulics plugin is not available
566 if not (hasattr(context,
'__class__')
and
567 (isinstance(context, Context)
or
568 context.__class__.__name__ ==
'Context')):
569 raise TypeError(f
"PlantHydraulicsModel requires a Context instance, got {type(context).__name__}")
571 self.context = context
572 self.hydraulics_model =
None
574 self._per_primitive_uuids = set()
577 registry = get_plugin_registry()
579 if not registry.is_plugin_available(
'planthydraulics'):
581 "PlantHydraulicsModel requires the 'planthydraulics' plugin which is not available.\n\n"
582 "The plant hydraulics plugin computes root, stem and leaf water potentials, turgor "
583 "pressure, osmotic potential and relative water content from leaf transpiration.\n\n"
584 "To enable plant hydraulics modeling, build PyHelios with all plugins:\n"
585 " build_scripts/build_helios\n\n"
586 "System requirements:\n"
587 " - Platforms: Windows, Linux, macOS\n"
588 " - No GPU required\n"
589 " - No special dependencies"
594 self.
hydraulics_model = hydraulics_wrapper.createPlantHydraulicsModel(context.getNativePtr())
597 "Failed to create PlantHydraulicsModel instance. "
598 "This may indicate a problem with the native library."
600 logger.info(
"PlantHydraulicsModel created successfully")
602 except Exception
as e:
606 """Raise if the owning Context has been destroyed (see Context.check_context_alive)."""
607 check_context_alive(getattr(self,
"context",
None),
"PlantHydraulicsModel")
610 """Context manager entry."""
613 def __exit__(self, exc_type, exc_value, traceback):
614 """Context manager exit with proper cleanup."""
618 logger.debug(
"PlantHydraulicsModel destroyed successfully")
619 except Exception
as e:
620 logger.warning(f
"Error destroying PlantHydraulicsModel: {e}")
625 """Destructor to ensure C++ resources freed even without 'with' statement."""
630 except Exception
as e:
632 warnings.warn(f
"Error in PlantHydraulicsModel.__del__: {e}")
635 """Get the native pointer for advanced operations."""
641 UUIDs: Optional[List[int]] =
None) ->
None:
643 Set the model coefficients for all primitives, or for a subset of primitives.
645 Setting coefficients for all primitives clears any coefficients previously set for
648 Coefficients set for specific primitives apply to their leaf conductance and capacitance
649 only. Stem and root water potentials are always computed from the coefficients set for
653 modelcoefficients: Hydraulic conductance and capacitance parameters
654 UUIDs: Optional list of primitive UUIDs. If None, applies to all primitives.
657 ValueError: If modelcoefficients is not a PlantHydraulicsModelCoefficients, a parameter is
658 out of range, or UUIDs is empty
659 PlantHydraulicsModelError: If operation fails
662 >>> coeffs = PlantHydraulicsModelCoefficients()
663 >>> coeffs.setLeafHydraulicConductance(0.05, -1.5, 2.0)
664 >>> hydraulics.setModelCoefficients(coeffs)
666 if not isinstance(modelcoefficients, PlantHydraulicsModelCoefficients):
668 "setModelCoefficients() modelcoefficients must be a PlantHydraulicsModelCoefficients, "
669 f
"got {type(modelcoefficients).__name__}"
671 modelcoefficients.validate(
'setModelCoefficients')
672 uuid_list =
None if UUIDs
is None else _validate_uuids(UUIDs,
'setModelCoefficients')
676 if uuid_list
is None:
677 hydraulics_wrapper.setModelCoefficients(
678 self.
hydraulics_model, modelcoefficients.to_list(), modelcoefficients.leaf_capacitance_species)
681 hydraulics_wrapper.setModelCoefficientsForUUIDs(
683 modelcoefficients.leaf_capacitance_species)
685 except Exception
as e:
690 Set the model coefficients from the species library.
692 The library provides leaf pressure-volume curve parameters; all other coefficients take
693 their default values.
696 species: Species name. See pyhelios.PlantHydraulics.AVAILABLE_SPECIES.
697 UUIDs: Optional primitive UUID or list of UUIDs. If None, applies to all primitives.
700 ValueError: If the species is not in the library or UUIDs is empty
701 PlantHydraulicsModelError: If operation fails
704 >>> hydraulics.setModelCoefficientsFromLibrary("Walnut")
709 elif isinstance(UUIDs, numbers.Integral)
and not isinstance(UUIDs, bool):
710 uuid_list = [
_validate_int(UUIDs,
'UUID',
'setModelCoefficientsFromLibrary', 0)]
716 if uuid_list
is None:
717 hydraulics_wrapper.setModelCoefficientsFromLibrary(self.
hydraulics_model, species)
720 hydraulics_wrapper.setModelCoefficientsFromLibraryForUUIDs(self.
hydraulics_model, species, uuid_list)
722 except Exception
as e:
727 Get the coefficients set for a specific primitive.
729 Only coefficients given for specific primitives can be read: those set with
730 setModelCoefficients() or setModelCoefficientsFromLibrary() and a UUIDs argument. A primitive
731 without its own coefficients uses the model-wide ones, which the native model does not
734 Leaf capacitance taken from the species library is returned as its pressure-volume curve
735 parameters, with leaf_capacitance_species set to None.
741 A new PlantHydraulicsModelCoefficients holding the primitive's coefficients
744 ValueError: If UUID is not a non-negative integer
745 PlantHydraulicsModelError: If no coefficients were set for this primitive, or the
749 >>> hydraulics.setModelCoefficients(coeffs, UUIDs=[leaf_uuid])
750 >>> hydraulics.getModelCoefficients(leaf_uuid).LeafHydraulicConductance.saturated_conductance
752 uuid =
_validate_int(UUID,
'UUID',
'getModelCoefficients', 0)
757 f
"getModelCoefficients() primitive {uuid} has no coefficients of its own; it uses the "
758 f
"model-wide coefficients, which cannot be read back from the native model. Pass UUIDs to "
759 f
"setModelCoefficients() or setModelCoefficientsFromLibrary() to give it its own."
762 values = hydraulics_wrapper.getModelCoefficients(self.
hydraulics_model, uuid)
763 except Exception
as e:
765 return PlantHydraulicsModelCoefficients.from_list(values)
769 Get the model coefficients of a species from the library.
771 The library provides leaf pressure-volume curve parameters; all other coefficients are at
772 their default values. The leaf capacitance is returned as its parameter values, with
773 leaf_capacitance_species set to None.
776 species: Species name. See pyhelios.PlantHydraulics.AVAILABLE_SPECIES.
779 A new PlantHydraulicsModelCoefficients
782 ValueError: If the species is not in the library
783 PlantHydraulicsModelError: If operation fails
786 >>> coeffs = hydraulics.getModelCoefficientsFromLibrary("Walnut")
787 >>> coeffs.LeafHydraulicCapacitance.osmotic_potential_at_full_turgor
794 values = hydraulics_wrapper.getModelCoefficientsFromLibrary(self.
hydraulics_model, species)
795 except Exception
as e:
797 return PlantHydraulicsModelCoefficients.from_list(values)
801 def run(self, UUIDs: Optional[List[int]] =
None, timespan: int = 0, timestep: int = 100) ->
None:
803 Run the plant hydraulics model.
805 Primitives sharing a plantID are treated as the leaves of one plant, with one stem, root and
806 soil water potential. The model runs for every plant that the given primitives belong to,
807 and writes output data to all primitives in the Context with that plantID, not only to the
810 Given primitives with no plantID are grouped into one new plant: those that do not belong
811 to an object are added to a new polymesh object, and all of them are given the primitive
812 data "plantID", set to that object's ID. Primitives that already belong to an object stay
816 UUIDs: Optional list of primitive UUIDs selecting the plants to run. If None, runs for
817 all primitives in the Context; primitives with no plantID, including any that are
818 not leaves, are then grouped into a single plant.
819 timespan: Duration of the simulation (s). 0 gives the steady-state solution.
820 timestep: Timestep of a non-steady-state simulation (s).
823 ValueError: If UUIDs is empty, timespan is negative, or timestep is not positive
824 PlantHydraulicsModelError: If calculation fails, including when every primitive without a
825 plantID already belongs to an object, so that no polymesh object can be created
828 Non-steady-state runs (timespan > 0) are under construction in the native plugin, and
829 require constant stem and root capacitances.
832 >>> hydraulics.run(leaf_uuids) # steady state, the plants these leaves belong to
840 if uuid_list
is None:
843 hydraulics_wrapper.runForUUIDs(self.
hydraulics_model, uuid_list, timespan, timestep)
844 except Exception
as e:
849 Toggle writing of the optional primitive data "hydraulic_conductance" (mol/m²/s/MPa).
851 The data is written by non-steady-state runs only.
854 toggle: True to write the data
856 _validate_bool(toggle,
'toggle',
'outputConductancePrimitiveData')
860 except Exception
as e:
865 Toggle writing of the optional primitive data "hydraulic_capacitance" (mol/m²/MPa).
867 The data is written by non-steady-state runs only.
870 toggle: True to write the data
872 _validate_bool(toggle,
'toggle',
'outputCapacitancePrimitiveData')
875 hydraulics_wrapper.outputCapacitancePrimitiveData(self.
hydraulics_model, toggle)
876 except Exception
as e:
883 Group leaf primitives into a plant that shares stem, root and soil hydraulics.
885 Those of the primitives that do not belong to an object are added to a new polymesh object.
886 All of them are given the primitive data "plantID", set to that object's ID; primitives
887 that already belong to an object stay in it.
890 UUIDs: Leaf primitive UUIDs
893 The plantID assigned to the primitives
896 ValueError: If UUIDs is empty, or any of the primitives already has a plantID
897 PlantHydraulicsModelError: If all of the primitives already belong to an object, so that
898 no polymesh object can be created
903 ungrouped = hydraulics_wrapper.getPrimitivesWithoutPlantID(self.
hydraulics_model, uuid_list)
904 except Exception
as e:
906 already_grouped = sorted(set(uuid_list) - set(ungrouped))
909 "groupPrimitivesIntoPlantObject() primitives already have a plantID: "
910 f
"{already_grouped[:10]}{'...' if len(already_grouped) > 10 else ''}"
913 hydraulics_wrapper.groupPrimitivesIntoPlantObject(self.
hydraulics_model, uuid_list)
914 return hydraulics_wrapper.getPlantIDForUUIDs(self.
hydraulics_model, uuid_list)
915 except Exception
as e:
918 def getPlantID(self, UUIDs: Union[int, List[int]]) -> int:
920 Get the plantID of a primitive, or the plantID shared by a list of primitives.
923 UUIDs: Primitive UUID or list of UUIDs
929 ValueError: If UUIDs is empty
930 PlantHydraulicsModelError: If a primitive has no plantID, or the primitives do not share one
938 return hydraulics_wrapper.getPlantIDForUUIDs(self.
hydraulics_model, uuid_list)
939 except Exception
as e:
944 plant_ids = hydraulics_wrapper.getUniquePlantIDs(self.
hydraulics_model, uuid_list)
945 if len(plant_ids) > 1:
946 raise ValueError(f
"UUIDs do not share the same plantID; found plantIDs {sorted(plant_ids)}")
950 Get the unique plantIDs of a list of primitives.
953 UUIDs: Primitive UUIDs
956 List of unique plantIDs
959 ValueError: If UUIDs is empty
960 PlantHydraulicsModelError: If a primitive has no plantID
965 return hydraulics_wrapper.getUniquePlantIDs(self.
hydraulics_model, uuid_list)
966 except Exception
as e:
971 Get the primitives belonging to a plant.
974 plantID: Plant identifier
977 List of primitive UUIDs; empty if no primitive has this plantID
979 if isinstance(plantID, bool)
or not isinstance(plantID, numbers.Integral):
980 raise ValueError(f
"getPrimitivesByPlantID() plantID must be an integer, got {type(plantID).__name__}")
983 return hydraulics_wrapper.getPrimitivesByPlantID(self.
hydraulics_model, int(plantID))
984 except Exception
as e:
989 Get the primitives that have no plantID, in either parent object data or primitive data.
992 UUIDs: Primitive UUIDs to check
995 List of primitive UUIDs without a plantID
998 ValueError: If UUIDs is empty
1003 return hydraulics_wrapper.getPrimitivesWithoutPlantID(self.
hydraulics_model, uuid_list)
1004 except Exception
as e:
1011 if isinstance(UUIDs, numbers.Integral)
and not isinstance(UUIDs, bool):
1020 return hydraulics_wrapper.getWaterPotential(self.
hydraulics_model, compartment, uuid_list[0])
1022 return hydraulics_wrapper.getWaterPotentialForUUIDs(self.
hydraulics_model, compartment, uuid_list)
1023 except Exception
as e:
1027 plant_id =
_validate_int(plantID,
'plantID', method_name, 0)
1030 return hydraulics_wrapper.getWaterPotentialOfPlant(self.
hydraulics_model, compartment, plant_id)
1031 except Exception
as e:
1036 Get the stem water potential (MPa) of the plant that a leaf primitive, or a list of leaf
1037 primitives of one plant, belongs to.
1040 PlantHydraulicsModelError: If the model has not been run for the plant
1046 Get the stem water potential (MPa) of a plant.
1049 PlantHydraulicsModelError: If the model has not been run for the plant
1055 Get the root water potential (MPa) of the plant that a leaf primitive, or a list of leaf
1056 primitives of one plant, belongs to.
1059 PlantHydraulicsModelError: If the model has not been run for the plant
1065 Get the root water potential (MPa) of a plant.
1068 PlantHydraulicsModelError: If the model has not been run for the plant
1074 Get the soil water potential (MPa) of the plant that a leaf primitive, or a list of leaf
1075 primitives of one plant, belongs to.
1078 PlantHydraulicsModelError: If no soil water potential has been set and the model has not been
1085 Get the soil water potential (MPa) of a plant.
1088 PlantHydraulicsModelError: If no soil water potential has been set and the model has not been
1095 Set the soil water potential of a plant.
1097 Plants with no soil water potential set use -0.001 MPa.
1100 plantID: Plant identifier
1101 soil_water_potential: Soil water potential (MPa)
1104 >>> plantID = hydraulics.getPlantID(leaf_uuids)
1105 >>> hydraulics.setSoilWaterPotentialOfPlant(plantID, -0.05)
1107 plant_id =
_validate_int(plantID,
'plantID',
'setSoilWaterPotentialOfPlant', 0)
1108 potential =
_validate_float(soil_water_potential,
'soil_water_potential',
'setSoilWaterPotentialOfPlant')
1111 hydraulics_wrapper.setSoilWaterPotentialOfPlant(self.
hydraulics_model, plant_id, potential)
1112 except Exception
as e:
1119 if not isinstance(coeffs, HydraulicCapacitance):
1120 raise ValueError(f
"{method_name}() coeffs must be a HydraulicCapacitance, got {type(coeffs).__name__}")
1121 coeffs.validate(method_name)
1122 water_content =
_validate_float(relative_water_content,
'relative_water_content', method_name)
1123 if not 0.0 < water_content <= 1.0:
1124 raise ValueError(f
"{method_name}() relative_water_content must be in (0, 1], got {water_content}")
1125 return water_content
1130 Compute osmotic potential (MPa) at a relative water content from pressure-volume curve parameters.
1133 coeffs: Pressure-volume curve parameters
1134 relative_water_content: Relative water content (unitless), in (0, 1]
1136 water_content = PlantHydraulicsModel._validate_curve_args(coeffs, relative_water_content,
'computeOsmoticPotential')
1137 return hydraulics_wrapper.computeOsmoticPotential(coeffs.to_list(), water_content)
1142 Compute turgor pressure (MPa) at a relative water content from pressure-volume curve parameters.
1145 coeffs: Pressure-volume curve parameters
1146 relative_water_content: Relative water content (unitless), in (0, 1]
1148 water_content = PlantHydraulicsModel._validate_curve_args(coeffs, relative_water_content,
'computeTurgorPressure')
1149 return hydraulics_wrapper.computeTurgorPressure(coeffs.to_list(), water_content)
1154 Compute water potential (MPa) at a relative water content, the sum of turgor pressure and
1155 osmotic potential from pressure-volume curve parameters.
1158 coeffs: Pressure-volume curve parameters
1159 relative_water_content: Relative water content (unitless), in (0, 1]
1161 water_content = PlantHydraulicsModel._validate_curve_args(coeffs, relative_water_content,
'computeWaterPotential')
1162 return hydraulics_wrapper.computeWaterPotential(coeffs.to_list(), water_content)
1165 def computeCapacitance(coeffs: HydraulicCapacitance, relative_water_content: float) -> float:
1167 Compute hydraulic capacitance (mol/m²/MPa) at a relative water content.
1169 Returns the constant capacitance if coeffs holds one, otherwise the saturated specific water
1170 content divided by the slope of the pressure-volume curve.
1173 coeffs: Hydraulic capacitance parameters
1174 relative_water_content: Relative water content (unitless), in (0.001, 1]
1176 water_content = PlantHydraulicsModel._validate_curve_args(coeffs, relative_water_content,
'computeCapacitance')
1177 if not coeffs.is_constant()
and water_content <= 0.001:
1178 raise ValueError(f
"computeCapacitance() relative_water_content must be > 0.001, got {water_content}")
1179 return hydraulics_wrapper.computeCapacitance(coeffs.to_list(), water_content)
1182 def computeConductance(coeffs: HydraulicConductance, water_potential: float, temperature: float = 298.15) -> float:
1184 Compute hydraulic conductance (mol/m²/s/MPa) at a water potential and temperature.
1187 coeffs: Hydraulic conductance parameters
1188 water_potential: Water potential (MPa)
1189 temperature: Temperature (K); used only if coeffs has temperature dependence enabled
1191 if not isinstance(coeffs, HydraulicConductance):
1192 raise ValueError(f
"computeConductance() coeffs must be a HydraulicConductance, got {type(coeffs).__name__}")
1193 coeffs.validate(
'computeConductance')
1194 potential =
_validate_float(water_potential,
'water_potential',
'computeConductance')
1195 temperature_K =
_validate_float(temperature,
'temperature',
'computeConductance')
1196 if temperature_K <= 0.0:
1197 raise ValueError(f
"computeConductance() temperature must be > 0 K, got {temperature_K}")
1198 return hydraulics_wrapper.computeConductance(coeffs.to_list(), potential, temperature_K)
1202 Check if PlantHydraulicsModel is available in current build.
1205 True if plugin is available, False otherwise
1207 registry = get_plugin_registry()
1208 return registry.is_plugin_available(
'planthydraulics')
1214 Create PlantHydraulicsModel instance with context.
1217 context: Helios Context
1220 PlantHydraulicsModel instance
Hydraulic capacitance of a leaf, stem or root, from pressure-volume curve parameters.
bool is_constant(self)
True if this is a constant capacitance rather than a pressure-volume curve.
float cell_wall_elasticity_exponent
Exponent of the turgor pressure versus relative water content relationship (unitless).
float saturated_specific_water_content
Specific water content at a relative water content of 1 (mol/m²).
None validate(self, str method_name="HydraulicCapacitance")
Raise ValueError if any parameter is outside its valid range.
List[float] to_list(self)
Flat layout expected by the native interface.
float fixed_constant_capacitance
Constant capacitance (mol/m²/MPa), or -1 to use the pressure-volume curve.
float relative_water_content_at_turgor_loss
Relative water content at the turgor loss point (unitless), in (0, 1).
'HydraulicCapacitance' constant(cls, float capacitance)
Create a constant hydraulic capacitance.
float osmotic_potential_at_full_turgor
Osmotic potential at full turgor (MPa).
Hydraulic conductance of a leaf, stem or root as a function of water potential.
float potential_at_half_saturated
Water potential at which conductance is half its saturated value (MPa).
float saturated_conductance
Conductance at a water potential of zero (mol/m²/s/MPa).
float sensitivity
Steepness of the decline in conductance around potential_at_half_saturated (unitless).
None validate(self, str method_name="HydraulicConductance")
Raise ValueError if any parameter is outside its valid range.
bool temperature_dependence
If True, conductance is scaled by (T/298.15)^7.
List[float] to_list(self)
Flat layout expected by the native interface.
Hydraulic conductance and capacitance parameters of the leaf, stem and root compartments.
None setStemHydraulicCapacitance(self, float osmotic_potential_at_full_turgor, Optional[float] relative_water_content_at_turgor_loss=None, Optional[float] cell_wall_elasticity_exponent=None)
Set stem hydraulic capacitance, constant or from pressure-volume curve parameters.
List[float] to_list(self)
Flat layout expected by the native interface (see pyhelios_wrapper_planthydraulics....
None setRootHydraulicConductanceTemperatureDependence(self, bool temperature_dependence)
Toggle the temperature dependence of root hydraulic conductance, K(T) = K*(T/298.15)^7.
None setStemHydraulicConductance(self, float saturated_conductance, Optional[float] potential_at_half_saturated=None, Optional[float] sensitivity=None, bool temperature_dependence=False)
Set stem hydraulic conductance, constant or as a function of stem water potential.
None setLeafHydraulicCapacitanceFromLibrary(self, str species)
Set leaf hydraulic capacitance from the species library of pressure-volume curve parameters.
Optional[HydraulicCapacitance] LeafHydraulicCapacitance
HydraulicCapacitance, or None when the leaf capacitance comes from the.
Optional[str] leaf_capacitance_species
Species name whose library leaf capacitance is used, or None.
None setStemHydraulicConductanceTemperatureDependence(self, bool temperature_dependence)
Toggle the temperature dependence of stem hydraulic conductance, K(T) = K*(T/298.15)^7.
None setLeafHydraulicConductance(self, float saturated_conductance, Optional[float] potential_at_half_saturated=None, Optional[float] sensitivity=None, bool temperature_dependence=False)
Set leaf hydraulic conductance, constant or as a function of leaf water potential.
'PlantHydraulicsModelCoefficients' from_list(cls, Sequence[float] values)
Build coefficients from the flat layout written by to_list().
None setLeafHydraulicCapacitance(self, float osmotic_potential_at_full_turgor, Optional[float] relative_water_content_at_turgor_loss=None, Optional[float] cell_wall_elasticity_exponent=None, Optional[float] saturated_specific_water_content=None)
Set leaf hydraulic capacitance, constant or from pressure-volume curve parameters.
None setRootHydraulicCapacitance(self, float osmotic_potential_at_full_turgor, Optional[float] relative_water_content_at_turgor_loss=None, Optional[float] cell_wall_elasticity_exponent=None)
Set root hydraulic capacitance, constant or from pressure-volume curve parameters.
None setRootHydraulicConductance(self, float saturated_conductance, Optional[float] potential_at_half_saturated=None, Optional[float] sensitivity=None, bool temperature_dependence=False)
Set root hydraulic conductance, constant or as a function of root water potential.
None validate(self, str method_name="PlantHydraulicsModelCoefficients")
Raise ValueError if any compartment's parameters are missing, mistyped or out of range.
None setLeafHydraulicConductanceTemperatureDependence(self, bool temperature_dependence)
Toggle the temperature dependence of leaf hydraulic conductance, K(T) = K*(T/298.15)^7.
Exception raised for PlantHydraulics-specific errors.
High-level interface for plant hydraulics modeling.
float _validate_curve_args(coeffs, relative_water_content, str method_name)
__del__(self)
Destructor to ensure C++ resources freed even without 'with' statement.
float computeWaterPotential(HydraulicCapacitance coeffs, float relative_water_content)
Compute water potential (MPa) at a relative water content, the sum of turgor pressure and osmotic pot...
float getStemWaterPotential(self, Union[int, List[int]] UUIDs)
Get the stem water potential (MPa) of the plant that a leaf primitive, or a list of leaf primitives o...
_single_or_list(UUIDs, str method_name)
float _get_water_potential_of_plant(self, str compartment, plantID, str method_name)
float _get_water_potential(self, str compartment, UUIDs, str method_name)
None outputCapacitancePrimitiveData(self, bool toggle)
Toggle writing of the optional primitive data "hydraulic_capacitance" (mol/m²/MPa).
float getStemWaterPotentialOfPlant(self, int plantID)
Get the stem water potential (MPa) of a plant.
List[int] getPrimitivesWithoutPlantID(self, List[int] UUIDs)
Get the primitives that have no plantID, in either parent object data or primitive data.
float getRootWaterPotential(self, Union[int, List[int]] UUIDs)
Get the root water potential (MPa) of the plant that a leaf primitive, or a list of leaf primitives o...
getNativePtr(self)
Get the native pointer for advanced operations.
bool is_available(self)
Check if PlantHydraulicsModel is available in current build.
None setModelCoefficients(self, PlantHydraulicsModelCoefficients modelcoefficients, Optional[List[int]] UUIDs=None)
Set the model coefficients for all primitives, or for a subset of primitives.
PlantHydraulicsModelCoefficients getModelCoefficients(self, int UUID)
Get the coefficients set for a specific primitive.
None setModelCoefficientsFromLibrary(self, str species, Optional[Union[int, List[int]]] UUIDs=None)
Set the model coefficients from the species library.
float getSoilWaterPotentialOfPlant(self, int plantID)
Get the soil water potential (MPa) of a plant.
int groupPrimitivesIntoPlantObject(self, List[int] UUIDs)
Group leaf primitives into a plant that shares stem, root and soil hydraulics.
__exit__(self, exc_type, exc_value, traceback)
Context manager exit with proper cleanup.
int getPlantID(self, Union[int, List[int]] UUIDs)
Get the plantID of a primitive, or the plantID shared by a list of primitives.
float computeTurgorPressure(HydraulicCapacitance coeffs, float relative_water_content)
Compute turgor pressure (MPa) at a relative water content from pressure-volume curve parameters.
List[int] getPrimitivesByPlantID(self, int plantID)
Get the primitives belonging to a plant.
None _require_shared_plant(self, List[int] uuid_list)
__enter__(self)
Context manager entry.
None outputConductancePrimitiveData(self, bool toggle)
Toggle writing of the optional primitive data "hydraulic_conductance" (mol/m²/s/MPa).
_check_context_alive(self)
Raise if the owning Context has been destroyed (see Context.check_context_alive).
PlantHydraulicsModelCoefficients getModelCoefficientsFromLibrary(self, str species)
Get the model coefficients of a species from the library.
float getRootWaterPotentialOfPlant(self, int plantID)
Get the root water potential (MPa) of a plant.
float getSoilWaterPotential(self, Union[int, List[int]] UUIDs)
Get the soil water potential (MPa) of the plant that a leaf primitive, or a list of leaf primitives o...
float computeConductance(HydraulicConductance coeffs, float water_potential, float temperature=298.15)
Compute hydraulic conductance (mol/m²/s/MPa) at a water potential and temperature.
float computeCapacitance(HydraulicCapacitance coeffs, float relative_water_content)
Compute hydraulic capacitance (mol/m²/MPa) at a relative water content.
float computeOsmoticPotential(HydraulicCapacitance coeffs, float relative_water_content)
Compute osmotic potential (MPa) at a relative water content from pressure-volume curve parameters.
None run(self, Optional[List[int]] UUIDs=None, int timespan=0, int timestep=100)
Run the plant hydraulics model.
List[int] getUniquePlantIDs(self, List[int] UUIDs)
Get the unique plantIDs of a list of primitives.
None setSoilWaterPotentialOfPlant(self, int plantID, float soil_water_potential)
Set the soil water potential of a plant.
Exception classes for PyHelios library.
bool _validate_bool(value, str name, str method_name)
HydraulicCapacitance _make_capacitance(method_name, first, relative_water_content_at_turgor_loss, cell_wall_elasticity_exponent, saturated_specific_water_content=None)
str _validate_species(species, str method_name)
List[int] _validate_uuids(UUIDs, str method_name)
HydraulicConductance _make_conductance(method_name, saturated_conductance, potential_at_half_saturated, sensitivity, temperature_dependence)
PlantHydraulicsModel create_plant_hydraulics_model(Context context)
Create PlantHydraulicsModel instance with context.
int _validate_int(value, str name, str method_name, int minimum)
float _validate_float(value, str name, str method_name)