A fully-worked example: soil nutrients and plant growth
The following code demonstrates the key functionality of Bristlecone, using a real-world example. Specifically, it demonstrates model-fitting and model-selection for the mechanisms controlling nutrient limitation to shrub individuals in the Arctic tundra.
The hypotheses are tested on a per-shrub basis. For each shrub, there are four components that may vary in the model, which when multiplied together results in 12 possible combinations of mechanisms for each shrub.
First, we must load Bristlecone.
open Bristlecone // Opens Bristlecone core library and estimation engine
open Bristlecone.Language // Open the language for writing Bristlecone models
open Bristlecone.Time
Defining a 'base model'
Then, we define a base model
system, into which we can nest
the components that vary (which represent different hypotheses).
Our base model consists of the following parts:
- An empirical transform. As this model uses long-term ecological data, there is a function that translates from an ecological proxy (stable nitrogen isotope) into the desired variable - soil nitrogen availability.
- Two ordinary differential equations (ODEs). These represent the soil N availability and plant biomass through time.
- A measurement variable. Bristlecone 'measurements' are effectively derived time-series that are calulated from the integrated ODE output. Here, we use a measurement variable to transform biomass into wood ring production, where rings are only produced where plant biomass has increased during the year.
The code for the parts of the base model is shown below.
// Empirical transform from δ15N to N availability.
let ``δ15N -> N availability`` =
(Constant 100. * Environment "N" + Constant 309.) / Constant 359.
// ODE1. Cumulative stem biomass
let ``db/dt`` geom nLimitation =
Parameter "r" * (geom This) * This * (nLimitation ``δ15N -> N availability``)
- Parameter "γ[b]" * This
// ODE2. Soil nitrogen availability
let ``dN/dt`` geom feedback limitationName nLimitation =
if limitationName = "None" then
Parameter "λ" - Parameter "γ[N]" * ``δ15N -> N availability`` + feedback This
else
Parameter "λ" - Parameter "γ[N]" * ``δ15N -> N availability`` + feedback This
- (geom This) * This * (nLimitation ``δ15N -> N availability``)
// Measurement variable: stem radius
let stemRadius lastRadius lastEnv env =
let oldCumulativeMass = lastEnv |> lookup "bs"
let newCumulativeMass = env |> lookup "bs"
if (newCumulativeMass - oldCumulativeMass) > 0. then
newCumulativeMass |> Allometric.Proxies.toRadiusMM // NB Allometrics is given in full in the downloadable script.
else
lastRadius
Once we have defined the components, we can scaffold them into a model system. We can plug in the nestable hypotheses (defined further below) by defining the base model as a function that takes parameters representing the alternative hypotheses.
let ``base model`` geometricConstraint plantSoilFeedback (nLimitMode, nLimitation) =
Model.empty
|> Model.addEquation "bs" (``db/dt`` geometricConstraint nLimitation)
|> Model.addEquation "N" (``dN/dt`` geometricConstraint plantSoilFeedback nLimitMode nLimitation)
|> Model.includeMeasure "x" stemRadius
|> Model.estimateParameter "λ" notNegative 0.001 0.500
|> Model.estimateParameter "γ[N]" notNegative 0.001 0.200
|> Model.estimateParameter "γ[b]" notNegative 0.001 0.200
|> Model.useLikelihoodFunction (ModelLibrary.Likelihood.bivariateGaussian "x" "N")
|> Model.estimateParameter "ρ" noConstraints -0.500 0.500
|> Model.estimateParameter "σ[x]" notNegative 0.001 0.100
|> Model.estimateParameter "σ[y]" notNegative 0.001 0.100
Defining the competing hypotheses
Here, we define 12 alternative hypotheses by defining three interchangeable components:
- Asymptotic plant size (2 types);
- Plant-soil feedback presence / absence (2 types); and
- Nitrogen limitation form (3 types).
Once we have defined each of the three components, we can take the
product of them with the base model which forms 12
alternative hypotheses, each represented as a ModelSystem
.
Geometric constraint
Plants do not grow indefinitely, but eventually reach an asymptotic mass owing either to geometric or resource constraints. Here, we define two competing hypotheses: that a shrub does not show evidence of nearing its asymptote, or that it does (based on a Chapman-Richards growth function).
In Bristlecone, we use modelComponent
to construct a pluggable component
into a model system. We pass modelComponent
a list of subComponent
s, which
each have a name and an equation. In its equation, a model component can
take one or many parameters, but these must match the signiture required
by the hole in the base model. For example, the geometric constraint here
takes the current mass
only.
In addition, a subComponent
may require additional estimatable parameters
over the base model. In this case, the Chapman-Richards model requires an
extra parameter K, which represents the asymptotic biomass. These may be
added to a subComponent
by using |> estimateParameter
afterwards, as below.
let ``geometric constraint`` =
modelComponent
"Geometric constraint"
[ subComponent "None" (Constant 1. |> (*))
subComponent "Chapman-Richards" (fun mass -> Constant 1. - (mass / (Parameter "k" * Constant 1000.)))
|> estimateParameter "k" notNegative 3.00 5.00 ] // Asymptotic biomass (in kilograms)
Plant-soil feedback
The plant-soil feedback is the flow of nutrients from plant biomass into the
soil available nitrogen pool. Here, we effectively turn on or off N input into
the soil pool on biomass loss. In the base model, density-dependent biomass
loss occurs. Turning on the feedback here creates an N input into soil based
on the biomass lost multiplied by a conversion factor ɑ
.
let ``plant-soil feedback`` =
let biomassLoss biomass =
(Parameter "ɑ" / Constant 100.) * biomass * Parameter "γ[b]"
modelComponent
"Plant-Soil Feedback"
[ subComponent "None" (Constant 1. |> (*))
subComponent "Biomass Loss" biomassLoss
|> estimateParameter "ɑ" notNegative 0.01 1.00 ] // N-recycling efficiency
Nitrogen limitation
We specify three plausable mechanisms for nutrient limitation to shrub growth: (1) that growth is independent on soil N availability; (2) that growth is dependent on soil N availability in a linear way; or (3) that a mechanistic model of root-foraging (saturating) best represents N-limitation of shrub growth.
A new concept here is the Conditional
element in an equation. This
term exposes a ModelExpression -> float
(compute), allowing a calculation
to be conditional on the state of parameters or values. In this example,
we use it to restrict the models such that the N-limiting effect cannot
be zero.
let ``N-limitation to growth`` =
let saturating minimumNutrient nutrient =
let hollingModel n =
(Parameter "a" * n)
/ (Constant 1. + (Parameter "a" (** Parameter "b"*) * Parameter "h" * n))
Conditional
<| fun compute ->
if compute (hollingModel minimumNutrient) < 1e-12 then
Invalid
else
hollingModel nutrient
let linear min resource =
Conditional
<| fun compute ->
if compute (Parameter "a" * min) < 1e-12 then
Invalid
else
Parameter "a" * resource
modelComponent
"N-limitation"
[ subComponent "Saturating" (saturating (Constant 5.))
|> estimateParameter "a" notNegative 0.100 0.400
|> estimateParameter "h" notNegative 0.100 0.400
|> estimateParameter "r" notNegative 0.500 1.000
subComponent "Linear" (linear (Constant 5.))
|> estimateParameter "a" notNegative 0.100 0.400
|> estimateParameter "r" notNegative 0.500 1.000
subComponent "None" (Constant 1. |> (*))
|> estimateParameter "r" notNegative 0.500 1.000 ]
Putting the hypotheses together
let hypotheses =
``base model``
|> Hypotheses.createFromComponent ``geometric constraint``
|> Hypotheses.useAnother ``plant-soil feedback``
|> Hypotheses.useAnotherWithName ``N-limitation to growth``
|> Hypotheses.compile
The resultant hypotheses (each of which is a Hypotheses.Hypothesis
) are:
|
Setting up a Bristlecone engine
A bristlecone engine provides a fixed setup for estimating parameters from data. We use the same engine for all model fits within a single study.
Here, we scaffold an engine from Bristlecone.mkContinuous
, as we are working
with continuous-time models.
Note. In a non-docs environment, we may choose to use a logger for this
example that outputs real-time traces in graphical format using ggplot
in R
.
To do this, we can call withOutput
with Logging.RealTimeTrace.graphWithConsole 60. 10000
to use the graphics functions from the Bristlecone.Charts.R
package.
let output = Logging.Console.logger 1000
let engine =
Bristlecone.mkContinuous
|> Bristlecone.withContinuousTime Integration.MathNet.integrate
|> Bristlecone.withOutput output
|> Bristlecone.withConditioning Conditioning.RepeatFirstDataPoint
|> Bristlecone.withCustomOptimisation (
Optimisation.MonteCarlo.SimulatedAnnealing.fastSimulatedAnnealing
0.01
true
{ Optimisation.MonteCarlo.SimulatedAnnealing.AnnealSettings<float>.Default with
InitialTemperature = 100.
TemperatureCeiling = Some 100.
HeatRamp = (fun t -> t + 5.00)
BoilingAcceptanceRate = 0.85
HeatStepLength = Optimisation.EndConditions.afterIteration 1000
TuneLength = 1000
AnnealStepLength =
(fun x n ->
Optimisation.MonteCarlo.SimulatedAnnealing.EndConditions.improvementCount 5000 250 x n
|| Optimisation.EndConditions.afterIteration 10000 x n) }
)
Testing the engine and model
Running a full test is strongly recommended. The test will demonstrate if the current configuration can find known parameters for a model. If this step fails, there is an issue with either your model, or the Bristlecone configuration.
let testSettings =
Test.create
|> Test.addNoise (Test.Noise.tryAddNormal "σ[y]" "N")
|> Test.addNoise (Test.Noise.tryAddNormal "σ[x]" "bs")
|> Test.addGenerationRules
[ Test.GenerationRules.alwaysMoreThan -3. "N"
Test.GenerationRules.alwaysLessThan 20. "N"
Test.GenerationRules.alwaysMoreThan 0. "bs"
Test.GenerationRules.monotonicallyIncreasing "x" ] // There must be at least 10mm of wood production
|> Test.addStartValues [ "x", 5.0; "bs", 5.0<Dendro.mm> |> Allometric.Proxies.toBiomassMM; "N", 3.64 ]
|> Test.withTimeSeriesLength 30
|> Test.endWhen (Optimisation.EndConditions.afterIteration 1000)
let testResult =
hypotheses
|> List.map ((fun h -> h.Model) >> Bristlecone.testModel engine testSettings)
Load in the real dataset
Here, we are using the Bristlecone.Dendro package to
read in dendroecological data. For other problems, any
method to wrangle the data into a TimeSeries
is acceptable.
open Bristlecone.Dendro
let dataset =
let plants =
Data.PlantIndividual.loadRingWidths (__SOURCE_DIRECTORY__ + "/../data/yamal-rw.csv")
let isotopeData =
Data.PlantIndividual.loadLocalEnvironmentVariable (__SOURCE_DIRECTORY__ + "/../data/yuribei-d15N-imputed.csv")
plants |> PlantIndividual.zipEnvMany "N" isotopeData
Model-fitting to real data
In this step, we will apply our EstimationEngine
to the real
shrub data and model hypotheses.
Because there are so many hypotheses (x12) and individuals (x10),
and we want to run replicate analyses (x3), it makes sense to
run these 360 workloads in parallel. To do this, we can make use of
the workflow tools in the Bristlecone.Workflow
namespace.
An orchestration agent is an agent that queues and runs work items in parallel. Below, we demonstrate setting up an agent:
open Bristlecone.Workflow
let orchestrator =
Orchestration.OrchestrationAgent(
writeOut = output,
maxSimultaneous = System.Environment.ProcessorCount,
retainResults = false
)
Before we can run the models, there are some specific considerations required for this problem.
Setting the start values
Given time-series data, a common modelling problem is the question of what to set t = 0 as. One strategy is to repeat the first data point (t1) as t0. In this instance, out isotope time-series are shorter than the ring-width time-series, so we generally know the real value of one time-series but not the other. Because of this, we use a custom start point for each shrub individual.
let startValues (startDate: System.DateTime) (plant: PlantIndividual.PlantIndividual) =
let removeUnit (x: float<_>) = float x
let initialRadius =
match plant.Growth with
| PlantIndividual.PlantGrowth.RingWidth s ->
match s with
| GrowthSeries.Cumulative c ->
let trimmed = c |> TimeSeries.trimStart (startDate - System.TimeSpan.FromDays(366.))
match trimmed with
| Some t -> t.Values |> Seq.head
| None -> failwith "Could not get t0 from ring-width series"
| _ -> invalidOp "Not applicable"
| _ -> invalidOp "Not applicable"
let initialMass = initialRadius |> Allometric.Proxies.toBiomassMM
let initialNitrogen = plant.Environment.[(code "N").Value].Head |> fst
[ ((code "x").Value, initialRadius |> removeUnit)
((code "N").Value, initialNitrogen)
((code "bs").Value, initialMass) ]
|> Map.ofList
Next, we set up some configuration settings, then wrap up our hypotheses and shrubs
as work packages for the orchestrator, where a work package is a Async<ModelSystem.EstimationResult>
.
The function to make the work packages first sets up the common time period and custom start values for each shrub, then creates per-hypothesis work packages for that shrub.
module Config =
let numberOfReplicates = 3
let resultsDirectory = "results/test/"
let thinTrace = Some 100
let endWhen = Optimisation.EndConditions.afterIteration 100000
// Function to scaffold work packages
let workPackages shrubs (hypotheses: Hypotheses.Hypothesis list) engine saveDirectory =
seq {
for s in shrubs do
// 1. Arrange the subject and settings
let shrub = s |> PlantIndividual.toCumulativeGrowth
let common = shrub |> PlantIndividual.keepCommonYears
let startDate = (common.Environment.[(code "N").Value]).StartDate |> snd
let startConditions = startValues startDate shrub
let e = engine |> Bristlecone.withConditioning (Conditioning.Custom startConditions)
// 2. Setup batches of dependent analyses
for h in hypotheses do
for _ in [ 1 .. Config.numberOfReplicates ] do
yield
async {
// A. Compute result
let result =
Bristlecone.tryFit e Config.endWhen (Bristlecone.fromDendro common) h.Model
// B. Save to file
match result with
| Ok r ->
Bristlecone.Data.EstimationResult.saveAll
saveDirectory
s.Identifier.Value
h.ReferenceCode
Config.thinTrace
r
return r
| Error e -> return failwithf "Error in package: %s" e
}
}
let work = workPackages dataset hypotheses engine Config.resultsDirectory
// Calling this function will run all of the analyses, but for this
// example script we won't run them here.
let run () =
work
|> Seq.iter (Orchestration.OrchestrationMessage.StartWorkPackage >> orchestrator.Post)
Model selection
After calling run ()
, we should have a folder containing csv files, three
for each EstimationResult
. We can load all of these in at once to
calculate model comparison statistics.
Functions for loading data are in the Bristlecone.Data
namespace. You
may notice that in the work package definition above we used functions from
this namespace to save the results.
let saveDiagnostics () =
// 1. Get all results sliced by plant and hypothesis
let results =
let get (subject: PlantIndividual.PlantIndividual) (hypothesis: Hypotheses.Hypothesis) =
Bristlecone.Data.EstimationResult.loadAll
Config.resultsDirectory
subject.Identifier.Value
hypothesis.Model
hypothesis.ReferenceCode
Bristlecone.ModelSelection.ResultSet.arrangeResultSets dataset hypotheses get
// 2. Save convergence statistics to file
results
|> Diagnostics.Convergence.gelmanRubinAll
10000
(fun (s: PlantIndividual.PlantIndividual) -> s.Identifier.Value)
(fun (h: Hypotheses.Hypothesis) -> h.ReferenceCode)
|> Data.Convergence.save Config.resultsDirectory
// 3. Save Akaike weights to file
results
|> ModelSelection.Akaike.akaikeWeightsForSet (fun (h: Hypotheses.Hypothesis) -> h.ReferenceCode)
|> Seq.map (fun (x, a, b, c) -> x.Identifier.Value, a, b, c)
|> Data.ModelSelection.save Config.resultsDirectory
// // 4. Save out logged components
// results
// |> Seq.map(fun r ->
// Diagnostics.ModelComponents.calculateComponents fit engine r)
// 5. One-step ahead predictions
let bestFits =
Seq.allPairs dataset hypotheses
|> Seq.map (fun (s, h) ->
s, h, Bristlecone.Data.MLE.loadBest Config.resultsDirectory s.Identifier.Value h.Model h.ReferenceCode)
let oneStepPredictions =
bestFits
|> Seq.map (fun (s, h, mle) ->
// 0. Convert x into biomass
let preTransform (data: CodedMap<TimeSeries<float>>) =
data
|> Map.toList
|> List.collect (fun (k, v) ->
if k.Value = "x" then
[ (k, v)
((code "bs").Value,
v |> TimeSeries.map (fun (x, _) -> x * 1.<mm> |> Allometric.Proxies.toBiomassMM)) ]
else
[ (k, v) ])
|> Map.ofList
// 1. Arrange the subject and settings (same as in model-fitting)
let shrub = s |> PlantIndividual.toCumulativeGrowth
let common = shrub |> PlantIndividual.keepCommonYears
let startDate = (common.Environment.[(code "N").Value]).StartDate |> snd
let startConditions = startValues startDate shrub
let e =
engine
|> Bristlecone.withConditioning (Bristlecone.Conditioning.Custom startConditions)
let result =
Bristlecone.oneStepAhead e h.Model preTransform (Bristlecone.fromDendro common) (mle |> snd |> snd)
// Save each n-step ahead result to a csv file
Bristlecone.Data.NStepAhead.save
Config.resultsDirectory
s.Identifier.Value
h.ReferenceCode
(mle |> fst)
1
result
s.Identifier.Value, h.ReferenceCode, result)
Bristlecone.Data.NStepAhead.saveAllRMSE Config.resultsDirectory oneStepPredictions
()
module Bristlecone from Bristlecone
--------------------
namespace Bristlecone
<summary>Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions.</summary>
<summary>Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π.</summary>
val double: value: 'T -> double (requires member op_Explicit)
--------------------
type double = System.Double
--------------------
type double<'Measure> = float<'Measure>
Gives the basal radius in centimetres of a stem/branch given its length in centimetres. Function from Niklas and Spatz (2004).
The basal radius is always positive.
Inverse equation of basalRadius.
Total shrub volume given height and number of stems
val float: value: 'T -> float (requires member op_Explicit)
--------------------
type float = System.Double
--------------------
type float<'Measure> = float
<summary> Statistics for determining the root of non-linear equations. </summary>
<summary> Bisect method for finding root of non-linear equations. </summary>
Radius in millimetres
Biomass in grams.
<summary>Represents a double-precision floating-point number.</summary>
<summary> An F# Domain Specific Language (DSL) for scripting with Bristlecone. </summary>
union case ModelExpression.Parameter: string -> ModelExpression
--------------------
module Parameter from Bristlecone
<summary> Terms for scaffolding a model system for use with Bristlecone. </summary>
<summary>Likelihood functions to represent a variety of distributions and data types.</summary>
<namespacedoc><summary>Pre-built model parts for use in Bristlecone</summary></namespacedoc>
<summary> Log likelihood function for dual simultaneous system, assuming Gaussian error for both x and y. Requires parameters 'σ[x]', 'σ[y]' and 'ρ' to be included in any `ModelSystem` that uses it. </summary>
<summary> Creates a nested component that can be inserted into a base model. </summary>
<summary>Types to represent a hypothesis, given that a hypothesis is a model system that contains some alternate formulations of certain components.</summary>
<summary>Implement a component where a model system requires one. A component is a part of a model that may be varied, for example between competing hypotheses.</summary>
<param name="comp">A tuple representing a component scaffolded with the `modelComponent` and `subComponent` functions.</param>
<param name="builder">A builder started with `createFromComponent`</param>
<typeparam name="'a"></typeparam>
<typeparam name="'b"></typeparam>
<returns>A builder to add further components or compile with `Hypothesis.compile`</returns>
<summary>Add a second or further component to a model system where one is still required.</summary>
<param name="comp">A tuple representing a component scaffolded with the `modelComponent` and `subComponent` functions.</param>
<param name="builder">A builder started with `createFromComponent`</param>
<typeparam name="'a"></typeparam>
<typeparam name="'b"></typeparam>
<returns>A builder to add further components or compile with `Hypothesis.compile`</returns>
<summary>Add a second or further component to a model system where one is still required.</summary>
<param name="comp">A tuple representing a component scaffolded with the `modelComponent` and `subComponent` functions.</param>
<param name="builder">A builder started with `createFromComponent`</param>
<typeparam name="'a"></typeparam>
<typeparam name="'b"></typeparam>
<returns>A builder to add further components or compile with `Hypothesis.compile`</returns>
<summary>Compiles a suite of competing model hypotheses based on the given components. The compilation includes only the required parameters in each model hypothesis, and combines all labels into a single model identifier.</summary>
<param name="builder">A builder started with `createFromComponent`</param>
<returns>A list of compiled hypotheses for this model system and specified components.</returns>
module Seq from Bristlecone
--------------------
module Seq from Microsoft.FSharp.Collections
<summary>Compiles a reference code that may be used to identify (although not necessarily uniquely) this hypothesis</summary>
<returns>A string in the format XX_XXX_YY_YYY... where XX_XXX is a singe component with XX the component and XXX the implementation.</returns>
<summary> Simple logger to console that prints line-by-line progress and events. </summary>
<summary> A simple console logger. `nIteration` specifies the number of iterations after which to log the current likelihood and parameter values. </summary>
<summary>A basic estimation engine for ordinary differential equations, using a Nelder-Mead optimiser.</summary>
<summary> Use a custom integration method </summary>
<summary>Substitute a specific logger into</summary>
<param name="out"></param>
<param name="engine"></param>
<typeparam name="'a"></typeparam>
<typeparam name="'b"></typeparam>
<returns></returns>
<summary> Choose how the start point is chosen when solving the model system </summary>
<summary> A module containing Monte Carlo Markov Chain (MCMC) methods for optimisation. An introduction to MCMC approaches is provided by [Reali, Priami, and Marchetti (2017)](https://doi.org/10.3389/fams.2017.00006) </summary>
<summary> A meta-heuristic that approximates a global optimium by simulating slow cooling as a slow decrease in the probability of temporarily accepting worse solutions. </summary>
<summary> Candidate distribution: Cauchy univariate [] Probability: Bottzmann Machine </summary>
<summary> Represents configurable settings of an annealing procedure that supports (a) heating, followed by (b) annealing. </summary>
<summary> End the optimisation procedure when a minimum number of iterations is exceeded. </summary>
module Test from Bristlecone.Language
<summary> Terms for designing tests for model systems. </summary>
--------------------
module Test from Bristlecone
<summary> Add noise to a particular time-series when generating fake time-series. Built-in noise functions are in the `Noise` module. </summary>
<summary> Functions for adding background variability into test problems. </summary>
<summary> Adds normally-distributed noise around each data point in the selected time-series. Returns `None` if the series or parameter does not exist. </summary>
<summary> Ensures that all generated values are greater than i </summary>
<summary> Ensures that all generated values are less than i </summary>
<summary> Ensures that there is always a positive change in values of a variable </summary>
<summary> Adds start values to the test settings. Overwrites any existing start values that may already exist. </summary>
Radius in millimetres
module List from Bristlecone
--------------------
module List from Microsoft.FSharp.Collections
--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
<summary>Test that the specified estimation engine can correctly estimate known parameters. Random parameter sets are generated from the given model system.</summary>
<param name="engine">An estimation engine containing the method used for model-fitting.</param>
<param name="settings">Test settings that define how the test will be conducted.</param>
<param name="model">The model system to test against the estimation engine.</param>
<returns>A test result that indicates differences between the expected and actual fit.</returns>
namespace Bristlecone.Data
--------------------
namespace Microsoft.FSharp.Data
<summary> Assigns local environmental conditions to each plant in a sequence, given a sequence of environmental time-series where each time-series has the code of the plant associated with it. </summary>
<summary> Queue functions to manage many work packages in parallel. [ Inspired by Tom Petricek: http://fssnip.net/nX ] </summary>
type OrchestrationAgent = new: writeOut: (LogEvent -> unit) * maxSimultaneous: int * retainResults: bool -> OrchestrationAgent member Post: msg: OrchestrationMessage -> unit member TryGetResult: unit -> EstimationResult option
<summary> The `OrchestrationAgent` queues work items of the type `Async<EstimationResult>`, which are run in parallel up to a total of `maxSimultaneous` at one time. </summary>
--------------------
new: writeOut: (Logging.LogEvent -> unit) * maxSimultaneous: int * retainResults: bool -> Orchestration.OrchestrationAgent
<summary>Provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited.</summary>
<summary>Gets the number of processors available to the current process.</summary>
<returns>The 32-bit signed integer that specifies the number of processors that are available.</returns>
[<Struct>] type DateTime = new: year: int * month: int * day: int -> unit + 10 overloads member Add: value: TimeSpan -> DateTime member AddDays: value: float -> DateTime member AddHours: value: float -> DateTime member AddMilliseconds: value: float -> DateTime member AddMinutes: value: float -> DateTime member AddMonths: months: int -> DateTime member AddSeconds: value: float -> DateTime member AddTicks: value: int64 -> DateTime member AddYears: value: int -> DateTime ...
<summary>Represents an instant in time, typically expressed as a date and time of day.</summary>
--------------------
System.DateTime ()
(+0 other overloads)
System.DateTime(ticks: int64) : System.DateTime
(+0 other overloads)
System.DateTime(ticks: int64, kind: System.DateTimeKind) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, calendar: System.Globalization.Calendar) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: System.DateTimeKind) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: System.Globalization.Calendar) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: System.DateTimeKind) : System.DateTime
(+0 other overloads)
module TimeSeries from Bristlecone.Time
--------------------
type TimeSeries<'T> = TimeSeries.TimeSeries<'T>
<summary> Remove all time points that occur before the desired start date. </summary>
[<Struct>] type TimeSpan = new: hours: int * minutes: int * seconds: int -> unit + 3 overloads member Add: ts: TimeSpan -> TimeSpan member CompareTo: value: obj -> int + 1 overload member Divide: divisor: float -> TimeSpan + 1 overload member Duration: unit -> TimeSpan member Equals: value: obj -> bool + 2 overloads member GetHashCode: unit -> int member Multiply: factor: float -> TimeSpan member Negate: unit -> TimeSpan member Subtract: ts: TimeSpan -> TimeSpan ...
<summary>Represents a time interval.</summary>
--------------------
System.TimeSpan ()
System.TimeSpan(ticks: int64) : System.TimeSpan
System.TimeSpan(hours: int, minutes: int, seconds: int) : System.TimeSpan
System.TimeSpan(days: int, hours: int, minutes: int, seconds: int) : System.TimeSpan
System.TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : System.TimeSpan
<summary> A short code representation of an identifier for a parameter, model equation, or other model component. </summary>
module Map from Bristlecone
--------------------
module Map from Microsoft.FSharp.Collections
--------------------
type Map<'Key,'Value (requires comparison)> = interface IReadOnlyDictionary<'Key,'Value> interface IReadOnlyCollection<KeyValuePair<'Key,'Value>> interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable<KeyValuePair<'Key,'Value>> interface ICollection<KeyValuePair<'Key,'Value>> interface IDictionary<'Key,'Value> new: elements: ('Key * 'Value) seq -> Map<'Key,'Value> member Add: key: 'Key * value: 'Value -> Map<'Key,'Value> ...
--------------------
new: elements: ('Key * 'Value) seq -> Map<'Key,'Value>
union case Hypotheses.Hypothesis.Hypothesis: ModelSystem.ModelSystem * Hypotheses.ComponentName list -> Hypotheses.Hypothesis
--------------------
type Hypothesis = | Hypothesis of ModelSystem * ComponentName list member Components: ComponentName list member Model: ModelSystem member ReferenceCode: string
<summary>A hypothesis consists of a model system and the names of the swappable components within it, alongside the name of their current implementation.</summary>
val seq: sequence: 'T seq -> 'T seq
--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
<summary> Where a plant has associated environmental data, discard the beginning or end of the growth and environment time-series where not all data are present. </summary>
<summary> Fit a time-series model to data. Please note: it is strongly recommended that you test that the given `EstimationEngine` can correctly identify known parameters for your model. Refer to the `Bristlecone.testModel` function, which can be used to generate known data and complete this process. </summary>
<param name="engine">The engine encapsulates all settings that form part of the estimation method. Importantly, this includes the random number generator used for all stages of the analysis; if this is set using a fixed seed, the result will be reproducable.</param>
<param name="endCondition">You must specify a stopping condition, after which the optimisation process will cease. Bristlecone includes built-in end conditions in the `Bristlecone.Optimisation.EndConditions` module.</param>
<param name="timeSeriesData"></param>
<param name="model"></param>
<returns></returns>
<summary>Lower time-series data from a plant individual type into basic time-series that may be used for model-fitting</summary>
<param name="plant">A plant individual</param>
<returns>A coded map of time-series data for model-fitting</returns>
<summary>Save the Maximum Likelihood Estimate, trace of the optimisation procedure, and time-series.</summary>
<param name="directory">Relative or absolute directory to save files to</param>
<param name="subject">An identifier for the subject of the test</param>
<param name="modelId">An identifier for the model used</param>
<param name="thinTraceBy">If Some, an integer representing the nth traces to keep from the optimisation trace. If None, does not thin the trace.</param>
<param name="result">The estimation result to save</param>
<summary> Load an `EstimationResult` that has previously been saved as three seperate dataframes. Results will only be reconstructed when file names and formats are in original Bristlecone format. </summary>
<summary>Contains tools for conducting Model Selection across individual subjects and hypotheses.</summary>
<summary>Organises multiple hypotheses and multiple subjects into distinct analysis groups.</summary>
<summary>Arrange estimation results into subject and hypothesis groups.</summary>
<param name="subjects"></param>
<param name="hypotheses"></param>
<param name="getResults"></param>
<typeparam name="'subject"></typeparam>
<typeparam name="'hypothesis"></typeparam>
<typeparam name="'a">An estimation result</typeparam>
<returns></returns>
<summary>Diagnostic techniques for determining the suitability of results obtained with Bristlecone.</summary>
<summary>Convergence diagnostics for monte-carlo markov chain (MCMC) analyses.</summary>
<summary>Calculate the Gelman-Rubin statistic for each parameter in all of the given `ResultSet`. The statistic tends downwards to one, with one indicating perfect convergence between all chains.</summary>
<param name="nMostRecent">How many recent iterations to use from the trace.</param>
<param name="subject">A function to retrieve a subject ID from a subject</param>
<param name="hypothesis">A function to retrieve a hypothesis ID from a hypothesis</param>
<param name="result">A result set (of 1 .. many results) for a particular subject and hypothesis</param>
<returns>If more than one replicate, the R-hat convergence statistic across replicates</returns>
<summary>Functions for conducting Akaike Information Criterion (AIC).</summary>
<summary>Akaike weights for a result set.</summary>
<param name="getRefCode">A function that gets a short reference code from a hypothesis.</param>
<param name="set">A sequence of `ResultSet`s, within each the 1 .. many results of a particular subject * hypothesis combination.</param>
<returns>An `(EstimationResult * float) seq` of estimation results paired to their Akaike weights.</returns>
<exception cref="ArgumentException">Occurs when there are no observations within an estimation result.</exception>
<summary>Functions of loading and saving Maximum Likelihood Estimates from model fits</summary>
<summary>Load the Maximum Likelihood Estimate (with the lowest -log Liklihood) from the given directory for a given subject and model combination.</summary>
<param name="directory">The results folder where files are saved</param>
<param name="subject">An identifier for the subject of the fit</param>
<param name="modelId">An identifier for the model that was fit</param>
<returns>A tuple containing the analysis ID followed by another tuple that contains the likelihood and theta (parameter set)</returns>
<summary> Map a function to each value in the time series. </summary>
<summary>Addresses the question: "How good am I at predicting the next data point?. Given fitted parameters, assesses how well the model predicts the next data point from each point in the time-series data. This approach can provide another indication of model performance.</summary>
<param name="engine">The exact estimation engine used for the existing model fit</param>
<param name="hypothesis">The exact model system / hypothesis from which parameters have been already estimated</param>
<param name="preTransform">A function that may transform each shorter time-series before prediction. This may be needed, for example, if there are custom start values that need to be configured in a complex way (e.g. for derived mesaurement variables).</param>
<param name="timeSeries">The observed data to predict against.</param>
<param name="estimatedTheta">A parameter pool containing already estimated parameters from model fitting step</param>
<returns>A time-series for each variable containing a step-ahead prediction</returns>
<summary>Loads and saves one-step-ahead and n-step-ahead prediction results into and out of simple CSV files</summary>
<summary>Save an individual n-step prediction (excluding statistics) for an individual subject and hypothesis / model.</summary>
<param name="directory">The file directory to save to</param>
<param name="subjectId">Subject ID</param>
<param name="modelId">Model ID or Hypothesis ID</param>
<param name="analysisId">The unique reference of the estimation result used to generate n-step predictions</param>
<param name="stepsAhead">The number of time-steps ahead predicted</param>
<param name="result">The n-step prediction from Bristlecone.oneStepAhead or similar</param>
<summary>Saves a full ensemble overview of the root mean squared error of n-step ahead predictions.</summary>
<param name="directory">The file directory to save to</param>
<param name="results">A sequence of subjectID * hypothesisID * n-step result</param>