1"""Typed model for Helios plant architecture parameters.
3This module provides discoverable, validated dataclasses mirroring the nested
4C++ ``ShootParameters`` / ``PhytomerParameters`` / ``LeafPrototype`` structures
5(plus the flat ``CarbohydrateParameters`` / ``NitrogenParameters``). The objects
6serialize to/from the plain ``dict`` JSON transport used by the PlantArchitecture
7wrapper, so they can be used interchangeably with the raw-dict API.
9Canonical usage builds a typed object from the values currently defined in the
10native library, mutates it, and applies it back -- this avoids any drift between
11Python-side defaults and the C++ defaults::
13 from pyhelios import Context, PlantArchitecture
14 from pyhelios.plant_architecture_params import ShootParameters, RandomParameterFloat
16 with Context() as ctx:
17 pa = PlantArchitecture(ctx)
18 pa.loadPlantModelFromLibrary("almond")
19 sp = ShootParameters.from_dict(pa.getCurrentShootParameters("trunk"))
20 sp.phytomer_parameters.leaf.pitch = RandomParameterFloat.uniform(40, 50)
21 pa.defineShootType("trunk2", sp)
25* Every numeric leaf/shoot/phytomer field is a :class:`RandomParameterFloat` or
26 :class:`RandomParameterInt` carrying a distribution and its parameters.
27* Prototype functions (leaf/flower/fruit) are referenced by *name* -- a string
28 naming a built-in Helios prototype (e.g. ``"AlmondFlowerPrototype"``). An empty
29 string / ``None`` means "unset". The C++ ``shared_ptr<Phytomer>`` creation and
30 callback functions are not exposable from Python and are not represented here.
31* Child shoot types serialize on input only (the native struct has no public
32 getter); see :attr:`ShootParameters.child_shoot_types`.
35from __future__
import annotations
37from dataclasses
import dataclass, field
38from typing
import Any, Dict, List, Optional, Tuple
41 "RandomParameterFloat",
45 "InternodeParameters",
49 "InflorescenceParameters",
52 "CarbohydrateParameters",
62 """A float-valued parameter with a sampling distribution.
64 Use the classmethod constructors (:meth:`constant`, :meth:`uniform`,
65 :meth:`normal`, :meth:`weibull`) rather than constructing directly.
68 distribution: str =
"constant"
69 parameters: List[float] = field(default_factory=
lambda: [0.0])
72 def constant(cls, value: float) ->
"RandomParameterFloat":
73 return cls(
"constant", [float(value)])
76 def uniform(cls, min_val: float, max_val: float) ->
"RandomParameterFloat":
78 raise ValueError(f
"min_val ({min_val}) must be <= max_val ({max_val})")
79 return cls(
"uniform", [float(min_val), float(max_val)])
82 def normal(cls, mean: float, std_dev: float) ->
"RandomParameterFloat":
84 raise ValueError(f
"std_dev ({std_dev}) must be >= 0")
85 return cls(
"normal", [float(mean), float(std_dev)])
88 def weibull(cls, shape: float, scale: float) ->
"RandomParameterFloat":
90 raise ValueError(f
"shape ({shape}) must be > 0")
92 raise ValueError(f
"scale ({scale}) must be > 0")
93 return cls(
"weibull", [float(shape), float(scale)])
99 def from_dict(cls, d: Dict[str, Any]) ->
"RandomParameterFloat":
100 return cls(str(d[
"distribution"]), [float(p)
for p
in d[
"parameters"]])
105 """An int-valued parameter with a sampling distribution."""
107 distribution: str =
"constant"
108 parameters: List[int] = field(default_factory=
lambda: [0])
111 def constant(cls, value: int) ->
"RandomParameterInt":
112 return cls(
"constant", [int(value)])
115 def uniform(cls, min_val: int, max_val: int) ->
"RandomParameterInt":
116 if min_val > max_val:
117 raise ValueError(f
"min_val ({min_val}) must be <= max_val ({max_val})")
118 return cls(
"uniform", [int(min_val), int(max_val)])
121 def discrete(cls, values: List[int]) ->
"RandomParameterInt":
123 raise ValueError(
"values list cannot be empty")
124 return cls(
"discretevalues", [int(v)
for v
in values])
131 def from_dict(cls, d: Dict[str, Any]) ->
"RandomParameterInt":
132 return cls(str(d[
"distribution"]), [int(round(float(p)))
for p
in d[
"parameters"]])
137RandomParameter = RandomParameterFloat
143Color = Tuple[float, float, float]
144Vec3 = Tuple[float, float, float]
147def _rpf(d: Dict[str, Any], key: str, default: RandomParameterFloat) -> RandomParameterFloat:
148 return RandomParameterFloat.from_dict(d[key])
if key
in d
else default
151def _rpi(d: Dict[str, Any], key: str, default: RandomParameterInt) -> RandomParameterInt:
152 return RandomParameterInt.from_dict(d[key])
if key
in d
else default
156 return {
"r": float(c[0]),
"g": float(c[1]),
"b": float(c[2])}
160 return (float(d.get(
"r", default[0])), float(d.get(
"g", default[1])), float(d.get(
"b", default[2])))
164 return {
"x": float(v[0]),
"y": float(v[1]),
"z": float(v[2])}
168 return (float(d.get(
"x", default[0])), float(d.get(
"y", default[1])), float(d.get(
"z", default[2])))
176 leaf_aspect_ratio: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(1.0))
177 midrib_fold_fraction: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
178 longitudinal_curvature: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
179 lateral_curvature: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
180 petiole_roll: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
181 wave_period: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
182 wave_amplitude: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
183 leaf_buckle_length: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
184 leaf_buckle_angle: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
185 leaf_offset: Vec3 = (0.0, 0.0, 0.0)
186 subdivisions: int = 1
187 unique_prototypes: int = 1
188 build_petiolule: bool =
False
189 OBJ_model_file: str =
""
190 leaf_texture_file: Dict[int, str] = field(default_factory=dict)
191 prototype_function: Optional[str] =
None
214 def from_dict(cls, d: Dict[str, Any]) ->
"LeafPrototype":
216 tex = d.get(
"leaf_texture_file", {})
218 leaf_aspect_ratio=
_rpf(d,
"leaf_aspect_ratio", base.leaf_aspect_ratio),
219 midrib_fold_fraction=
_rpf(d,
"midrib_fold_fraction", base.midrib_fold_fraction),
220 longitudinal_curvature=
_rpf(d,
"longitudinal_curvature", base.longitudinal_curvature),
221 lateral_curvature=
_rpf(d,
"lateral_curvature", base.lateral_curvature),
222 petiole_roll=
_rpf(d,
"petiole_roll", base.petiole_roll),
223 wave_period=
_rpf(d,
"wave_period", base.wave_period),
224 wave_amplitude=
_rpf(d,
"wave_amplitude", base.wave_amplitude),
225 leaf_buckle_length=
_rpf(d,
"leaf_buckle_length", base.leaf_buckle_length),
226 leaf_buckle_angle=
_rpf(d,
"leaf_buckle_angle", base.leaf_buckle_angle),
227 leaf_offset=
_vec3_from_dict(d[
"leaf_offset"], base.leaf_offset)
if "leaf_offset" in d
else base.leaf_offset,
228 subdivisions=int(d.get(
"subdivisions", base.subdivisions)),
229 unique_prototypes=int(d.get(
"unique_prototypes", base.unique_prototypes)),
230 build_petiolule=bool(d.get(
"build_petiolule", base.build_petiolule)),
231 OBJ_model_file=str(d.get(
"OBJ_model_file", base.OBJ_model_file)),
232 leaf_texture_file={int(k): str(v)
for k, v
in tex.items()},
233 prototype_function=(d.get(
"prototype_function")
or None),
242 pitch: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(20.0))
243 phyllotactic_angle: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(137.5))
244 radius_initial: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.001))
245 max_vegetative_buds_per_petiole: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(0))
246 max_floral_buds_per_petiole: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(0))
247 color: Color = (0.0, 0.0, 0.0)
248 image_texture: str =
""
249 length_segments: int = 1
250 radial_subdivisions: int = 7
266 def from_dict(cls, d: Dict[str, Any]) ->
"InternodeParameters":
269 pitch=
_rpf(d,
"pitch", base.pitch),
270 phyllotactic_angle=
_rpf(d,
"phyllotactic_angle", base.phyllotactic_angle),
271 radius_initial=
_rpf(d,
"radius_initial", base.radius_initial),
272 max_vegetative_buds_per_petiole=
_rpi(d,
"max_vegetative_buds_per_petiole", base.max_vegetative_buds_per_petiole),
273 max_floral_buds_per_petiole=
_rpi(d,
"max_floral_buds_per_petiole", base.max_floral_buds_per_petiole),
274 color=
_color_from_dict(d[
"color"], base.color)
if "color" in d
else base.color,
275 image_texture=str(d.get(
"image_texture", base.image_texture)),
276 length_segments=int(d.get(
"length_segments", base.length_segments)),
277 radial_subdivisions=int(d.get(
"radial_subdivisions", base.radial_subdivisions)),
283 petioles_per_internode: int = 1
284 pitch: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(90.0))
285 radius: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.001))
286 length: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.05))
287 curvature: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
288 taper: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
289 color: Color = (0.0, 0.0, 0.0)
290 length_segments: int = 1
291 radial_subdivisions: int = 7
307 def from_dict(cls, d: Dict[str, Any]) ->
"PetioleParameters":
310 petioles_per_internode=int(d.get(
"petioles_per_internode", base.petioles_per_internode)),
311 pitch=
_rpf(d,
"pitch", base.pitch),
312 radius=
_rpf(d,
"radius", base.radius),
313 length=
_rpf(d,
"length", base.length),
314 curvature=
_rpf(d,
"curvature", base.curvature),
315 taper=
_rpf(d,
"taper", base.taper),
316 color=
_color_from_dict(d[
"color"], base.color)
if "color" in d
else base.color,
317 length_segments=int(d.get(
"length_segments", base.length_segments)),
318 radial_subdivisions=int(d.get(
"radial_subdivisions", base.radial_subdivisions)),
324 leaves_per_petiole: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(1))
325 pitch: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
326 yaw: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
327 roll: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
328 leaflet_offset: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
329 leaflet_scale: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(1.0))
330 prototype_scale: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.05))
331 prototype: LeafPrototype = field(default_factory=LeafPrototype)
346 def from_dict(cls, d: Dict[str, Any]) ->
"LeafParameters":
349 leaves_per_petiole=
_rpi(d,
"leaves_per_petiole", base.leaves_per_petiole),
350 pitch=
_rpf(d,
"pitch", base.pitch),
351 yaw=
_rpf(d,
"yaw", base.yaw),
352 roll=
_rpf(d,
"roll", base.roll),
353 leaflet_offset=
_rpf(d,
"leaflet_offset", base.leaflet_offset),
354 leaflet_scale=
_rpf(d,
"leaflet_scale", base.leaflet_scale),
355 prototype_scale=
_rpf(d,
"prototype_scale", base.prototype_scale),
356 prototype=LeafPrototype.from_dict(d[
"prototype"])
if "prototype" in d
else base.prototype,
362 length: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.05))
363 radius: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.001))
364 pitch: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
365 roll: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
366 curvature: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
367 color: Color = (0.0, 0.0, 0.0)
368 length_segments: int = 3
369 radial_subdivisions: int = 7
384 def from_dict(cls, d: Dict[str, Any]) ->
"PeduncleParameters":
387 length=
_rpf(d,
"length", base.length),
388 radius=
_rpf(d,
"radius", base.radius),
389 pitch=
_rpf(d,
"pitch", base.pitch),
390 roll=
_rpf(d,
"roll", base.roll),
391 curvature=
_rpf(d,
"curvature", base.curvature),
392 color=
_color_from_dict(d[
"color"], base.color)
if "color" in d
else base.color,
393 length_segments=int(d.get(
"length_segments", base.length_segments)),
394 radial_subdivisions=int(d.get(
"radial_subdivisions", base.radial_subdivisions)),
400 flowers_per_peduncle: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(1))
401 flower_offset: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
402 pitch: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
403 roll: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
404 flower_prototype_scale: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0075))
405 fruit_prototype_scale: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0075))
406 fruit_gravity_factor_fraction: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
407 unique_prototypes: int = 1
408 flower_prototype_function: Optional[str] =
None
409 fruit_prototype_function: Optional[str] =
None
426 def from_dict(cls, d: Dict[str, Any]) ->
"InflorescenceParameters":
429 flowers_per_peduncle=
_rpi(d,
"flowers_per_peduncle", base.flowers_per_peduncle),
430 flower_offset=
_rpf(d,
"flower_offset", base.flower_offset),
431 pitch=
_rpf(d,
"pitch", base.pitch),
432 roll=
_rpf(d,
"roll", base.roll),
433 flower_prototype_scale=
_rpf(d,
"flower_prototype_scale", base.flower_prototype_scale),
434 fruit_prototype_scale=
_rpf(d,
"fruit_prototype_scale", base.fruit_prototype_scale),
435 fruit_gravity_factor_fraction=
_rpf(d,
"fruit_gravity_factor_fraction", base.fruit_gravity_factor_fraction),
436 unique_prototypes=int(d.get(
"unique_prototypes", base.unique_prototypes)),
437 flower_prototype_function=(d.get(
"flower_prototype_function")
or None),
438 fruit_prototype_function=(d.get(
"fruit_prototype_function")
or None),
444 internode: InternodeParameters = field(default_factory=InternodeParameters)
445 petiole: PetioleParameters = field(default_factory=PetioleParameters)
446 leaf: LeafParameters = field(default_factory=LeafParameters)
447 peduncle: PeduncleParameters = field(default_factory=PeduncleParameters)
448 inflorescence: InflorescenceParameters = field(default_factory=InflorescenceParameters)
460 def from_dict(cls, d: Dict[str, Any]) ->
"PhytomerParameters":
463 internode=InternodeParameters.from_dict(d[
"internode"])
if "internode" in d
else base.internode,
464 petiole=PetioleParameters.from_dict(d[
"petiole"])
if "petiole" in d
else base.petiole,
465 leaf=LeafParameters.from_dict(d[
"leaf"])
if "leaf" in d
else base.leaf,
466 peduncle=PeduncleParameters.from_dict(d[
"peduncle"])
if "peduncle" in d
else base.peduncle,
467 inflorescence=InflorescenceParameters.from_dict(d[
"inflorescence"])
if "inflorescence" in d
else base.inflorescence,
477 (
"girth_area_factor", 0.0),
478 (
"insertion_angle_tip", 20.0),
479 (
"insertion_angle_decay_rate", 0.0),
480 (
"internode_length_max", 0.02),
481 (
"internode_length_min", 0.002),
482 (
"internode_length_decay_rate", 0.0),
485 (
"gravitropic_curvature", 0.0),
487 (
"phyllochron_min", 2.0),
488 (
"elongation_rate_max", 0.2),
489 (
"vegetative_bud_break_probability_min", 0.0),
490 (
"vegetative_bud_break_probability_max", 1.0),
491 (
"vegetative_bud_break_probability_decay_rate", -0.5),
492 (
"flower_bud_break_probability", 0.0),
493 (
"fruit_set_probability", 0.0),
494 (
"vegetative_bud_break_time", 5.0),
498 (
"max_nodes_per_season", 9999),
499 (
"max_terminal_floral_buds", 0),
501_SHOOT_BOOL_FIELDS = (
502 (
"flowers_require_dormancy",
False),
503 (
"growth_requires_dormancy",
False),
504 (
"determinate_shoot_growth",
True),
510 phytomer_parameters: PhytomerParameters = field(default_factory=PhytomerParameters)
513 girth_area_factor: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
514 insertion_angle_tip: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(20.0))
515 insertion_angle_decay_rate: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
516 internode_length_max: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.02))
517 internode_length_min: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.002))
518 internode_length_decay_rate: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
519 base_roll: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
520 base_yaw: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
521 gravitropic_curvature: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
522 tortuosity: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
523 phyllochron_min: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(2.0))
524 elongation_rate_max: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.2))
525 vegetative_bud_break_probability_min: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
526 vegetative_bud_break_probability_max: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(1.0))
527 vegetative_bud_break_probability_decay_rate: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(-0.5))
528 flower_bud_break_probability: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
529 fruit_set_probability: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(0.0))
530 vegetative_bud_break_time: RandomParameterFloat = field(default_factory=
lambda: RandomParameterFloat.constant(5.0))
533 max_nodes: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(10))
534 max_nodes_per_season: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(9999))
535 max_terminal_floral_buds: RandomParameterInt = field(default_factory=
lambda: RandomParameterInt.constant(0))
538 flowers_require_dormancy: bool =
False
539 growth_requires_dormancy: bool =
False
540 determinate_shoot_growth: bool =
True
545 child_shoot_types: Optional[Dict[str, Any]] =
None
549 for name, _
in _SHOOT_RPF_FIELDS:
550 d[name] = getattr(self, name).
to_dict()
551 for name, _
in _SHOOT_RPI_FIELDS:
552 d[name] = getattr(self, name).
to_dict()
553 for name, _
in _SHOOT_BOOL_FIELDS:
554 d[name] = bool(getattr(self, name))
560 def from_dict(cls, d: Dict[str, Any]) ->
"ShootParameters":
561 kwargs: Dict[str, Any] = {}
562 if "phytomer_parameters" in d:
563 kwargs[
"phytomer_parameters"] = PhytomerParameters.from_dict(d[
"phytomer_parameters"])
564 for name, default
in _SHOOT_RPF_FIELDS:
566 kwargs[name] = RandomParameterFloat.from_dict(d[name])
567 for name, default
in _SHOOT_RPI_FIELDS:
569 kwargs[name] = RandomParameterInt.from_dict(d[name])
570 for name, default
in _SHOOT_BOOL_FIELDS:
572 kwargs[name] = bool(d[name])
573 if "child_shoot_types" in d:
574 kwargs[
"child_shoot_types"] = d[
"child_shoot_types"]
578 """Set child shoot types; probabilities must sum to 1 (validated natively)."""
579 if len(labels) != len(probabilities):
580 raise ValueError(
"labels and probabilities must be the same length")
582 raise ValueError(
"labels and probabilities cannot be empty")
583 self.
child_shoot_types = {
"labels": list(labels),
"probabilities": [float(p)
for p
in probabilities]}
589def _flat_to_dict(obj: Any, names: Tuple[str, ...]) -> Dict[str, float]:
590 return {n: float(getattr(obj, n))
for n
in names}
593def _flat_from_dict(cls: Any, d: Dict[str, Any], names: Tuple[str, ...]) -> Any:
595 kwargs = {n: float(d[n])
for n
in names
if n
in d}
597 kwargs.setdefault(n, getattr(base, n))
602 "stem_density",
"stem_carbon_percentage",
"stem_carbohydrate_percentage",
603 "stem_structural_carbon_percentage",
"maturity_age",
"initial_density_ratio",
604 "shoot_root_ratio",
"leaf_total_carbon_percentage",
"SLA",
605 "leaf_carbohydrate_percentage",
"leaf_carbon_percentage",
"total_flower_cost",
606 "fruit_density",
"fruit_carbon_percentage",
"r_m_w_20",
"r_m_r_20",
607 "living_wood_fraction",
"growth_respiration_fraction",
"carbohydrate_abortion_threshold",
608 "carbohydrate_pruning_threshold",
"bud_death_threshold_days",
"branch_death_threshold_days",
609 "carbohydrate_phyllochron_threshold",
"carbohydrate_vegetative_break_threshold",
610 "carbohydrate_growth_threshold",
"starch_sequestration_ratio",
611 "carbohydrate_transfer_threshold_down",
"carbohydrate_transfer_threshold_up",
612 "carbon_conductance_down",
"carbon_conductance_up",
618 """Flat carbohydrate-model parameters. Defaults mirror the Helios C++ defaults;
619 prefer ``CarbohydrateParameters.from_dict(pa.getDefaultCarbohydrateParameters())``."""
621 stem_density: float = 675000.0
622 stem_carbon_percentage: float = 0.457
623 stem_carbohydrate_percentage: float = 1 - (1 / 1.14)
624 stem_structural_carbon_percentage: float = 0.457 - (1 - (1 / 1.14))
625 maturity_age: float = 120.0
626 initial_density_ratio: float = 0.25
627 shoot_root_ratio: float = 3.0
628 leaf_total_carbon_percentage: float = 0.453
629 SLA: float = 9.2 / 10000 / 0.453 * 12.01
630 leaf_carbohydrate_percentage: float = 1 - (1 / 1.13)
631 leaf_carbon_percentage: float = 0.453
632 total_flower_cost: float = 8.33e-4
633 fruit_density: float = 525000.0
634 fruit_carbon_percentage: float = 0.475
635 r_m_w_20: float = 5.25164e-05
636 r_m_r_20: float = 5.25164e-03
637 living_wood_fraction: float = 0.5
638 growth_respiration_fraction: float = 0.211
639 carbohydrate_abortion_threshold: float = 0.1
640 carbohydrate_pruning_threshold: float = 0.025
641 bud_death_threshold_days: float = 2.0
642 branch_death_threshold_days: float = 5.0
643 carbohydrate_phyllochron_threshold: float = 0.05
644 carbohydrate_vegetative_break_threshold: float = 0.05
645 carbohydrate_growth_threshold: float = 0.2
646 starch_sequestration_ratio: float = 0.025
647 carbohydrate_transfer_threshold_down: float = 0.025
648 carbohydrate_transfer_threshold_up: float = 0.04
649 carbon_conductance_down: float = 0.95
650 carbon_conductance_up: float = 0.95 * 0.5
656 def from_dict(cls, d: Dict[str, Any]) ->
"CarbohydrateParameters":
661 "target_leaf_N_area",
"minimum_leaf_N_area",
"root_allocation_fraction",
662 "max_N_accumulation_rate",
"leaf_remobilization_efficiency",
663 "remobilization_age_threshold",
"fruit_N_area",
669 """Flat nitrogen-model parameters. Prefer
670 ``NitrogenParameters.from_dict(pa.getDefaultNitrogenParameters())``."""
672 target_leaf_N_area: float = 1.5
673 minimum_leaf_N_area: float = 0.5
674 root_allocation_fraction: float = 0.15
675 max_N_accumulation_rate: float = 0.1
676 leaf_remobilization_efficiency: float = 0.70
677 remobilization_age_threshold: float = 0.70
678 fruit_N_area: float = 1.0
680 def to_dict(self) -> Dict[str, float]:
684 def from_dict(cls, d: Dict[str, Any]) ->
"NitrogenParameters":
Flat carbohydrate-model parameters.
"CarbohydrateParameters" from_dict(cls, Dict[str, Any] d)
Dict[str, float] to_dict(self)
Optional fruit_prototype_function
RandomParameterFloat roll
Dict[str, Any] to_dict(self)
RandomParameterFloat fruit_prototype_scale
RandomParameterFloat pitch
Optional flower_prototype_function
RandomParameterInt flowers_per_peduncle
RandomParameterFloat fruit_gravity_factor_fraction
"InflorescenceParameters" from_dict(cls, Dict[str, Any] d)
RandomParameterFloat flower_offset
RandomParameterFloat flower_prototype_scale
"InternodeParameters" from_dict(cls, Dict[str, Any] d)
RandomParameterFloat pitch
RandomParameterInt max_floral_buds_per_petiole
RandomParameterFloat radius_initial
Dict[str, Any] to_dict(self)
RandomParameterInt max_vegetative_buds_per_petiole
RandomParameterFloat phyllotactic_angle
RandomParameterFloat leaflet_offset
RandomParameterFloat prototype_scale
RandomParameterFloat roll
RandomParameterFloat pitch
"LeafParameters" from_dict(cls, Dict[str, Any] d)
RandomParameterInt leaves_per_petiole
RandomParameterFloat leaflet_scale
Dict[str, Any] to_dict(self)
RandomParameterFloat longitudinal_curvature
Optional prototype_function
Dict[str, Any] to_dict(self)
RandomParameterFloat leaf_buckle_length
"LeafPrototype" from_dict(cls, Dict[str, Any] d)
RandomParameterFloat wave_period
RandomParameterFloat leaf_aspect_ratio
RandomParameterFloat midrib_fold_fraction
RandomParameterFloat wave_amplitude
RandomParameterFloat lateral_curvature
RandomParameterFloat leaf_buckle_angle
RandomParameterFloat petiole_roll
Flat nitrogen-model parameters.
RandomParameterFloat pitch
RandomParameterFloat curvature
RandomParameterFloat length
RandomParameterFloat roll
Dict[str, Any] to_dict(self)
RandomParameterFloat radius
"PeduncleParameters" from_dict(cls, Dict[str, Any] d)
Dict[str, Any] to_dict(self)
"PetioleParameters" from_dict(cls, Dict[str, Any] d)
RandomParameterFloat length
RandomParameterFloat curvature
RandomParameterFloat pitch
int petioles_per_internode
RandomParameterFloat radius
RandomParameterFloat taper
Dict[str, Any] to_dict(self)
PetioleParameters petiole
InternodeParameters internode
PeduncleParameters peduncle
"PhytomerParameters" from_dict(cls, Dict[str, Any] d)
InflorescenceParameters inflorescence
A float-valued parameter with a sampling distribution.
"RandomParameterFloat" from_dict(cls, Dict[str, Any] d)
"RandomParameterFloat" normal(cls, float mean, float std_dev)
"RandomParameterFloat" weibull(cls, float shape, float scale)
Dict[str, Any] to_dict(self)
"RandomParameterFloat" uniform(cls, float min_val, float max_val)
"RandomParameterFloat" constant(cls, float value)
An int-valued parameter with a sampling distribution.
"RandomParameterInt" from_dict(cls, Dict[str, Any] d)
Dict[str, Any] to_dict(self)
"RandomParameterInt" discrete(cls, List[int] values)
"RandomParameterInt" uniform(cls, int min_val, int max_val)
"RandomParameterInt" constant(cls, int value)
None define_child_shoot_types(self, List[str] labels, List[float] probabilities)
Set child shoot types; probabilities must sum to 1 (validated natively).
Dict[str, Any] to_dict(self)
Optional child_shoot_types
PhytomerParameters phytomer_parameters
"ShootParameters" from_dict(cls, Dict[str, Any] d)
Vec3 _vec3_from_dict(Dict[str, Any] d, Vec3 default)
Any _flat_from_dict(Any cls, Dict[str, Any] d, Tuple[str,...] names)
Dict[str, float] _vec3_to_dict(Vec3 v)
Dict[str, float] _flat_to_dict(Any obj, Tuple[str,...] names)
RandomParameterInt _rpi(Dict[str, Any] d, str key, RandomParameterInt default)
Dict[str, float] _color_to_dict(Color c)
Color _color_from_dict(Dict[str, Any] d, Color default)
RandomParameterFloat _rpf(Dict[str, Any] d, str key, RandomParameterFloat default)