leaf_gradient() and leaf_gradient_batch() lose method, step, stationarity_tol and fast_stem_curve, and their results lose method and stationarity, with no aliases: there is no difference to tune and no fallback to choose. A gradient costs the same whatever pars asks for.status is the kind the solve recorded: a leaf shut past the end of its stem curve is "pinned", not "no-gradient". A prescribed psi reproduces the solving path to rounding, not to the bit, and one whose leaf potential lies in the stem curve's tail is "no-gradient". The gradient_active_set condition is gone (#261).g_min = 5e-3 on a dry soil, rows in the stem traits and in g_min were wrong by up to 100%. With the energy balance on, the g_min row was wrong by up to 30% even at g_min = 0. No solve moves, and a leaf with no cuticle and the energy balance off records the same tape (#250).par_NIR after par_PPFD (n_leaf_pars is 37), so with the energy balance on a derivative in the intercepted near-infrared reaches leaf temperature. passive_pars() fills it from NIR_int_; gradient::n_theta does not change (#257).$hydraulic_cost_TF() is $hydraulic_cost_TF24() and $profit_psi_leaf_TF() is $profit_psi_leaf_TF24(), with no aliases. For C++ users, hydraulic_cost_TF_kernel is hydraulic_cost_TF24_kernel, and MultiLayerRoots::soil_number_of_depths_ is an int. No number moves.plot_model_overview() draws its profit panel at the leaf's own soil potential: given a leaf at a soil other than 1 MPa, the panel's curve used to disagree with the optimum it marked. The figure also hands a caller's leaf back on its own model.leaf_gradient() and leaf_gradient_batch() refuse LeastCost_beta on another curve with the same description leaf_solve() gives, a unit-cost ratio, where they called it a price of water.psi_crit in one evaluation rather than searched for. The collar solve of every curve is 2-3% faster. No number moves.$evaluate_root_collar_psi()) and a replay refuse a curve's unset parameter by name, as the solve does; they used to report a non-finite objective.Leaf members atm_vpd, ca, atm_kpa, atm_o2_kpa and leaf_temp are gone (the drivers are set_physiology's arguments), as are util::identical, util::clamp and Leaf::stem_curve_integral_inverse_deriv (#248).operating_collar(), billed_outputs_at(), physical_outputs_at()) follows the energy balance on every curve, where it refused a leaf with it on (#225). Leaf temperature moves with the stem's flux and with light, and the rows carry it through the capacities, the deficit, the cuticle and the first-order condition; ProfitMax's |A|max is read where |A| peaks. With the energy balance off every number and every tape is unchanged.leaf_damage_gradient() takes every input's derivative in one forward pass, on XAD's forward-mode scalar carrying all 17 directions, in place of a hand-written dual number and a pass per input. For all 17 inputs, the default, it is about 6 times faster; asking for one or two inputs costs what asking for all of them does. Derivatives move by at most 2e-15 relative; nothing else moves.LeastCost a leaf that cannot fix carbon at any opening (in the dark, or too hot) is reported closed at its wet end on both routes, as under SOX and JW26. It used to be opened to psi_crit on the leaf route, since a negative A/W is largest at the largest W, and refused on the collar route.ProfitMax the collar route reports a leaf with no objective (in the dark, or with a soil drier than psi_crit) as the leaf route does: closed, with zero profit and NA lambda. It used to report a profit from normalisers that were not positive, be refused, or fail on a very dry soil. Its derivative surface refuses such a point by name.carbon, A less the part of the cost that is carbon spent (only TF24's hydraulic cost is), beside profit, the objective; plant grows on carbon. physical_outputs_at() also returns A, E, psi_leaf, ci and gc, for fitting. (#239).$carbon and a carbon column of operating_point() and leaf_solve(), appended last.shadow_cost is the price part of every difference curve's cost: the whole cost on CF77, JS22 and CMax (it was 0), unchanged on TF24 and TF24_floor, and NA on SOX, JW26, LeastCost and ProfitMax (it was 0). No other number moves.ProfitMax, on either route, $hydraulic_cost_ and the hydraulic_cost column of operating_point() are NA, as under SOX, JW26 and LeastCost; on a reused leaf they reported the last other curve's cost. ProfitMax's own costs are $hydraulic_cost_norm_ and $thermal_cost_. Nothing else moves (#209).stem_c or root_c no longer rebuild a vulnerability table for every observation: a leaf keeps the last eight tables it built, so a batch builds each perturbed table once. A full gradient now costs about what one without those two traits costs. No number moves (#236).route = "stem" is route = "leaf" (in leaf_solve(), both gradients, $set_model() and $model_route()), and the psi_stem column of leaf_solve(), operating_point() and the gradients is psi_leaf. Names about the stem itself keep stem: stem_P50, stem_c, psi_crit and the stem curve. There are no aliases: the old names are gone.opt_psi_stem_ is opt_psi_leaf_, and psi_stem reads psi_leaf in profit_psi_stem_*, dprofit_dpsi_stem*, optimise_psi_stem_single, evaluate_psi_stem_at, psi_stem_to_ci, transpiration_to_psi_stem, set_leaf_states_rates_from_psi_stem and find_psi_stem_from_psi_root. $stem_wet_bound() is $leaf_wet_bound(), as is the infeasibility code of that name (leaf_infeasible_codes()), gradient::Route::Stem is Route::Leaf, and the header leaf_stem_routes.hpp is leaf_route.hpp.resistance is no longer a gradient parameter: the route pins the stem's upstream end at psi_soil, so its row was exactly zero. Naming it is refused with that reason; it remains one on the collar route over the single-potential supply.Leaf, leaf_model(), leaf_solve(), leaf_batch(), leaf_gradient() and leaf_gradient_batch(): the TF24_floor model, plant's, on the stem route over the single-potential supply. The multi-layer supply (supply = leaf_supply_multilayer(), or $set_supply_multilayer(), which also seats the collar route) and the collar route (route = "collar") are asked for. To reproduce earlier default results, pass supply = leaf_supply_multilayer(), model = "TF24", route = "collar". model = "collar" is gone. align_curves() aligns on the stem route as before, so its answers do not move.TF24_floor_lambda_o defaults to 0, as plant's does, where TF24_floor is TF24 bit for bit; it used to be refused unset. A TF24_floor gradient's default pars includes it.leaf_gradient() is leaf_gradient_batch() with one observation: it crosses into C++ once rather than over a hundred times, and its result names its route. An entry it cannot determine (a refused point's gradient, a stem route's collar) is NaN, as the batch's always was, where it was NA. Its errors are classed as the batch's are: an infeasible point is a phylloptim_infeasible condition, and no error is a C++Error.$evaluate_root_collar_psi()) seeds its normalisers, as its solve does; on a leaf whose drivers were just set it used to fail with a non-finite profit (#232).$lambda, $lambda_molar and the lambda column of operating_point() and leaf_solve() report the marginal cost of water of the curve the leaf is set to, on the route it was solved; they used to report TF24's whatever curve was set. $lambda_emergent and the lambda_emergent column, which held that number, are gone: read lambda. $lambda_multilayer is gone too: on the collar route $lambda is that number, for every curve.lambda as NA, as it does at a shut collar, where it used to report a negative number. Nothing else moves.cost_curve_parameters() lists each curve's parameters and defaults from the curves' definitions, which the package's own parameter tables now read; $curve_cost(), $curve_profit() and $curve_lambda() evaluate any curve by name at a stem potential, whatever the leaf is set to.marginal_cost_water() and marginal_cost_water_multilayer() are removed and marginal_cost_water_molar() is lambda_molar(): lambda_emergent() is the one λ a leaf reports. A curve's Curve<K> no longer holds λ, and its parameters state whether their defaults are aligned (#230).Curve<K> states the shape of its objective (a difference, a product, a ratio or a normalised value) and holds the factor that shape composes with assimilation: SOX's and JW26's reduction factors, LeastCost's weighted resource use and ProfitMax's normalised hydraulic cost. One evaluator per shape computes every curve's profit. No result changes and every bound method keeps its name (#228).phylloptim::Curve<K> in leaf_cost_curves.hpp: its name, the parameters it owns and their defaults, its properties, and its cost, the cost's slopes and its marginal cost of water. A curve missing a piece is a compile error naming it. No result changes and every bound method keeps its name (#226).$find_root_collar_psi() solves the curve the leaf is set to, on the collar route, and refuses what that curve refuses (TF24_floor without its price, for one); it used to solve TF24 whatever curve was set. A leaf on the default model is unchanged.leaf_gradient(model = "collar") on a reused leaf set to another curve differentiates TF24's collar route, as a fresh leaf does, at a solved or a prescribed psi. It used to solve TF24 and test the point against the other curve, reporting it pinned, and to differentiate the other curve at a prescribed psi. The leaf is left set to the model the gradient used, as the stem routes already left it, and solved on that route.leaf_gradient_batch() uses a step you name wherever it takes a finite difference (method = "fd", or a pinned row under "auto"), as leaf_gradient() does; it used to ignore it there (#219).operating_collar(), billed_outputs_at()) refuses a leaf with the energy balance on. It held leaf temperature at the solve's value, so its rows differed from a difference of the solve, by up to the whole row (#224).evaluate_psi_stem_at()) now reports that point's marginal cost of water (lambda_emergent); it used to report the value left over from the previous solve. Nothing else changes.leaf_gradient_batch() now refuses prices the way leaf_solve() does: a price the chosen model does not use is an error, and so is model = "TF24_floor" without TF24_floor_lambda_o, instead of an error in every row.leaf_solve() takes one price for all rows and refuses a vector; for a price per observation, use leaf_batch(), which now accepts one (#207).Leaf::stem_capacity_floor is removed (#199).Full notes: git show d972042:NEWS.md.
collar_at is operating_collar and outputs_at is billed_outputs_at; the full list is in the PRs). Results and the R interface are unchanged (#195, #198).set_drivers() refuses a vapour-pressure deficit at or below zero or above saturation, and drivers that would heat a leaf past what the model can evaluate; the old clamp of leaf temperature to −40–70 °C, with leaf_temp_min and leaf_temp_max, is gone. A stem potential outside the feasible range and a negative damage state are refused too, and leaf_gradient() reports "refused" where it said "clamped". Results change only near the old clamps (#191).psi_crit, so a leaf that was held there can open further; SOX, JW26, CF77 and LeastCost still stop at psi_crit. The statuses "boundary-crit" and "boundary-root-crit" become "boundary-dry", and the integer codes of later statuses shift. For C++ users, supply_psi_crit, root_psi_crit_at, invert_stem_curve*, eval_stem_curve and closed_form::PastLastKnot are removed (#188).Full notes: git show v0.26.2:NEWS.md.
align_curves()): JS22_gamma 1.0 → 0.4718, CMax_a 0.6 → 0.6386, and CF77_lambda_ and LeastCost_beta, which had no default, now 107751 and 51.60. Set the old values to reproduce earlier JS22 and CMax results; TF24's results do not change. The documentation is now a website (#179).g_min, the cuticular conductance: the water a leaf loses through its surface with the stomata shut (default 0; leaf_traits(g_min = )). leaf_solve() and operating_point() gain a last column, residual_flux. For C++ users, set_traits() takes g_min as its sixteenth argument and the parameter numbering shifts (n_theta is 35). At g_min = 0 an open leaf is unchanged (#185)."shade-death" is removed (later codes shift), as are set_shutdown_state(), ci_assigned(), the no_flow_*() functions and root_limit_binds_first(); closed leaves' values change (#185).impair_H_, impair_Tmid_, k_i_Tref_, m_rep_, t_rep_cut_ and $logistic_(); added: k_i_Tiso_, k_rec_Ea_ and k_mat_Ea_; k_i_ and k_i_baseline_ default to 276 per day (were 0.5). The damage layer is off by default, so nothing else changes (#186)."determined" is removed (later codes shift) and respiration_temp_deriv() is temp_deriv(); only closed leaves change (#177).Full notes: git show v0.26.2:NEWS.md.
transpiration(), stom_cond_CO2() and psi_stem_to_ci() refuse a stem wetter than the soil instead of returning a negative flow. The solver never asks for one, so results are unchanged (#181).model_registry() lists every equation and parameter with its units, source and the code that evaluates it (#168).ci and A are unchanged), its soil-moisture factor stays between 0 and 1, and a leaf at zero deficit no longer returns Inf (#130).adjoint_scalar, supply_derivatives, with_slope<T>, set_direction), and Leaf::pair<T> is replaced by odelia::with_slope<T>. Results are unchanged (#164).Full notes: git show v0.26.2:NEWS.md.
lambda_emergent is the chosen model's marginal cost of water; it was always TF24's (wrong by up to 146% for CF77). The unused fields count, psi_stem, opt_ci_ and f_r are removed from R. With the energy balance on, stem optima move very slightly (#171).closed_form_integral() and closed_form_curve() gain an argument, removed again in 0.21.0 (#160).gb_H2O (the boundary layer's conductance) and gs_stomatal_H2O (the stomata's own); gs_H2O is still the total. With the energy balance on, LeastCost's lambda_emergent changes slightly (#169, #170).LeastCost (Prentice et al. 2014, which minimises the cost per unit of carbon gained), with a dimensionless LeastCost_beta. For C++ users the parameter numbering shifts (n_theta is 35), so a hand-written theta needs the extra entry (#137).Full notes: git show v0.15.4:NEWS.md.
longwave_net_offset is removed; if you overwrite ra_ with a combined convective and radiative resistance, set g_rad_ to 0 as well (#120).a is renamed phi_J, the quantum yield per absorbed photon: leaf_traits(a = x) becomes leaf_traits(phi_J = x / 0.85), and likewise in Leaf(), set_traits(), l$a and leaf_gradient(pars = "a"). New absorptances alpha_PAR_ (0.85) and alpha_NIR_ (0.20), and PPFD is the light the leaf intercepts. At the defaults nothing changes (#162).l$NIR_int_, the near-infrared the leaf intercepts (about PPFD / 4.57 in daylight, 0 under LEDs), or set_physiology() refuses. The leaf absorbs less radiation (345 W m⁻² instead of 657 at PPFD 1500) and runs a median 7.9 °C cooler. sw_abs_per_par is removed (#162).use_thermal_damage_, off by default) tracks how much of the leaf is functional, impaired and damaged as its temperature varies, with $damage_rates(), leaf_damage_trajectory() and leaf_damage_gradient(). For C++ users its inputs join the parameter numbering, so a hand-filled theta must recount. Off, nothing changes (#162).Full notes: git show v0.15.4:NEWS.md.
odelia (>= 0.8.0)) rather than a pinned one, so a package using both pins odelia once; no code changes (#153, #154, #155).vignette("derivative-surface")); requires odelia 0.7.0 or later (#136).vulnerability_curve_ncontrol is 400, was 100), so results move slightly; a leaf held at a bound is placed more precisely, and leaf_gradient(method = "ift") refuses one by name (#136).evaluate_root_collar_psi and dprofit_droot_collar_psi use the chosen model rather than always TF24, and a replayed point hands plant the same derivatives its solve did (#136).Full notes: git show v0.10.3:NEWS.md.
root_network_from_carbon() takes a vector of widths and layer_thickness() is layer_thicknesses(); a graded profile had up to 3.7 times the root resistance it should (#134, #135, #141, #144).leaf_solve() reports the chosen model's lambda_emergent (its lambda column is always TF24's), and a reused leaf no longer carries a price over from a closed leaf before it (#133).TF24_floor, TF24 plus a price of water TF24_floor_lambda_o; leaf_solve() and leaf_batch() take the prices; set_model() takes a method, where "closed" is a fast approximation for TF24 and CF77; and CF77 can close as the soil dries, set through theta, theta_fc and theta_w (#128, #131, #132).l$set_model(curve, route) and solve with l$optimise(), which replace the per-model functions; leaf_solve() and leaf_gradient() take model =; every model reports lambda_emergent; plot_model_overview() draws the model (#126).leaf_supply_single() is leaf_supply_singlelayer(); the vulnerability traits are stem_P50, stem_c, root_P50 and root_c (convert a published curve with weibull_p50_c()), with stem_b, psi_crit, root_b and root_psi_crit derived; beta2, cost_scale_TF24 and lambda_ are TF24_beta2, TF24_cost_scale and CF77_lambda_; evaluate_psi_stem_by() and dprofit_dpsi_stem_by() are evaluate_psi_stem_at() and dprofit_dpsi_stem_checked(); perturb_stem_b() is perturb_stem_P50(); the statuses PinnedWet/PinnedDry are "boundary-soil"/"boundary-crit". Removed: the prescribed-lambda Sperry optimiser, profitmax_scan_n_ and leaf_behaviour_fingerprint() (#126).Full notes: git show v0.10.3:NEWS.md.
lambda_ is an input that nothing overwrites; a closed leaf reports one leaf temperature, which changes energy-balance results at shutdown; the unused field lambda_analytical_ is removed (#111, #117, #118).Tleaf and gs_H2O are outputs and the H₂O:CO₂ diffusion ratio can be set; the exact gas constant and molar mass of water move results slightly (#101, #102, #103, #106, #108).R_d_25 is a trait and respiration rises with temperature (rd_to_vcmax_ratio_ is removed); diffusion is driven by the leaf-to-air vapour-pressure deficit, which lowers gs and A with the energy balance on; the vulnerability curves cover their full range, which moves results; Sperry's ProfitMax model; trait gradients; traits can be read back (#86, #89, #90, #93, #99).Leaf, leaf_solve(), leaf_supply_singlelayer(), leaf_gradient(), leaf_gradient_batch()); set_physiology() takes root resistances instead of root carbon; the solver finds the optimum more precisely, which moves results (#30, #36, #47, #63).set_physiology() takes 10 arguments, not 14; every water potential is a positive number (a magnitude), so root_collar_psi_ is opt_root_psi_ and dE_from_soil_dpsi_collar returns a positive conductance; mass_root_prop is root_carbon_per_leaf_area, per unit leaf area; b and c are stem_b and stem_c, and g1_TF24 is cost_scale_TF24 (#29).Full notes: git show v0.10.3:NEWS.md.