diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 5d9fa6667..94597bd6f 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.9.3","generation_timestamp":"2023-10-10T18:49:36","documenter_version":"1.1.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.9.3","generation_timestamp":"2023-10-13T20:19:20","documenter_version":"1.1.1"}} \ No newline at end of file diff --git a/dev/API/DataContainers/index.html b/dev/API/DataContainers/index.html index 23fb3a6a7..4b21cd941 100644 --- a/dev/API/DataContainers/index.html +++ b/dev/API/DataContainers/index.html @@ -1,2 +1,2 @@ -DataContainers · EnsembleKalmanProcesses.jl

DataContainers

Base.sizeFunction
size(c<:ConstraintType)

A constraint has size 1.

source
size(dc::DataContainer, idx::IT) where {IT <: Integer}

Returns the size of the stored data. If idx provided, it returns the size along dimension idx.

source
size(pdc::PairedDataContainer, idx::IT) where {IT <: Integer}

Returns the sizes of the inputs and ouputs along dimension idx (if provided).

source
+DataContainers · EnsembleKalmanProcesses.jl

DataContainers

Base.sizeFunction
size(c<:ConstraintType)

A constraint has size 1.

source
size(dc::DataContainer, idx::IT) where {IT <: Integer}

Returns the size of the stored data. If idx provided, it returns the size along dimension idx.

source
size(pdc::PairedDataContainer, idx::IT) where {IT <: Integer}

Returns the sizes of the inputs and ouputs along dimension idx (if provided).

source
diff --git a/dev/API/EnsembleKalmanProcess/index.html b/dev/API/EnsembleKalmanProcess/index.html index da7a7be04..7ec4eee7c 100644 --- a/dev/API/EnsembleKalmanProcess/index.html +++ b/dev/API/EnsembleKalmanProcess/index.html @@ -10,12 +10,12 @@ failure_handler_method::FM = IgnoreFailures(), localization_method::LM = NoLocalization(), verbose::Bool = false, -) where {FT <: AbstractFloat, P <: Process, FM <: FailureHandlingMethod, LM <: LocalizationMethod}

Inputs:

Other constructors:

EnsembleKalmanProcess(u, obs_mean, obs_noise_cov, N_ens, g, err, scheduler, accelerator, Δt, process, rng, failure_handler, localizer, verbose)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:117.

EnsembleKalmanProcess(params, obs_mean, obs_noise_cov, process)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:147.

EnsembleKalmanProcess(obs_mean, obs_noise_cov, process)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:223.

source
EnsembleKalmanProcesses.FailureHandlerType
FailureHandler{P <: Process, FM <: FailureHandlingMethod}

Structure defining the failure handler method used in the EnsembleKalmanProcess.

Fields

  • failsafe_update::Function

    Failsafe algorithmic update equation

Constructors

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:10.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:22.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:31.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:17.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:29.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:40.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:52.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:235.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:254.

source
EnsembleKalmanProcesses.SampleSuccGaussType

" SampleSuccGauss <: FailureHandlingMethod

Failure handling method that substitutes failed ensemble members by new samples from the empirical Gaussian distribution defined by the updated successful ensemble.

source
EnsembleKalmanProcesses.IgnoreFailuresType

Failure handling method that ignores forward model failures

source
EnsembleKalmanProcesses.get_uFunction
get_u(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}

Returns the unconstrained parameters at the given iteration. Returns a DataContainer object unless return_array is true.

source
get_u(ekp::EnsembleKalmanProcess; return_array=true)

Returns the unconstrained parameters from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.

source
EnsembleKalmanProcesses.get_gFunction
get_g(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}

Returns the forward model evaluations at the given iteration. Returns a DataContainer object unless return_array is true.

source
get_g(ekp::EnsembleKalmanProcess; return_array=true)

Returns the forward model evaluations from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.

source
EnsembleKalmanProcesses.get_ϕFunction
get_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)

Returns the constrained parameters at the given iteration.

source
get_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)

Returns the constrained parameters from all iterations. The outer dimension is given by the number of iterations.

source
EnsembleKalmanProcesses.get_u_finalFunction
get_u_final(ekp::EnsembleKalmanProcess, return_array=true)

Get the unconstrained parameters at the last iteration, returning a DataContainer Object if return_array is false.

source
EnsembleKalmanProcesses.get_g_finalFunction
get_g_final(ekp::EnsembleKalmanProcess, return_array=true)

Get forward model outputs at the last iteration, returns a DataContainer Object if return_array is false.

source
EnsembleKalmanProcesses.get_ϕ_finalFunction
get_ϕ_final(ekp::EnsembleKalmanProcess)

Get the constrained parameters at the last iteration.

source
EnsembleKalmanProcesses.get_u_meanFunction
get_u_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}

Returns the mean unconstrained parameter at the given iteration.

source
get_u_mean(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)

Returns the mean unconstrained parameter at the requested iteration.

source
EnsembleKalmanProcesses.get_u_covFunction
get_u_cov(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}

Returns the unconstrained parameter sample covariance at the given iteration.

source
get_u_cov(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)

Returns the unconstrained parameter covariance at the requested iteration.

source
EnsembleKalmanProcesses.get_g_meanFunction
get_g_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}

Returns the mean forward map evaluation at the given iteration.

source
EnsembleKalmanProcesses.get_ϕ_meanFunction
get_ϕ_mean(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)

Returns the constrained transform of the mean unconstrained parameter at the given iteration.

source
EnsembleKalmanProcesses.get_u_mean_finalFunction
get_u_mean_final(ekp::EnsembleKalmanProcess)

Get the mean unconstrained parameter at the last iteration.

source
EnsembleKalmanProcesses.get_u_cov_finalFunction
get_u_cov_final(ekp::EnsembleKalmanProcess)

Get the mean unconstrained parameter covariance at the last iteration.

source
EnsembleKalmanProcesses.get_g_mean_finalFunction
get_g_mean_final(ekp::EnsembleKalmanProcess)

Get the mean forward model evaluation at the last iteration.

source
EnsembleKalmanProcesses.get_ϕ_mean_finalFunction
get_ϕ_mean_final(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)

Get the constrained transform of the mean unconstrained parameter at the last iteration.

source
EnsembleKalmanProcesses.compute_error!Function
compute_error!(ekp::EnsembleKalmanProcess)

Computes the covariance-weighted error of the mean forward model output, (ḡ - y)'Γ_inv(ḡ - y). The error is stored within the EnsembleKalmanProcess.

source
EnsembleKalmanProcesses.get_errorFunction
get_error(ekp::EnsembleKalmanProcess)

Returns the mean forward model output error as a function of algorithmic time.

source
EnsembleKalmanProcesses.get_N_iterationsFunction
get_N_iterations(ekp::EnsembleKalmanProcess)

Get number of times update has been called (equals size(g), or size(u)-1).

source
EnsembleKalmanProcesses.construct_initial_ensembleFunction
construct_initial_ensemble(
+) where {FT <: AbstractFloat, P <: Process, FM <: FailureHandlingMethod, LM <: LocalizationMethod}

Inputs:

  • params :: Initial parameter ensemble
  • obs_mean :: Vector of observations
  • obs_noise_cov :: Noise covariance associated with the observations obs_mean
  • process :: Algorithm used to evolve the ensemble
  • scheduler :: Adaptive timestep calculator
  • Δt :: Initial time step or learning rate
  • rng :: Random number generator
  • failure_handler_method :: Method used to handle particle failures
  • localization_method :: Method used to localize sample covariances
  • verbose :: Whether to print diagnostic information

Other constructors:

EnsembleKalmanProcess(u, obs_mean, obs_noise_cov, N_ens, g, err, scheduler, accelerator, Δt, process, rng, failure_handler, localizer, verbose)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:117.

EnsembleKalmanProcess(params, obs_mean, obs_noise_cov, process)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:147.

EnsembleKalmanProcess(obs_mean, obs_noise_cov, process)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:223.

source
EnsembleKalmanProcesses.FailureHandlerType
FailureHandler{P <: Process, FM <: FailureHandlingMethod}

Structure defining the failure handler method used in the EnsembleKalmanProcess.

Fields

  • failsafe_update::Function

    Failsafe algorithmic update equation

Constructors

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:10.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:22.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:31.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:17.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:29.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:40.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:52.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:236.

FailureHandler(process, method)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:255.

source
EnsembleKalmanProcesses.SampleSuccGaussType

" SampleSuccGauss <: FailureHandlingMethod

Failure handling method that substitutes failed ensemble members by new samples from the empirical Gaussian distribution defined by the updated successful ensemble.

source
EnsembleKalmanProcesses.IgnoreFailuresType

Failure handling method that ignores forward model failures

source
EnsembleKalmanProcesses.get_uFunction
get_u(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}

Returns the unconstrained parameters at the given iteration. Returns a DataContainer object unless return_array is true.

source
get_u(ekp::EnsembleKalmanProcess; return_array=true)

Returns the unconstrained parameters from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.

source
EnsembleKalmanProcesses.get_gFunction
get_g(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}

Returns the forward model evaluations at the given iteration. Returns a DataContainer object unless return_array is true.

source
get_g(ekp::EnsembleKalmanProcess; return_array=true)

Returns the forward model evaluations from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.

source
EnsembleKalmanProcesses.get_ϕFunction
get_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)

Returns the constrained parameters at the given iteration.

source
get_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)

Returns the constrained parameters from all iterations. The outer dimension is given by the number of iterations.

source
EnsembleKalmanProcesses.get_u_finalFunction
get_u_final(ekp::EnsembleKalmanProcess, return_array=true)

Get the unconstrained parameters at the last iteration, returning a DataContainer Object if return_array is false.

source
EnsembleKalmanProcesses.get_g_finalFunction
get_g_final(ekp::EnsembleKalmanProcess, return_array=true)

Get forward model outputs at the last iteration, returns a DataContainer Object if return_array is false.

source
EnsembleKalmanProcesses.get_ϕ_finalFunction
get_ϕ_final(ekp::EnsembleKalmanProcess)

Get the constrained parameters at the last iteration.

source
EnsembleKalmanProcesses.get_u_meanFunction
get_u_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}

Returns the mean unconstrained parameter at the given iteration.

source
get_u_mean(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)

Returns the mean unconstrained parameter at the requested iteration.

source
EnsembleKalmanProcesses.get_u_covFunction
get_u_cov(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}

Returns the unconstrained parameter sample covariance at the given iteration.

source
get_u_cov(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)

Returns the unconstrained parameter covariance at the requested iteration.

source
EnsembleKalmanProcesses.get_g_meanFunction
get_g_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}

Returns the mean forward map evaluation at the given iteration.

source
EnsembleKalmanProcesses.get_ϕ_meanFunction
get_ϕ_mean(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)

Returns the constrained transform of the mean unconstrained parameter at the given iteration.

source
EnsembleKalmanProcesses.get_u_mean_finalFunction
get_u_mean_final(ekp::EnsembleKalmanProcess)

Get the mean unconstrained parameter at the last iteration.

source
EnsembleKalmanProcesses.get_u_cov_finalFunction
get_u_cov_final(ekp::EnsembleKalmanProcess)

Get the mean unconstrained parameter covariance at the last iteration.

source
EnsembleKalmanProcesses.get_g_mean_finalFunction
get_g_mean_final(ekp::EnsembleKalmanProcess)

Get the mean forward model evaluation at the last iteration.

source
EnsembleKalmanProcesses.get_ϕ_mean_finalFunction
get_ϕ_mean_final(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)

Get the constrained transform of the mean unconstrained parameter at the last iteration.

source
EnsembleKalmanProcesses.compute_error!Function
compute_error!(ekp::EnsembleKalmanProcess)

Computes the covariance-weighted error of the mean forward model output, (ḡ - y)'Γ_inv(ḡ - y). The error is stored within the EnsembleKalmanProcess.

source
EnsembleKalmanProcesses.get_errorFunction
get_error(ekp::EnsembleKalmanProcess)

Returns the mean forward model output error as a function of algorithmic time.

source
EnsembleKalmanProcesses.get_N_iterationsFunction
get_N_iterations(ekp::EnsembleKalmanProcess)

Get number of times update has been called (equals size(g), or size(u)-1).

source
EnsembleKalmanProcesses.construct_initial_ensembleFunction
construct_initial_ensemble(
     rng::AbstractRNG,
     prior::ParameterDistribution,
     N_ens::IT
 ) where {IT <: Int}
-construct_initial_ensemble(prior::ParameterDistribution, N_ens::IT) where {IT <: Int}

Construct the initial parameters, by sampling N_ens samples from specified prior distribution. Returned with parameters as columns.

source
EnsembleKalmanProcesses.update_ensemble!Function
update_ensemble!(
+construct_initial_ensemble(prior::ParameterDistribution, N_ens::IT) where {IT <: Int}

Construct the initial parameters, by sampling N_ens samples from specified prior distribution. Returned with parameters as columns.

source
EnsembleKalmanProcesses.update_ensemble!Function
update_ensemble!(
     ekp::EnsembleKalmanProcess,
     g::AbstractMatrix{FT};
     multiplicative_inflation::Bool = false,
@@ -23,36 +23,36 @@
     use_prior_cov::Bool = false,
     s::FT = 0.0,
     ekp_kwargs...,
-) where {FT, IT}

Updates the ensemble according to an Inversion process. Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • multiplicative_inflation :: Flag indicating whether to use multiplicative inflation.
  • additive_inflation :: Flag indicating whether to use additive inflation.
  • usepriorcov :: Bool specifying whether to use prior covariance estimate for additive inflation. If false (default), parameter covariance from the current iteration is used.
  • s :: Scaling factor for time step in inflation step.
  • ekpkwargs :: Keyword arguments to pass to standard ekp updateensemble!.
source
update_ensemble!(
+) where {FT, IT}

Updates the ensemble according to an Inversion process. Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • multiplicative_inflation :: Flag indicating whether to use multiplicative inflation.
  • additive_inflation :: Flag indicating whether to use additive inflation.
  • usepriorcov :: Bool specifying whether to use prior covariance estimate for additive inflation. If false (default), parameter covariance from the current iteration is used.
  • s :: Scaling factor for time step in inflation step.
  • ekpkwargs :: Keyword arguments to pass to standard ekp updateensemble!.
source
update_ensemble!(
     ekp::EnsembleKalmanProcess{FT, IT, Inversion},
     g::AbstractMatrix{FT},
     process::Inversion;
     deterministic_forward_map::Bool = true,
     failed_ens = nothing,
-) where {FT, IT}

Updates the ensemble according to an Inversion process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • deterministicforwardmap :: Whether output g comes from a deterministic model.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
+) where {FT, IT}

Updates the ensemble according to an Inversion process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • deterministicforwardmap :: Whether output g comes from a deterministic model.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
     ekp::EnsembleKalmanProcess{FT, IT, TransformInversion},
     g::AbstractMatrix{FT},
     process::TransformInversion;
     failed_ens = nothing,
-) where {FT, IT}

Updates the ensemble according to a TransformInversion process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
+) where {FT, IT}

Updates the ensemble according to a TransformInversion process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
     ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},
     g::AbstractMatrix{FT},
     process::SparseInversion{FT};
     deterministic_forward_map = true,
     failed_ens = nothing,
-) where {FT, IT}

Updates the ensemble according to a SparseInversion process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • deterministic_forward_map :: Whether output g comes from a deterministic model.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
+) where {FT, IT}

Updates the ensemble according to a SparseInversion process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • deterministic_forward_map :: Whether output g comes from a deterministic model.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
     ekp::EnsembleKalmanProcess{FT, IT, Sampler{FT}},
     g::AbstractMatrix{FT},
     process::Sampler{FT};
     failed_ens = nothing,
-) where {FT, IT}

Updates the ensemble according to a Sampler process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
+) where {FT, IT}

Updates the ensemble according to a Sampler process.

Inputs:

  • ekp :: The EnsembleKalmanProcess to update.
  • g :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
update_ensemble!(
     uki::EnsembleKalmanProcess{FT, IT, Unscented},
     g_in::AbstractMatrix{FT},
     process::Unscented;
     failed_ens = nothing,
-) where {FT <: AbstractFloat, IT <: Int}

Updates the ensemble according to an Unscented process.

Inputs:

  • uki :: The EnsembleKalmanProcess to update.
  • g_in :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
EnsembleKalmanProcesses.sample_empirical_gaussianFunction
sample_empirical_gaussian(
+) where {FT <: AbstractFloat, IT <: Int}

Updates the ensemble according to an Unscented process.

Inputs:

  • uki :: The EnsembleKalmanProcess to update.
  • g_in :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).
  • process :: Type of the EKP.
  • failed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.
source
EnsembleKalmanProcesses.sample_empirical_gaussianFunction
sample_empirical_gaussian(
     u::AbstractMatrix{FT},
     n::IT;
     inflation::Union{FT, Nothing} = nothing,
-) where {FT <: Real, IT <: Int}

Returns n samples from an empirical Gaussian based on point estimates u, adding inflation if the covariance is singular.

source
EnsembleKalmanProcesses.split_indices_by_successFunction
 split_indices_by_success(g::AbstractMatrix{FT}) where {FT <: Real}

Returns the successful/failed particle indices given a matrix with output vectors stored as columns. Failures are defined for particles containing at least one NaN output element.

source

Learning Rate Schedulers

EnsembleKalmanProcesses.DefaultSchedulerType
struct DefaultScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler containing a default constant step size, users can override this temporarily within update_ensemble!.

  • Δt_default::Any

    step size

source
EnsembleKalmanProcesses.MutableSchedulerType
struct MutableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler containing a mutable constant step size, users can override this permanently within update_ensemble!.

  • Δt_mutable::Vector

    mutable step size

source
EnsembleKalmanProcesses.EKSStableSchedulerType
struct EKSStableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler known to be stable for EKS, In particular, $\Delta t = \frac{\alpha}{\|U\| + \varepsilon}$ where $U = (G(u) - \bar{G(u)})^T\Gamma^{-1}(G(u) - y)$. Cannot be overriden.

  • numerator::Any

    the numerator $\alpha$

  • nugget::Any

    the nugget term $\varepsilon$

source
EnsembleKalmanProcesses.DataMisfitControllerType
struct DataMisfitController{FT, M, S} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler from Iglesias, Yang, 2021, Based on Bayesian Tempering. Terminates at T=1 by default, and at this time, ensemble spread provides a (more) meaningful approximation of posterior uncertainty In particular, for parameters $\theta_j$ at step $n$, to calculate the next timestep $\Delta t_n = \min\left(\max\left(\frac{J}{2\Phi}, \sqrt{\frac{J}{2\langle \Phi, \Phi \rangle}}\right), 1-\sum^{n-1}_i t_i\right)$ where $\Phi_j = \|\Gamma^{-\frac{1}{2}}(G(\theta_j) - y)\|^2$. Cannot be overriden by user provided timesteps. By default termination returns true from update_ensemble! and

  • if on_terminate == "stop", stops further iteration.
  • if on_terminate == "continue_fixed", continues iteration with the final timestep fixed
  • if on_terminate == "continue", continues the algorithm (though no longer compares to $1-\sum^{n-1}_i t_i$)

The user may also change the T with terminate_at keyword.

  • iteration::Vector{Int64}

    the current iteration

  • inv_sqrt_noise::Vector

    the inverse square-root of the noise covariance is stored

  • terminate_at::Any

    the algorithm time for termination, default: 1.0

  • on_terminate::Any

    the action on termination, default: "stop",

source
EnsembleKalmanProcesses.calculate_timestep!Function
calculate_timestep!(ekp::EnsembleKalmanProcess, g::AbstractMatrix, Δt_new::Union{Nothing, AbstractFloat}) -> Any
-

Calculates next timestep by pushing to ekp.Δt, !isnothing(return_value) implies termination condition has been met

source
+) where {FT <: Real, IT <: Int}

Returns n samples from an empirical Gaussian based on point estimates u, adding inflation if the covariance is singular.

source
EnsembleKalmanProcesses.split_indices_by_successFunction
 split_indices_by_success(g::AbstractMatrix{FT}) where {FT <: Real}

Returns the successful/failed particle indices given a matrix with output vectors stored as columns. Failures are defined for particles containing at least one NaN output element.

source

Learning Rate Schedulers

EnsembleKalmanProcesses.DefaultSchedulerType
struct DefaultScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler containing a default constant step size, users can override this temporarily within update_ensemble!.

  • Δt_default::Any

    step size

source
EnsembleKalmanProcesses.MutableSchedulerType
struct MutableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler containing a mutable constant step size, users can override this permanently within update_ensemble!.

  • Δt_mutable::Vector

    mutable step size

source
EnsembleKalmanProcesses.EKSStableSchedulerType
struct EKSStableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler known to be stable for EKS, In particular, $\Delta t = \frac{\alpha}{\|U\| + \varepsilon}$ where $U = (G(u) - \bar{G(u)})^T\Gamma^{-1}(G(u) - y)$. Cannot be overriden.

  • numerator::Any

    the numerator $\alpha$

  • nugget::Any

    the nugget term $\varepsilon$

source
EnsembleKalmanProcesses.DataMisfitControllerType
struct DataMisfitController{FT, M, S} <: EnsembleKalmanProcesses.LearningRateScheduler

Scheduler from Iglesias, Yang, 2021, Based on Bayesian Tempering. Terminates at T=1 by default, and at this time, ensemble spread provides a (more) meaningful approximation of posterior uncertainty In particular, for parameters $\theta_j$ at step $n$, to calculate the next timestep $\Delta t_n = \min\left(\max\left(\frac{J}{2\Phi}, \sqrt{\frac{J}{2\langle \Phi, \Phi \rangle}}\right), 1-\sum^{n-1}_i t_i\right)$ where $\Phi_j = \|\Gamma^{-\frac{1}{2}}(G(\theta_j) - y)\|^2$. Cannot be overriden by user provided timesteps. By default termination returns true from update_ensemble! and

  • if on_terminate == "stop", stops further iteration.
  • if on_terminate == "continue_fixed", continues iteration with the final timestep fixed
  • if on_terminate == "continue", continues the algorithm (though no longer compares to $1-\sum^{n-1}_i t_i$)

The user may also change the T with terminate_at keyword.

  • iteration::Vector{Int64}

    the current iteration

  • inv_sqrt_noise::Vector

    the inverse square-root of the noise covariance is stored

  • terminate_at::Any

    the algorithm time for termination, default: 1.0

  • on_terminate::Any

    the action on termination, default: "stop",

source
EnsembleKalmanProcesses.calculate_timestep!Function
calculate_timestep!(ekp::EnsembleKalmanProcess, g::AbstractMatrix, Δt_new::Union{Nothing, AbstractFloat}) -> Any
+

Calculates next timestep by pushing to ekp.Δt, !isnothing(return_value) implies termination condition has been met

source
diff --git a/dev/API/Inversion/index.html b/dev/API/Inversion/index.html index 81729a918..844958ba0 100644 --- a/dev/API/Inversion/index.html +++ b/dev/API/Inversion/index.html @@ -1,8 +1,8 @@ -Inversion · EnsembleKalmanProcesses.jl

Ensemble Kalman Inversion

EnsembleKalmanProcesses.eki_updateFunction
 eki_update(
+Inversion · EnsembleKalmanProcesses.jl

Ensemble Kalman Inversion

EnsembleKalmanProcesses.eki_updateFunction
 eki_update(
     ekp::EnsembleKalmanProcess{FT, IT, Inversion},
     u::AbstractMatrix{FT},
     g::AbstractMatrix{FT},
     y::AbstractMatrix{FT},
     obs_noise_cov::Union{AbstractMatrix{CT}, UniformScaling{CT}},
-) where {FT <: Real, IT, CT <: Real}

Returns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (4) and (5) of Schillings and Stuart (2017).

Localization is implemented following the ekp.localizer.

source
+) where {FT <: Real, IT, CT <: Real}

Returns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (4) and (5) of Schillings and Stuart (2017).

Localization is implemented following the ekp.localizer.

source
diff --git a/dev/API/Localizers/index.html b/dev/API/Localizers/index.html index 77ce1d28e..28e5de85d 100644 --- a/dev/API/Localizers/index.html +++ b/dev/API/Localizers/index.html @@ -1,8 +1,8 @@ Localizers · EnsembleKalmanProcesses.jl

Localizers

EnsembleKalmanProcesses.Localizers.LocalizerType
Localizer{LM <: LocalizationMethod, T}

Structure that defines a localize function, based on a localization method.

Fields

  • localize::Function

    Localizing function of the form: cov -> kernel .* cov

Constructors

Localizer(localization, p, d, J)
-Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:122.

Localizer(localization, p, d, J)
-Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:128.

Localizer(localization, p, d, J)
-Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:134.

Localizer(localization, p, d, J)
-Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:179.

Localizer(localization, p, d, J)
-Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:199.

Localizer(localization, p, d, J)
-Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:238.

source
EnsembleKalmanProcesses.Localizers.RBFType
RBF{FT <: Real} <: LocalizationMethod

Radial basis function localization method. Covariance terms $C_{i,j}$ are damped through multiplication with a centered Gaussian with standardized deviation $d(i,j)= \vert i-j \vert / l$.

Fields

  • lengthscale::Real

    Length scale defining the RBF kernel

source
EnsembleKalmanProcesses.Localizers.BernoulliDropoutType
BernoulliDropout{FT <: Real} <: LocalizationMethod

Localization method that drops cross-covariance terms with probability $1-p$, retaining a Hermitian structure.

Fields

  • prob::Real

    Probability of keeping a given cross-covariance term

source
EnsembleKalmanProcesses.Localizers.SECType
SEC{FT <: Real} <: LocalizationMethod

Sampling error correction that shrinks correlations by a factor of $\vert r \vert ^\alpha$, as per Lee (2021). Sparsity of the resulting correlations can be imposed through the parameter r_0.

Lee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341

Fields

  • α::Real

    Controls degree of sampling error correction

  • r_0::Real

    Cutoff correlation

source
EnsembleKalmanProcesses.Localizers.SECFisherType
SECFisher <: LocalizationMethod

Sampling error correction for EKI, as per Lee (2021), but using the method from Flowerdew (2015) based on the Fisher transformation. Correlations are shrinked by a factor determined by the sample correlation and the ensemble size.

Flowerdew, J. (2015). Towards a theory of optimal localisation. Tellus A: Dynamic Meteorology and Oceanography, 67(1), 25257. https://doi.org/10.3402/tellusa.v67.25257

Lee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341

source
+Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:122.

Localizer(localization, p, d, J)
+Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:128.

Localizer(localization, p, d, J)
+Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:134.

Localizer(localization, p, d, J)
+Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:179.

Localizer(localization, p, d, J)
+Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:199.

Localizer(localization, p, d, J)
+Localizer(localization, p, d, J, T)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:238.

source
EnsembleKalmanProcesses.Localizers.RBFType
RBF{FT <: Real} <: LocalizationMethod

Radial basis function localization method. Covariance terms $C_{i,j}$ are damped through multiplication with a centered Gaussian with standardized deviation $d(i,j)= \vert i-j \vert / l$.

Fields

  • lengthscale::Real

    Length scale defining the RBF kernel

source
EnsembleKalmanProcesses.Localizers.BernoulliDropoutType
BernoulliDropout{FT <: Real} <: LocalizationMethod

Localization method that drops cross-covariance terms with probability $1-p$, retaining a Hermitian structure.

Fields

  • prob::Real

    Probability of keeping a given cross-covariance term

source
EnsembleKalmanProcesses.Localizers.SECType
SEC{FT <: Real} <: LocalizationMethod

Sampling error correction that shrinks correlations by a factor of $\vert r \vert ^\alpha$, as per Lee (2021). Sparsity of the resulting correlations can be imposed through the parameter r_0.

Lee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341

Fields

  • α::Real

    Controls degree of sampling error correction

  • r_0::Real

    Cutoff correlation

source
EnsembleKalmanProcesses.Localizers.SECFisherType
SECFisher <: LocalizationMethod

Sampling error correction for EKI, as per Lee (2021), but using the method from Flowerdew (2015) based on the Fisher transformation. Correlations are shrinked by a factor determined by the sample correlation and the ensemble size.

Flowerdew, J. (2015). Towards a theory of optimal localisation. Tellus A: Dynamic Meteorology and Oceanography, 67(1), 25257. https://doi.org/10.3402/tellusa.v67.25257

Lee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341

source
EnsembleKalmanProcesses.Localizers.DeltaType

Dirac delta localization method, with an identity matrix as the kernel.

source
EnsembleKalmanProcesses.Localizers.NoLocalizationType

Idempotent localization method.

source
diff --git a/dev/API/Observations/index.html b/dev/API/Observations/index.html index f03e75a47..f1ddead9b 100644 --- a/dev/API/Observations/index.html +++ b/dev/API/Observations/index.html @@ -1,2 +1,2 @@ -Observations · EnsembleKalmanProcesses.jl

Observations

EnsembleKalmanProcesses.Observations.ObservationType
Observation{FT <: AbstractFloat}

Structure that contains the observations

Fields

  • samples::Array{Vector{FT}, 1} where FT<:AbstractFloat

    vector of observational samples, each of length sample_dim

  • obs_noise_cov::Union{Nothing, LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}, FT} where FT<:AbstractFloat

    covariance of the observational noise (assumed to be normally distributed); sample_dim x sample_dim (where sample_dim is the number of elements in each sample), or a scalar if the sample dim is 1. If not supplied, obs_noise_cov is set to a diagonal matrix whose non-zero elements are the variances of the samples, or to a scalar variance in the case of 1d samples. obs_noise_cov is set to nothing if only a single sample is provided.

  • mean::Union{AbstractVector{FT}, FT} where FT<:AbstractFloat

    sample mean

  • data_names::Union{String, AbstractVector{String}}

    names of the data

source
+Observations · EnsembleKalmanProcesses.jl

Observations

EnsembleKalmanProcesses.Observations.ObservationType
Observation{FT <: AbstractFloat}

Structure that contains the observations

Fields

  • samples::Array{Vector{FT}, 1} where FT<:AbstractFloat

    vector of observational samples, each of length sample_dim

  • obs_noise_cov::Union{Nothing, LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}, FT} where FT<:AbstractFloat

    covariance of the observational noise (assumed to be normally distributed); sample_dim x sample_dim (where sample_dim is the number of elements in each sample), or a scalar if the sample dim is 1. If not supplied, obs_noise_cov is set to a diagonal matrix whose non-zero elements are the variances of the samples, or to a scalar variance in the case of 1d samples. obs_noise_cov is set to nothing if only a single sample is provided.

  • mean::Union{AbstractVector{FT}, FT} where FT<:AbstractFloat

    sample mean

  • data_names::Union{String, AbstractVector{String}}

    names of the data

source
diff --git a/dev/API/ParameterDistributions/index.html b/dev/API/ParameterDistributions/index.html index 46d3e997e..94a6ec07f 100644 --- a/dev/API/ParameterDistributions/index.html +++ b/dev/API/ParameterDistributions/index.html @@ -1,5 +1,5 @@ -ParameterDistributions · EnsembleKalmanProcesses.jl

ParameterDistributions

ParameterDistributionTypes

EnsembleKalmanProcesses.ParameterDistributions.SamplesType
Samples{FT <: Real} <: ParameterDistributionType

A distribution comprised of only samples, stored as columns of parameters.

Fields

  • distribution_samples::AbstractMatrix{FT} where FT<:Real

    Samples defining an empirical distribution, stored as columns

source
EnsembleKalmanProcesses.ParameterDistributions.VectorOfParameterizedType
VectorOfParameterized <: ParameterDistributionType

A distribution built from an array of Parametrized distributions. A utility to help stacking of distributions where a multivariate equivalent doesn't exist.

Fields

  • distribution::AbstractVector{DT} where DT<:Distributions.Distribution

    A vector of parameterized distributions

source

Constraints

EnsembleKalmanProcesses.ParameterDistributions.ConstraintType
Constraint{T} <: ConstraintType

Class describing a 1D bijection between constrained and unconstrained spaces. Included parametric types for T:

  • NoConstraint
  • BoundedBelow
  • BoundedAbove
  • Bounded

Fields

  • constrained_to_unconstrained::Function

    A map from constrained domain -> (-Inf,Inf)

  • c_to_u_jacobian::Function

    The jacobian of the map from constrained domain -> (-Inf,Inf)

  • unconstrained_to_constrained::Function

    Map from (-Inf,Inf) -> constrained domain

  • bounds::Union{Nothing, Dict}

    Dictionary of values used to build the Constraint (e.g. "lowerbound" or "upperbound")

source
EnsembleKalmanProcesses.ParameterDistributions.boundedFunction
bounded(lower_bound::Real, upper_bound::Real)

Constructs a Constraint with provided upper and lower bounds, enforced by maps x -> log((x - lower_bound) / (upper_bound - x)) and x -> (upper_bound * exp(x) + lower_bound) / (exp(x) + 1).

source

ParameterDistributions

EnsembleKalmanProcesses.ParameterDistributions.ParameterDistributionType
ParameterDistribution

Structure to hold a parameter distribution, always stored as an array of distributions internally.

Fields

  • distribution::AbstractVector{PDType} where PDType<:EnsembleKalmanProcesses.ParameterDistributions.ParameterDistributionType

    Vector of parameter distributions, defined in unconstrained space

  • constraint::AbstractVector{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType

    Vector of constraints defining transformations between constrained and unconstrained space

  • name::AbstractVector{ST} where ST<:AbstractString

    Vector of parameter names

Constructors

ParameterDistribution(distribution, constraint, name)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:289.

ParameterDistribution(param_dist_dict)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:305.

ParameterDistribution(distribution, constraint, name)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:389.

ParameterDistribution(distribution_samples, constraint, name)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:431.

source
EnsembleKalmanProcesses.ParameterDistributions.constrained_gaussianFunction
constrained_gaussian(
+ParameterDistributions · EnsembleKalmanProcesses.jl

ParameterDistributions

ParameterDistributionTypes

EnsembleKalmanProcesses.ParameterDistributions.SamplesType
Samples{FT <: Real} <: ParameterDistributionType

A distribution comprised of only samples, stored as columns of parameters.

Fields

  • distribution_samples::AbstractMatrix{FT} where FT<:Real

    Samples defining an empirical distribution, stored as columns

source
EnsembleKalmanProcesses.ParameterDistributions.VectorOfParameterizedType
VectorOfParameterized <: ParameterDistributionType

A distribution built from an array of Parametrized distributions. A utility to help stacking of distributions where a multivariate equivalent doesn't exist.

Fields

  • distribution::AbstractVector{DT} where DT<:Distributions.Distribution

    A vector of parameterized distributions

source

Constraints

EnsembleKalmanProcesses.ParameterDistributions.ConstraintType
Constraint{T} <: ConstraintType

Class describing a 1D bijection between constrained and unconstrained spaces. Included parametric types for T:

  • NoConstraint
  • BoundedBelow
  • BoundedAbove
  • Bounded

Fields

  • constrained_to_unconstrained::Function

    A map from constrained domain -> (-Inf,Inf)

  • c_to_u_jacobian::Function

    The jacobian of the map from constrained domain -> (-Inf,Inf)

  • unconstrained_to_constrained::Function

    Map from (-Inf,Inf) -> constrained domain

  • bounds::Union{Nothing, Dict}

    Dictionary of values used to build the Constraint (e.g. "lowerbound" or "upperbound")

source
EnsembleKalmanProcesses.ParameterDistributions.boundedFunction
bounded(lower_bound::Real, upper_bound::Real)

Constructs a Constraint with provided upper and lower bounds, enforced by maps x -> log((x - lower_bound) / (upper_bound - x)) and x -> (upper_bound * exp(x) + lower_bound) / (exp(x) + 1).

source

ParameterDistributions

EnsembleKalmanProcesses.ParameterDistributions.ParameterDistributionType
ParameterDistribution

Structure to hold a parameter distribution, always stored as an array of distributions internally.

Fields

  • distribution::AbstractVector{PDType} where PDType<:EnsembleKalmanProcesses.ParameterDistributions.ParameterDistributionType

    Vector of parameter distributions, defined in unconstrained space

  • constraint::AbstractVector{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType

    Vector of constraints defining transformations between constrained and unconstrained space

  • name::AbstractVector{ST} where ST<:AbstractString

    Vector of parameter names

Constructors

ParameterDistribution(distribution, constraint, name)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:289.

ParameterDistribution(param_dist_dict)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:305.

ParameterDistribution(distribution, constraint, name)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:389.

ParameterDistribution(distribution_samples, constraint, name)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:431.

source
EnsembleKalmanProcesses.ParameterDistributions.constrained_gaussianFunction
constrained_gaussian(
     name::AbstractString,
     μ_c::Real,
     σ_c::Real,
@@ -8,4 +8,4 @@
     repeats = 1,
     optim_algorithm::Optim.AbstractOptimizer = NelderMead(),
     optim_kwargs...,
-)

Constructor for a 1D ParameterDistribution consisting of a transformed Gaussian, constrained to have support on [lower_bound, upper_bound], with first two moments μ_c and σ_c^2. The moment integrals can't be done in closed form, so we set the parameters of the distribution with numerical optimization.

Note

The intended use case is defining priors set from user expertise for use in inference with adequate data, so for the sake of performance we only require that the optimization reproduce μ_c, σ_c to a loose tolerance (1e-5). Warnings are logged when the optimization fails.

Note

The distribution may be bimodal for σ_c large relative to the width of the bound interval. In extreme cases the distribution becomes concentrated at the bound endpoints. We regard this as a feature, not a bug, and do not warn the user when bimodality occurs.

source
EnsembleKalmanProcesses.ParameterDistributions.batchFunction
batch(pd::ParameterDistribution; function_parameter_opt = "dof")

Returns a list of contiguous [collect(1:i), collect(i+1:j),... ] used to split parameter arrays by distribution dimensions. function_parameter_opt is passed to ndims in the special case of FunctionParameterDistributionTypes.

source
EnsembleKalmanProcesses.ParameterDistributions.get_distributionFunction
get_distribution(pd::ParameterDistribution)

Returns a Dict of ParameterDistribution distributions, with the parameter names as dictionary keys. For parameters represented by Samples, the samples are returned as a 2D (parameter_dimension x n_samples) array.

source

gets the, distribution over the coefficients

source
StatsBase.sampleFunction
sample([rng], pd::ParameterDistribution, [n_draws])

Draws n_draws samples from the parameter distributions pd. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
sample([rng], d::Samples, [n_draws])

Draws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
sample([rng], d::Parameterized, [n_draws])

Draws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
sample([rng], d::VectorOfParameterized, [n_draws])

Draws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
Distributions.logpdfFunction
logpdf(pd::ParameterDistribution, xarray::Array{<:Real,1})

Obtains the independent logpdfs of the parameter distributions at xarray (non-Samples Distributions only), and returns their sum.

source
Statistics.meanFunction
mean(pd::ParameterDistribution)

Returns a concatenated mean of the parameter distributions.

source
Statistics.varFunction
var(pd::ParameterDistribution)

Returns a flattened variance of the distributions

source
Statistics.covFunction
cov(pd::ParameterDistribution)

Returns a dense blocked (co)variance of the distributions.

source

FunctionParameterDistributions

EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterfaceType
struct GaussianRandomFieldInterface <: FunctionParameterDistributionType

GaussianRandomFieldInterface object based on a GRF package. Only a ND->1D output-dimension field interface is implemented.

Fields

  • gaussian_random_field::Any

    GRF object, containing the mapping from the field of coefficients to the discrete function

  • package::EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage

    the choice of GRF package

  • distribution::EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution

    the distribution of the coefficients that we shall compute with

source
Base.ndimsMethod
ndims(grfi::GaussianRandomFieldInterface, function_parameter_opt = "dof")

Provides a relevant number of dimensions in different circumstances, If function_parameter_opt =

  • "dof" : returns n_dofs(grfi), the degrees of freedom in the function
  • "eval" : returns n_eval_pts(grfi), the number of discrete evaluation points of the function
  • "constraint": returns 1, the number of constraints in the evaluation space
source
EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrainedMethod
transform_constrained_to_unconstrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatrix)

Assume x is a matrix with columns as flattened samples of evaluation points. Remove the constraint from constraint to the output space of the function. Note this is the inverse of transform_unconstrained_to_constrained(...,build_flag=false)

source
EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrainedMethod
transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractVector)

Optional Args build_flag::Bool = true

Two functions, depending on build_flag If true, assume x is a vector of coefficients. Perform the following 3 maps.

  1. Apply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)
  2. Build the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.
  3. Apply the constraint from constraint to the output space of the function.

If false, Assume x is a flattened vector of evaluation points. Apply only step 3. above to x.

source
EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrainedMethod
transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatri)

Optional args: build_flag::Bool = true

Two functions, depending on build_flag If true, assume x is a matrix with columns of coefficient samples. Perform the following 3 maps.

  1. Apply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)
  2. Build the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.
  3. Apply the constraint from constraint to the output space of the function.

If false, Assume x is a matrix with columns as flattened samples of evaluation points. Apply only step 3. above to x.

source
+)

Constructor for a 1D ParameterDistribution consisting of a transformed Gaussian, constrained to have support on [lower_bound, upper_bound], with first two moments μ_c and σ_c^2. The moment integrals can't be done in closed form, so we set the parameters of the distribution with numerical optimization.

Note

The intended use case is defining priors set from user expertise for use in inference with adequate data, so for the sake of performance we only require that the optimization reproduce μ_c, σ_c to a loose tolerance (1e-5). Warnings are logged when the optimization fails.

Note

The distribution may be bimodal for σ_c large relative to the width of the bound interval. In extreme cases the distribution becomes concentrated at the bound endpoints. We regard this as a feature, not a bug, and do not warn the user when bimodality occurs.

source
EnsembleKalmanProcesses.ParameterDistributions.batchFunction
batch(pd::ParameterDistribution; function_parameter_opt = "dof")

Returns a list of contiguous [collect(1:i), collect(i+1:j),... ] used to split parameter arrays by distribution dimensions. function_parameter_opt is passed to ndims in the special case of FunctionParameterDistributionTypes.

source
EnsembleKalmanProcesses.ParameterDistributions.get_distributionFunction
get_distribution(pd::ParameterDistribution)

Returns a Dict of ParameterDistribution distributions, with the parameter names as dictionary keys. For parameters represented by Samples, the samples are returned as a 2D (parameter_dimension x n_samples) array.

source

gets the, distribution over the coefficients

source
StatsBase.sampleFunction
sample([rng], pd::ParameterDistribution, [n_draws])

Draws n_draws samples from the parameter distributions pd. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
sample([rng], d::Samples, [n_draws])

Draws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
sample([rng], d::Parameterized, [n_draws])

Draws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
sample([rng], d::VectorOfParameterized, [n_draws])

Draws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.

source
Distributions.logpdfFunction
logpdf(pd::ParameterDistribution, xarray::Array{<:Real,1})

Obtains the independent logpdfs of the parameter distributions at xarray (non-Samples Distributions only), and returns their sum.

source
Statistics.meanFunction
mean(pd::ParameterDistribution)

Returns a concatenated mean of the parameter distributions.

source
Statistics.varFunction
var(pd::ParameterDistribution)

Returns a flattened variance of the distributions

source
Statistics.covFunction
cov(pd::ParameterDistribution)

Returns a dense blocked (co)variance of the distributions.

source

FunctionParameterDistributions

EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterfaceType
struct GaussianRandomFieldInterface <: FunctionParameterDistributionType

GaussianRandomFieldInterface object based on a GRF package. Only a ND->1D output-dimension field interface is implemented.

Fields

  • gaussian_random_field::Any

    GRF object, containing the mapping from the field of coefficients to the discrete function

  • package::EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage

    the choice of GRF package

  • distribution::EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution

    the distribution of the coefficients that we shall compute with

source
Base.ndimsMethod
ndims(grfi::GaussianRandomFieldInterface, function_parameter_opt = "dof")

Provides a relevant number of dimensions in different circumstances, If function_parameter_opt =

  • "dof" : returns n_dofs(grfi), the degrees of freedom in the function
  • "eval" : returns n_eval_pts(grfi), the number of discrete evaluation points of the function
  • "constraint": returns 1, the number of constraints in the evaluation space
source
EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrainedMethod
transform_constrained_to_unconstrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatrix)

Assume x is a matrix with columns as flattened samples of evaluation points. Remove the constraint from constraint to the output space of the function. Note this is the inverse of transform_unconstrained_to_constrained(...,build_flag=false)

source
EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrainedMethod
transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractVector)

Optional Args build_flag::Bool = true

Two functions, depending on build_flag If true, assume x is a vector of coefficients. Perform the following 3 maps.

  1. Apply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)
  2. Build the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.
  3. Apply the constraint from constraint to the output space of the function.

If false, Assume x is a flattened vector of evaluation points. Apply only step 3. above to x.

source
EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrainedMethod
transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatri)

Optional args: build_flag::Bool = true

Two functions, depending on build_flag If true, assume x is a matrix with columns of coefficient samples. Perform the following 3 maps.

  1. Apply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)
  2. Build the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.
  3. Apply the constraint from constraint to the output space of the function.

If false, Assume x is a matrix with columns as flattened samples of evaluation points. Apply only step 3. above to x.

source
diff --git a/dev/API/Sampler/index.html b/dev/API/Sampler/index.html index d462a63fc..3896e65f1 100644 --- a/dev/API/Sampler/index.html +++ b/dev/API/Sampler/index.html @@ -1,6 +1,6 @@ -Sampler · EnsembleKalmanProcesses.jl

Ensemble Kalman Sampler

EnsembleKalmanProcesses.SamplerType
Sampler{FT<:AbstractFloat,IT<:Int} <: Process

An ensemble Kalman Sampler process.

Fields

  • prior_mean::Vector{FT} where FT<:AbstractFloat

    Mean of Gaussian parameter prior in unconstrained space

  • prior_cov::Union{LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}} where FT<:AbstractFloat

    Covariance of Gaussian parameter prior in unconstrained space

Constructors

Sampler(prior_mean, prior_cov)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:17.

Sampler(prior)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:23.

source
EnsembleKalmanProcesses.eks_updateFunction
 eks_update(
+Sampler · EnsembleKalmanProcesses.jl

Ensemble Kalman Sampler

EnsembleKalmanProcesses.SamplerType
Sampler{FT<:AbstractFloat,IT<:Int} <: Process

An ensemble Kalman Sampler process.

Fields

  • prior_mean::Vector{FT} where FT<:AbstractFloat

    Mean of Gaussian parameter prior in unconstrained space

  • prior_cov::Union{LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}} where FT<:AbstractFloat

    Covariance of Gaussian parameter prior in unconstrained space

Constructors

Sampler(prior_mean, prior_cov)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:17.

Sampler(prior)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:23.

source
EnsembleKalmanProcesses.eks_updateFunction
 eks_update(
     ekp::EnsembleKalmanProcess{FT, IT, Sampler{FT}},
     u::AbstractMatrix{FT},
     g::AbstractMatrix{FT},
-) where {FT <: Real, IT}

Returns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the sampler algorithm.

The current implementation assumes that rows of u and g correspond to ensemble members, so it requires passing the transpose of the u and g arrays associated with ekp.

source
+) where {FT <: Real, IT}

Returns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the sampler algorithm.

The current implementation assumes that rows of u and g correspond to ensemble members, so it requires passing the transpose of the u and g arrays associated with ekp.

source
diff --git a/dev/API/SparseInversion/index.html b/dev/API/SparseInversion/index.html index 41213752e..f81868b6e 100644 --- a/dev/API/SparseInversion/index.html +++ b/dev/API/SparseInversion/index.html @@ -1,11 +1,11 @@ -SparseInversion · EnsembleKalmanProcesses.jl

Sparse Ensemble Kalman Inversion

EnsembleKalmanProcesses.SparseInversionType
SparseInversion <: Process

A sparse ensemble Kalman Inversion process

Fields

  • γ::AbstractFloat

    upper limit of l1-norm

  • threshold_value::AbstractFloat

    threshold below which the norm of parameters is pruned to zero

  • uc_idx::Union{Colon, AbstractVector}

    indices of parameters included in the evaluation of l1-norm constraint

  • reg::AbstractFloat

    a small regularization value to enhance robustness of convex optimization

Constructors

SparseInversion(γ, threshold_value, uc_idx, reg)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:21.

SparseInversion(γ)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:31.

SparseInversion()
source
EnsembleKalmanProcesses.sparse_eki_updateFunction
 sparse_eki_update(
+SparseInversion · EnsembleKalmanProcesses.jl

Sparse Ensemble Kalman Inversion

EnsembleKalmanProcesses.SparseInversionType
SparseInversion <: Process

A sparse ensemble Kalman Inversion process

Fields

  • γ::AbstractFloat

    upper limit of l1-norm

  • threshold_value::AbstractFloat

    threshold below which the norm of parameters is pruned to zero

  • uc_idx::Union{Colon, AbstractVector}

    indices of parameters included in the evaluation of l1-norm constraint

  • reg::AbstractFloat

    a small regularization value to enhance robustness of convex optimization

Constructors

SparseInversion(γ, threshold_value, uc_idx, reg)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:21.

SparseInversion(γ)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:31.

SparseInversion()
source
EnsembleKalmanProcesses.sparse_eki_updateFunction
 sparse_eki_update(
     ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},
     u::AbstractMatrix{FT},
     g::AbstractMatrix{FT},
     y::AbstractMatrix{FT},
     obs_noise_cov::Union{AbstractMatrix{CT}, UniformScaling{CT}},
-) where {FT <: Real, CT <: Real, IT}

Returns the sparse updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (3.7) and (3.14) of Schneider et al. (2021).

Localization is applied following Tong and Morzfeld (2022).

source
EnsembleKalmanProcesses.sparse_qpFunction
sparse_qp(
+) where {FT <: Real, CT <: Real, IT}

Returns the sparse updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (3.7) and (3.14) of Schneider et al. (2021).

Localization is applied following Tong and Morzfeld (2022).

source
EnsembleKalmanProcesses.sparse_qpFunction
sparse_qp(
     ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},
     v_j::Vector{FT},
     cov_vv_inv::AbstractMatrix{FT},
@@ -13,4 +13,4 @@
     H_g::SparseArrays.SparseMatrixCSC{FT},
     y_j::Vector{FT};
     H_uc::SparseArrays.SparseMatrixCSC{FT} = H_u,
-) where {FT, IT}

Solving quadratic programming problem with sparsity constraint.

source
+) where {FT, IT}

Solving quadratic programming problem with sparsity constraint.

source
diff --git a/dev/API/TOMLInterface/index.html b/dev/API/TOMLInterface/index.html index 2fc1db1bb..7db84db3e 100644 --- a/dev/API/TOMLInterface/index.html +++ b/dev/API/TOMLInterface/index.html @@ -4,7 +4,7 @@ iteration, member, pad_zeros = 3, -)

Obtains the file path to a specified ensemble member. The likely form is base_path/iteration_X/member_Y/ with X,Y padded with zeros. The file path can be reconstructed with: base_path - base path to where EKP parameters are stored member - number of the ensemble member (without zero padding) iteration - iteration of ensemble method (if =nothing then only the load path is used) pad_zeros - amount of digits to pad to

source

One can also call this without the iteration level

source
EnsembleKalmanProcesses.TOMLInterface.get_parameter_distributionFunction
get_parameter_distribution(param_dict, name)

Constructs a ParameterDistribution for a single parameter

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values name - parameter name

Returns a ParameterDistribution

source
get_parameter_distribution(param_dict, names)

Constructs a ParameterDistribution for an array of parameters

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values names - array of parameter names

Returns a ParameterDistribution

source
EnsembleKalmanProcesses.TOMLInterface.get_parameter_valuesFunction
get_parameter_values(param_dict, names)

Gets parameter values from a parameter dictionary, indexing by name.

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' values) name - iterable parameter names return_type - return type, default "dict", otherwise "array"

source
EnsembleKalmanProcesses.TOMLInterface.save_parameter_ensembleFunction
save_parameter_ensemble(
+)

Obtains the file path to a specified ensemble member. The likely form is base_path/iteration_X/member_Y/ with X,Y padded with zeros. The file path can be reconstructed with: base_path - base path to where EKP parameters are stored member - number of the ensemble member (without zero padding) iteration - iteration of ensemble method (if =nothing then only the load path is used) pad_zeros - amount of digits to pad to

source

One can also call this without the iteration level

source
EnsembleKalmanProcesses.TOMLInterface.get_parameter_distributionFunction
get_parameter_distribution(param_dict, name)

Constructs a ParameterDistribution for a single parameter

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values name - parameter name

Returns a ParameterDistribution

source
get_parameter_distribution(param_dict, names)

Constructs a ParameterDistribution for an array of parameters

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values names - array of parameter names

Returns a ParameterDistribution

source
EnsembleKalmanProcesses.TOMLInterface.get_parameter_valuesFunction
get_parameter_values(param_dict, names)

Gets parameter values from a parameter dictionary, indexing by name.

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' values) name - iterable parameter names return_type - return type, default "dict", otherwise "array"

source
EnsembleKalmanProcesses.TOMLInterface.save_parameter_ensembleFunction
save_parameter_ensemble(
     param_array,
     param_distribution,
     default_param_data,
@@ -13,4 +13,4 @@
     iteration
     pad_zeros=3,
 apply_constraints=true
-)

Saves the parameters in the given param_array to TOML files. The intended use is for saving the ensemble of parameters after each update of an ensemble Kalman process. Each ensemble member (column of param_array) is saved in a separate directory "member<j>" (j=1, ..., Nens). The name of the saved toml file is given by save_file; it is the same for all members. A directory "iteration<iter>" is created in `savepath`, which contains all the "member_<j>" subdirectories.

Args: param_array - array of size Nparam x Nens param_distribution - the parameter distribution underlying param_array apply_constraints - apply the constraints in param_distribution default_param_data - dict of default parameters to be combined and saved with the parameters in param_array into a toml file save_path - path to where the parameters will be saved save_file - name of the toml files to be generated iteration - the iteration of the ensemble Kalman process represented by the given param_array pad_zeros - the amount of zero-padding for the ensemble member number

source

One can also call this without the iteration level

source
EnsembleKalmanProcesses.TOMLInterface.get_admissible_parametersFunction
get_admissible_parameters(param_dict)

Finds all parameters in param_dict that are admissible for calibration.

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values

Returns an array of the names of all admissible parameters in param_dict. Admissible parameters must have a key "prior" and the value value of this is not set to "fixed". This allows for other parameters to be stored within the TOML file.

source
EnsembleKalmanProcesses.TOMLInterface.get_regularizationFunction
get_regularization(param_dict, name)

Returns the regularization information for a single parameter

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values name - parameter name

Returns a tuple (<regularizationtype>, <regularizationvalue>), where the regularization type is either "L1" or "L2", and the regularization value is a float. Returns (nothing, nothing) if parameter has no regularization information.

source
get_regularization(param_dict, names)

Returns the regularization information for an array of parameters

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values names - array of parameter names

Returns an arary of tuples (<regularizationtype>, <regularizationvalue>), with the ith tuple corresponding to the parameter names[i]. The regularization type is either "L1" or "L2", and the regularization value is a float. Returns (nothing, nothing) for parameters that have no regularization information.

source
EnsembleKalmanProcesses.TOMLInterface.write_log_fileFunction
write_log_file(param_dict, file_path)

Writes the parameters in param_dict into a .toml file

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values file_path - path of the file where parameters are saved

source
+)

Saves the parameters in the given param_array to TOML files. The intended use is for saving the ensemble of parameters after each update of an ensemble Kalman process. Each ensemble member (column of param_array) is saved in a separate directory "member<j>" (j=1, ..., Nens). The name of the saved toml file is given by save_file; it is the same for all members. A directory "iteration<iter>" is created in `savepath`, which contains all the "member_<j>" subdirectories.

Args: param_array - array of size Nparam x Nens param_distribution - the parameter distribution underlying param_array apply_constraints - apply the constraints in param_distribution default_param_data - dict of default parameters to be combined and saved with the parameters in param_array into a toml file save_path - path to where the parameters will be saved save_file - name of the toml files to be generated iteration - the iteration of the ensemble Kalman process represented by the given param_array pad_zeros - the amount of zero-padding for the ensemble member number

source

One can also call this without the iteration level

source
EnsembleKalmanProcesses.TOMLInterface.get_admissible_parametersFunction
get_admissible_parameters(param_dict)

Finds all parameters in param_dict that are admissible for calibration.

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values

Returns an array of the names of all admissible parameters in param_dict. Admissible parameters must have a key "prior" and the value value of this is not set to "fixed". This allows for other parameters to be stored within the TOML file.

source
EnsembleKalmanProcesses.TOMLInterface.get_regularizationFunction
get_regularization(param_dict, name)

Returns the regularization information for a single parameter

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values name - parameter name

Returns a tuple (<regularizationtype>, <regularizationvalue>), where the regularization type is either "L1" or "L2", and the regularization value is a float. Returns (nothing, nothing) if parameter has no regularization information.

source
get_regularization(param_dict, names)

Returns the regularization information for an array of parameters

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values names - array of parameter names

Returns an arary of tuples (<regularizationtype>, <regularizationvalue>), with the ith tuple corresponding to the parameter names[i]. The regularization type is either "L1" or "L2", and the regularization value is a float. Returns (nothing, nothing) for parameters that have no regularization information.

source
EnsembleKalmanProcesses.TOMLInterface.write_log_fileFunction
write_log_file(param_dict, file_path)

Writes the parameters in param_dict into a .toml file

Args: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values file_path - path of the file where parameters are saved

source
diff --git a/dev/API/Unscented/index.html b/dev/API/Unscented/index.html index 0f4c1f8c6..68348420e 100644 --- a/dev/API/Unscented/index.html +++ b/dev/API/Unscented/index.html @@ -1,5 +1,5 @@ -Unscented · EnsembleKalmanProcesses.jl

Unscented Kalman Inversion

EnsembleKalmanProcesses.UnscentedType
Unscented{FT<:AbstractFloat, IT<:Int} <: Process

An unscented Kalman Inversion process.

Fields

  • u_mean::Any

    an interable of arrays of size N_parameters containing the mean of the parameters (in each uki iteration a new array of mean is added)

  • uu_cov::Any

    an iterable of arrays of size (N_parameters x N_parameters) containing the covariance of the parameters (in each uki iteration a new array of cov is added)

  • obs_pred::Any

    an iterable of arrays of size N_y containing the predicted observation (in each uki iteration a new array of predicted observation is added)

  • c_weights::AbstractVecOrMat{FT} where FT<:AbstractFloat

    weights in UKI

  • mean_weights::AbstractVector{FT} where FT<:AbstractFloat

  • cov_weights::AbstractVector{FT} where FT<:AbstractFloat

  • N_ens::Int64

    number of particles 2N+1 or N+2

  • Σ_ω::AbstractMatrix{FT} where FT<:AbstractFloat

    covariance of the artificial evolution error

  • Σ_ν_scale::AbstractFloat

    covariance of the artificial observation error

  • α_reg::AbstractFloat

    regularization parameter

  • r::AbstractVector{FT} where FT<:AbstractFloat

    regularization vector

  • update_freq::Int64

    update frequency

  • impose_prior::Bool

    using augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation.

  • prior_mean::Any

    prior mean - defaults to initial mean

  • prior_cov::Any

    prior covariance - defaults to initial covariance

  • iter::Int64

    current iteration number

Constructors

Unscented(
+Unscented · EnsembleKalmanProcesses.jl

Unscented Kalman Inversion

EnsembleKalmanProcesses.UnscentedType
Unscented{FT<:AbstractFloat, IT<:Int} <: Process

An unscented Kalman Inversion process.

Fields

  • u_mean::Any

    an interable of arrays of size N_parameters containing the mean of the parameters (in each uki iteration a new array of mean is added), note - this is not the same as the ensemble mean of the sigma ensemble as it is taken prior to prediction

  • uu_cov::Any

    an iterable of arrays of size (N_parameters x N_parameters) containing the covariance of the parameters (in each uki iteration a new array of cov is added), note - this is not the same as the ensemble cov of the sigma ensemble as it is taken prior to prediction

  • obs_pred::Any

    an iterable of arrays of size N_y containing the predicted observation (in each uki iteration a new array of predicted observation is added)

  • c_weights::AbstractVecOrMat{FT} where FT<:AbstractFloat

    weights in UKI

  • mean_weights::AbstractVector{FT} where FT<:AbstractFloat

  • cov_weights::AbstractVector{FT} where FT<:AbstractFloat

  • N_ens::Int64

    number of particles 2N+1 or N+2

  • Σ_ω::AbstractMatrix{FT} where FT<:AbstractFloat

    covariance of the artificial evolution error

  • Σ_ν_scale::AbstractFloat

    covariance of the artificial observation error

  • α_reg::AbstractFloat

    regularization parameter

  • r::AbstractVector{FT} where FT<:AbstractFloat

    regularization vector

  • update_freq::Int64

    update frequency

  • impose_prior::Bool

    using augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation.

  • prior_mean::Any

    prior mean - defaults to initial mean

  • prior_cov::Any

    prior covariance - defaults to initial covariance

  • iter::Int64

    current iteration number

Constructors

Unscented(
     u0_mean::AbstractVector{FT},
     uu0_cov::AbstractMatrix{FT};
     α_reg::FT = 1.0,
@@ -9,28 +9,28 @@
     prior_mean::Any,
     prior_cov::Any,
     sigma_points::String = symmetric
-) where {FT <: AbstractFloat, IT <: Int}

Construct an Unscented Inversion Process.

Inputs:

  • u0_mean: Mean at initialization.
  • uu0_cov: Covariance at initialization.
  • α_reg: Hyperparameter controlling regularization toward the prior mean (0 < α_reg ≤ 1),

default should be 1, without regulariazion.

  • update_freq: Set to 0 when the inverse problem is not identifiable,

namely the inverse problem has multiple solutions, the covariance matrix will represent only the sensitivity of the parameters, instead of posterior covariance information; set to 1 (or anything > 0) when the inverse problem is identifiable, and the covariance matrix will converge to a good approximation of the posterior covariance with an uninformative prior.

  • modified_unscented_transform: Modification of the UKI quadrature given in Huang et al (2021).
  • impose_prior: using augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation. If impose_prior == true, prior mean and prior cov must be provided. This is recommended to use, especially when the number of observations is smaller than the number of parameters (ill-posed inverse problems). When this is used, other regularizations are turned off automatically.
  • prior_mean: Prior mean used for regularization.
  • prior_cov: Prior cov used for regularization.
  • sigma_points: String of sigma point type, it can be symmetric with 2N_par+1 ensemble members or simplex with N_par+2 ensemble members.
Unscented(u_mean, uu_cov, obs_pred, c_weights, mean_weights, cov_weights, N_ens, Σ_ω, Σ_ν_scale, α_reg, r, update_freq, impose_prior, prior_mean, prior_cov, iter)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:57.

Unscented(u0_mean, uu0_cov)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:91.

Unscented(prior)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:212.

source
EnsembleKalmanProcesses.construct_sigma_ensembleFunction
construct_sigma_ensemble(
+) where {FT <: AbstractFloat, IT <: Int}

Construct an Unscented Inversion Process.

Inputs:

  • u0_mean: Mean at initialization.
  • uu0_cov: Covariance at initialization.
  • α_reg: Hyperparameter controlling regularization toward the prior mean (0 < α_reg ≤ 1),

default should be 1, without regulariazion.

  • update_freq: Set to 0 when the inverse problem is not identifiable,

namely the inverse problem has multiple solutions, the covariance matrix will represent only the sensitivity of the parameters, instead of posterior covariance information; set to 1 (or anything > 0) when the inverse problem is identifiable, and the covariance matrix will converge to a good approximation of the posterior covariance with an uninformative prior.

  • modified_unscented_transform: Modification of the UKI quadrature given in Huang et al (2021).
  • impose_prior: using augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation. If impose_prior == true, prior mean and prior cov must be provided. This is recommended to use, especially when the number of observations is smaller than the number of parameters (ill-posed inverse problems). When this is used, other regularizations are turned off automatically.
  • prior_mean: Prior mean used for regularization.
  • prior_cov: Prior cov used for regularization.
  • sigma_points: String of sigma point type, it can be symmetric with 2N_par+1 ensemble members or simplex with N_par+2 ensemble members.
Unscented(u_mean, uu_cov, obs_pred, c_weights, mean_weights, cov_weights, N_ens, Σ_ω, Σ_ν_scale, α_reg, r, update_freq, impose_prior, prior_mean, prior_cov, iter)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:57.

Unscented(u0_mean, uu0_cov)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:91.

Unscented(prior)

defined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:212.

source
EnsembleKalmanProcesses.construct_sigma_ensembleFunction
construct_sigma_ensemble(
     process::Unscented,
     x_mean::Array{FT},
     x_cov::AbstractMatrix{FT},
-) where {FT <: AbstractFloat, IT <: Int}

Construct the sigma ensemble based on the mean x_mean and covariance x_cov.

source
EnsembleKalmanProcesses.construct_meanFunction
construct_mean(
     uki::EnsembleKalmanProcess{FT, IT, Unscented},
     x::AbstractVecOrMat{FT};
     mean_weights = uki.process.mean_weights,
-) where {FT <: AbstractFloat, IT <: Int}

constructs mean x_mean from an ensemble x.

source
EnsembleKalmanProcesses.construct_covFunction
construct_cov(
     uki::EnsembleKalmanProcess{FT, IT, Unscented},
     x::AbstractVecOrMat{FT},
     x_mean::Union{FT, AbstractVector{FT}, Nothing} = nothing;
     cov_weights = uki.process.cov_weights,
-) where {FT <: AbstractFloat, IT <: Int}

Constructs covariance xx_cov from ensemble x and mean x_mean.

source
construct_cov(
+) where {FT <: AbstractFloat, IT <: Int}

Constructs covariance xx_cov from ensemble x and mean x_mean.

source
construct_cov(
     uki::EnsembleKalmanProcess{FT, IT, Unscented},
     x::AbstractMatrix{FT},
     x_mean::AbstractVector{FT},
     obs_mean::AbstractMatrix{FT},
     y_mean::AbstractVector{FT};
     cov_weights = uki.process.cov_weights,
-) where {FT <: AbstractFloat, IT <: Int, P <: Process}

Constructs covariance xy_cov from ensemble x and mean x_mean, ensemble obs_mean and mean y_mean.

source
EnsembleKalmanProcesses.update_ensemble_analysis!Function
update_ensemble_analysis!(
     uki::EnsembleKalmanProcess{FT, IT, Unscented},
     u_p::AbstractMatrix{FT},
     g::AbstractMatrix{FT},
-) where {FT <: AbstractFloat, IT <: Int}

UKI analysis step : g is the predicted observations Ny x N_ens matrix

source
+) where {FT <: AbstractFloat, IT <: Int}

UKI analysis step : g is the predicted observations Ny x N_ens matrix

source
diff --git a/dev/assets/documenter.js b/dev/assets/documenter.js index 7002e2519..f5311607b 100644 --- a/dev/assets/documenter.js +++ b/dev/assets/documenter.js @@ -75,61 +75,76 @@ $(document).ready(function() { //////////////////////////////////////////////////////////////////////////////// require(['jquery'], function($) { +let timer = 0; var isExpanded = true; $(document).on("click", ".docstring header", function () { let articleToggleTitle = "Expand docstring"; - if ($(this).siblings("section").is(":visible")) { - $(this) - .find(".docstring-article-toggle-button") - .removeClass("fa-chevron-down") - .addClass("fa-chevron-right"); - } else { - $(this) - .find(".docstring-article-toggle-button") - .removeClass("fa-chevron-right") - .addClass("fa-chevron-down"); + debounce(() => { + if ($(this).siblings("section").is(":visible")) { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + } else { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); - articleToggleTitle = "Collapse docstring"; - } + articleToggleTitle = "Collapse docstring"; + } - $(this) - .find(".docstring-article-toggle-button") - .prop("title", articleToggleTitle); - $(this).siblings("section").slideToggle(); + $(this) + .find(".docstring-article-toggle-button") + .prop("title", articleToggleTitle); + $(this).siblings("section").slideToggle(); + }); }); $(document).on("click", ".docs-article-toggle-button", function () { let articleToggleTitle = "Expand docstring"; let navArticleToggleTitle = "Expand all docstrings"; - if (isExpanded) { - $(this).removeClass("fa-chevron-up").addClass("fa-chevron-down"); - $(".docstring-article-toggle-button") - .removeClass("fa-chevron-down") - .addClass("fa-chevron-right"); + debounce(() => { + if (isExpanded) { + $(this).removeClass("fa-chevron-up").addClass("fa-chevron-down"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); - isExpanded = false; + isExpanded = false; - $(".docstring section").slideUp(); - } else { - $(this).removeClass("fa-chevron-down").addClass("fa-chevron-up"); - $(".docstring-article-toggle-button") - .removeClass("fa-chevron-right") - .addClass("fa-chevron-down"); + $(".docstring section").slideUp(); + } else { + $(this).removeClass("fa-chevron-down").addClass("fa-chevron-up"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); - isExpanded = true; - articleToggleTitle = "Collapse docstring"; - navArticleToggleTitle = "Collapse all docstrings"; + isExpanded = true; + articleToggleTitle = "Collapse docstring"; + navArticleToggleTitle = "Collapse all docstrings"; - $(".docstring section").slideDown(); - } + $(".docstring section").slideDown(); + } - $(this).prop("title", navArticleToggleTitle); - $(".docstring-article-toggle-button").prop("title", articleToggleTitle); + $(this).prop("title", navArticleToggleTitle); + $(".docstring-article-toggle-button").prop("title", articleToggleTitle); + }); }); +function debounce(callback, timeout = 300) { + if (Date.now() - timer > timeout) { + callback(); + } + + clearTimeout(timer); + + timer = Date.now(); +} + }) //////////////////////////////////////////////////////////////////////////////// require([], function() { diff --git a/dev/assets/themes/documenter-dark.css b/dev/assets/themes/documenter-dark.css index 691b83abd..ec054ecc1 100644 --- a/dev/assets/themes/documenter-dark.css +++ b/dev/assets/themes/documenter-dark.css @@ -4,4 +4,4 @@ Maintainer: @ericwbailey Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css -*/}html.theme--documenter-dark html{background-color:#1f2424;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark article,html.theme--documenter-dark aside,html.theme--documenter-dark figure,html.theme--documenter-dark footer,html.theme--documenter-dark header,html.theme--documenter-dark hgroup,html.theme--documenter-dark section{display:block}html.theme--documenter-dark body,html.theme--documenter-dark button,html.theme--documenter-dark input,html.theme--documenter-dark optgroup,html.theme--documenter-dark select,html.theme--documenter-dark textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}html.theme--documenter-dark code,html.theme--documenter-dark pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark body{color:#fff;font-size:1em;font-weight:400;line-height:1.5}html.theme--documenter-dark a{color:#1abc9c;cursor:pointer;text-decoration:none}html.theme--documenter-dark a strong{color:currentColor}html.theme--documenter-dark a:hover{color:#1dd2af}html.theme--documenter-dark code{background-color:rgba(255,255,255,0.05);color:#ececec;font-size:.875em;font-weight:normal;padding:.1em}html.theme--documenter-dark hr{background-color:#282f2f;border:none;display:block;height:2px;margin:1.5rem 0}html.theme--documenter-dark img{height:auto;max-width:100%}html.theme--documenter-dark input[type="checkbox"],html.theme--documenter-dark input[type="radio"]{vertical-align:baseline}html.theme--documenter-dark small{font-size:.875em}html.theme--documenter-dark span{font-style:inherit;font-weight:inherit}html.theme--documenter-dark strong{color:#f2f2f2;font-weight:700}html.theme--documenter-dark fieldset{border:none}html.theme--documenter-dark pre{-webkit-overflow-scrolling:touch;background-color:#282f2f;color:#fff;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}html.theme--documenter-dark pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}html.theme--documenter-dark table td,html.theme--documenter-dark table th{vertical-align:top}html.theme--documenter-dark table td:not([align]),html.theme--documenter-dark table th:not([align]){text-align:inherit}html.theme--documenter-dark table th{color:#f2f2f2}html.theme--documenter-dark .box{background-color:#343c3d;border-radius:8px;box-shadow:none;color:#fff;display:block;padding:1.25rem}html.theme--documenter-dark a.box:hover,html.theme--documenter-dark a.box:focus{box-shadow:0 0.5em 1em -0.125em rgba(10,10,10,0.1),0 0 0 1px #1abc9c}html.theme--documenter-dark a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #1abc9c}html.theme--documenter-dark .button{background-color:#282f2f;border-color:#4c5759;border-width:1px;color:#375a7f;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 1px);text-align:center;white-space:nowrap}html.theme--documenter-dark .button strong{color:inherit}html.theme--documenter-dark .button .icon,html.theme--documenter-dark .button .icon.is-small,html.theme--documenter-dark .button #documenter .docs-sidebar form.docs-search>input.icon,html.theme--documenter-dark #documenter .docs-sidebar .button form.docs-search>input.icon,html.theme--documenter-dark .button .icon.is-medium,html.theme--documenter-dark .button .icon.is-large{height:1.5em;width:1.5em}html.theme--documenter-dark .button .icon:first-child:not(:last-child){margin-left:calc(-0.5em - 1px);margin-right:.25em}html.theme--documenter-dark .button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button:hover,html.theme--documenter-dark .button.is-hovered{border-color:#8c9b9d;color:#f2f2f2}html.theme--documenter-dark .button:focus,html.theme--documenter-dark .button.is-focused{border-color:#8c9b9d;color:#17a689}html.theme--documenter-dark .button:focus:not(:active),html.theme--documenter-dark .button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button:active,html.theme--documenter-dark .button.is-active{border-color:#343c3d;color:#f2f2f2}html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;color:#fff;text-decoration:underline}html.theme--documenter-dark .button.is-text:hover,html.theme--documenter-dark .button.is-text.is-hovered,html.theme--documenter-dark .button.is-text:focus,html.theme--documenter-dark .button.is-text.is-focused{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .button.is-text:active,html.theme--documenter-dark .button.is-text.is-active{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .button.is-text[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-ghost{background:none;border-color:rgba(0,0,0,0);color:#1abc9c;text-decoration:none}html.theme--documenter-dark .button.is-ghost:hover,html.theme--documenter-dark .button.is-ghost.is-hovered{color:#1abc9c;text-decoration:underline}html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:hover,html.theme--documenter-dark .button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus,html.theme--documenter-dark .button.is-white.is-focused{border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus:not(:active),html.theme--documenter-dark .button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-hovered{background-color:#000}html.theme--documenter-dark .button.is-white.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-white.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:hover,html.theme--documenter-dark .button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus,html.theme--documenter-dark .button.is-black.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus:not(:active),html.theme--documenter-dark .button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-black.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:hover,html.theme--documenter-dark .button.is-light.is-hovered{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus,html.theme--documenter-dark .button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus:not(:active),html.theme--documenter-dark .button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light.is-active{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:#ecf0f1;box-shadow:none}html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-outlined.is-focused{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-dark,html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover,html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus:not(:active),html.theme--documenter-dark .content kbd.button:focus:not(:active),html.theme--documenter-dark .button.is-dark.is-focused:not(:active),html.theme--documenter-dark .content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark[disabled],html.theme--documenter-dark .content kbd.button[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark,fieldset[disabled] html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:#282f2f;box-shadow:none}html.theme--documenter-dark .button.is-dark.is-inverted,html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted:hover,html.theme--documenter-dark .content kbd.button.is-inverted:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-dark.is-inverted[disabled],html.theme--documenter-dark .content kbd.button.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-loading::after,html.theme--documenter-dark .content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined,html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-outlined.is-focused{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-focused{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus:not(:active),html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus:not(:active),html.theme--documenter-dark .button.is-primary.is-focused:not(:active),html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary[disabled],html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;box-shadow:none}html.theme--documenter-dark .button.is-primary.is-inverted,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}html.theme--documenter-dark .button.is-primary.is-inverted[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:hover,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-light.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e8eef5;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:active,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-light.is-active,html.theme--documenter-dark .docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#dfe8f1;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:hover,html.theme--documenter-dark .button.is-link.is-hovered{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus,html.theme--documenter-dark .button.is-link.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus:not(:active),html.theme--documenter-dark .button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link.is-active{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:#1abc9c;box-shadow:none}html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-link.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-outlined.is-focused{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:hover,html.theme--documenter-dark .button.is-link.is-light.is-hovered{background-color:#e2fbf6;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:active,html.theme--documenter-dark .button.is-link.is-light.is-active{background-color:#d7f9f3;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:hover,html.theme--documenter-dark .button.is-info.is-hovered{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus,html.theme--documenter-dark .button.is-info.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus:not(:active),html.theme--documenter-dark .button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info.is-active{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:#024c7d;box-shadow:none}html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-info.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;color:#024c7d}html.theme--documenter-dark .button.is-info.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-outlined.is-focused{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:hover,html.theme--documenter-dark .button.is-info.is-light.is-hovered{background-color:#def2fe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:active,html.theme--documenter-dark .button.is-info.is-light.is-active{background-color:#d2edfe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:hover,html.theme--documenter-dark .button.is-success.is-hovered{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus,html.theme--documenter-dark .button.is-success.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus:not(:active),html.theme--documenter-dark .button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success.is-active{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:#008438;box-shadow:none}html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-success.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;color:#008438}html.theme--documenter-dark .button.is-success.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-outlined.is-focused{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:hover,html.theme--documenter-dark .button.is-success.is-light.is-hovered{background-color:#deffec;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:active,html.theme--documenter-dark .button.is-success.is-light.is-active{background-color:#d1ffe5;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:hover,html.theme--documenter-dark .button.is-warning.is-hovered{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus,html.theme--documenter-dark .button.is-warning.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus:not(:active),html.theme--documenter-dark .button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning.is-active{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:#ad8100;box-shadow:none}html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-warning.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-outlined.is-focused{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-focused{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:hover,html.theme--documenter-dark .button.is-warning.is-light.is-hovered{background-color:#fff7de;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:active,html.theme--documenter-dark .button.is-warning.is-light.is-active{background-color:#fff3d1;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:hover,html.theme--documenter-dark .button.is-danger.is-hovered{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus,html.theme--documenter-dark .button.is-danger.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus:not(:active),html.theme--documenter-dark .button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger.is-active{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;box-shadow:none}html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-danger.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-outlined.is-focused{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:hover,html.theme--documenter-dark .button.is-danger.is-light.is-hovered{background-color:#fce3e0;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:active,html.theme--documenter-dark .button.is-danger.is-light.is-active{background-color:#fcd8d5;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}html.theme--documenter-dark .button.is-small:not(.is-rounded),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:3px}html.theme--documenter-dark .button.is-normal{font-size:1rem}html.theme--documenter-dark .button.is-medium{font-size:1.25rem}html.theme--documenter-dark .button.is-large{font-size:1.5rem}html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .button{background-color:#8c9b9d;border-color:#5e6d6f;box-shadow:none;opacity:.5}html.theme--documenter-dark .button.is-fullwidth{display:flex;width:100%}html.theme--documenter-dark .button.is-loading{color:transparent !important;pointer-events:none}html.theme--documenter-dark .button.is-loading::after{position:absolute;left:calc(50% - (1em * 0.5));top:calc(50% - (1em * 0.5));position:absolute !important}html.theme--documenter-dark .button.is-static{background-color:#282f2f;border-color:#5e6d6f;color:#dbdee0;box-shadow:none;pointer-events:none}html.theme--documenter-dark .button.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{border-radius:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}html.theme--documenter-dark .buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .buttons .button{margin-bottom:0.5rem}html.theme--documenter-dark .buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}html.theme--documenter-dark .buttons:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .buttons:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:3px}html.theme--documenter-dark .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}html.theme--documenter-dark .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}html.theme--documenter-dark .buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}html.theme--documenter-dark .buttons.has-addons .button:last-child{margin-right:0}html.theme--documenter-dark .buttons.has-addons .button:hover,html.theme--documenter-dark .buttons.has-addons .button.is-hovered{z-index:2}html.theme--documenter-dark .buttons.has-addons .button:focus,html.theme--documenter-dark .buttons.has-addons .button.is-focused,html.theme--documenter-dark .buttons.has-addons .button:active,html.theme--documenter-dark .buttons.has-addons .button.is-active,html.theme--documenter-dark .buttons.has-addons .button.is-selected{z-index:3}html.theme--documenter-dark .buttons.has-addons .button:focus:hover,html.theme--documenter-dark .buttons.has-addons .button.is-focused:hover,html.theme--documenter-dark .buttons.has-addons .button:active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-selected:hover{z-index:4}html.theme--documenter-dark .buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .buttons.is-centered{justify-content:center}html.theme--documenter-dark .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}html.theme--documenter-dark .buttons.is-right{justify-content:flex-end}html.theme--documenter-dark .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:1rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1.25rem}}html.theme--documenter-dark .container{flex-grow:1;margin:0 auto;position:relative;width:auto}html.theme--documenter-dark .container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){html.theme--documenter-dark .container{max-width:992px}}@media screen and (max-width: 1215px){html.theme--documenter-dark .container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){html.theme--documenter-dark .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){html.theme--documenter-dark .container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){html.theme--documenter-dark .container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}html.theme--documenter-dark .content li+li{margin-top:0.25em}html.theme--documenter-dark .content p:not(:last-child),html.theme--documenter-dark .content dl:not(:last-child),html.theme--documenter-dark .content ol:not(:last-child),html.theme--documenter-dark .content ul:not(:last-child),html.theme--documenter-dark .content blockquote:not(:last-child),html.theme--documenter-dark .content pre:not(:last-child),html.theme--documenter-dark .content table:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .content h1,html.theme--documenter-dark .content h2,html.theme--documenter-dark .content h3,html.theme--documenter-dark .content h4,html.theme--documenter-dark .content h5,html.theme--documenter-dark .content h6{color:#f2f2f2;font-weight:600;line-height:1.125}html.theme--documenter-dark .content h1{font-size:2em;margin-bottom:0.5em}html.theme--documenter-dark .content h1:not(:first-child){margin-top:1em}html.theme--documenter-dark .content h2{font-size:1.75em;margin-bottom:0.5714em}html.theme--documenter-dark .content h2:not(:first-child){margin-top:1.1428em}html.theme--documenter-dark .content h3{font-size:1.5em;margin-bottom:0.6666em}html.theme--documenter-dark .content h3:not(:first-child){margin-top:1.3333em}html.theme--documenter-dark .content h4{font-size:1.25em;margin-bottom:0.8em}html.theme--documenter-dark .content h5{font-size:1.125em;margin-bottom:0.8888em}html.theme--documenter-dark .content h6{font-size:1em;margin-bottom:1em}html.theme--documenter-dark .content blockquote{background-color:#282f2f;border-left:5px solid #5e6d6f;padding:1.25em 1.5em}html.theme--documenter-dark .content ol{list-style-position:outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ol:not([type]){list-style-type:decimal}html.theme--documenter-dark .content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}html.theme--documenter-dark .content ol.is-lower-roman:not([type]){list-style-type:lower-roman}html.theme--documenter-dark .content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}html.theme--documenter-dark .content ol.is-upper-roman:not([type]){list-style-type:upper-roman}html.theme--documenter-dark .content ul{list-style:disc outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ul ul{list-style-type:circle;margin-top:0.5em}html.theme--documenter-dark .content ul ul ul{list-style-type:square}html.theme--documenter-dark .content dd{margin-left:2em}html.theme--documenter-dark .content figure{margin-left:2em;margin-right:2em;text-align:center}html.theme--documenter-dark .content figure:not(:first-child){margin-top:2em}html.theme--documenter-dark .content figure:not(:last-child){margin-bottom:2em}html.theme--documenter-dark .content figure img{display:inline-block}html.theme--documenter-dark .content figure figcaption{font-style:italic}html.theme--documenter-dark .content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}html.theme--documenter-dark .content sup,html.theme--documenter-dark .content sub{font-size:75%}html.theme--documenter-dark .content table{width:100%}html.theme--documenter-dark .content table td,html.theme--documenter-dark .content table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .content table th{color:#f2f2f2}html.theme--documenter-dark .content table th:not([align]){text-align:inherit}html.theme--documenter-dark .content table thead td,html.theme--documenter-dark .content table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .content table tfoot td,html.theme--documenter-dark .content table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .content table tbody tr:last-child td,html.theme--documenter-dark .content table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .content .tabs li+li{margin-top:0}html.theme--documenter-dark .content.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}html.theme--documenter-dark .content.is-normal{font-size:1rem}html.theme--documenter-dark .content.is-medium{font-size:1.25rem}html.theme--documenter-dark .content.is-large{font-size:1.5rem}html.theme--documenter-dark .icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}html.theme--documenter-dark .icon.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}html.theme--documenter-dark .icon.is-medium{height:2rem;width:2rem}html.theme--documenter-dark .icon.is-large{height:3rem;width:3rem}html.theme--documenter-dark .icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}html.theme--documenter-dark .icon-text .icon{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .icon-text .icon:not(:last-child){margin-right:.25em}html.theme--documenter-dark .icon-text .icon:not(:first-child){margin-left:.25em}html.theme--documenter-dark div.icon-text{display:flex}html.theme--documenter-dark .image,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{display:block;position:relative}html.theme--documenter-dark .image img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}html.theme--documenter-dark .image img.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:9999px}html.theme--documenter-dark .image.is-fullwidth,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}html.theme--documenter-dark .image.is-square,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square,html.theme--documenter-dark .image.is-1by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}html.theme--documenter-dark .image.is-5by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}html.theme--documenter-dark .image.is-4by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}html.theme--documenter-dark .image.is-3by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}html.theme--documenter-dark .image.is-5by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}html.theme--documenter-dark .image.is-16by9,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}html.theme--documenter-dark .image.is-2by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}html.theme--documenter-dark .image.is-3by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}html.theme--documenter-dark .image.is-4by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}html.theme--documenter-dark .image.is-3by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}html.theme--documenter-dark .image.is-2by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}html.theme--documenter-dark .image.is-3by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}html.theme--documenter-dark .image.is-9by16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}html.theme--documenter-dark .image.is-1by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}html.theme--documenter-dark .image.is-1by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}html.theme--documenter-dark .image.is-16x16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}html.theme--documenter-dark .image.is-24x24,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}html.theme--documenter-dark .image.is-32x32,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}html.theme--documenter-dark .image.is-48x48,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}html.theme--documenter-dark .image.is-64x64,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}html.theme--documenter-dark .image.is-96x96,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}html.theme--documenter-dark .image.is-128x128,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}html.theme--documenter-dark .notification{background-color:#282f2f;border-radius:.4em;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}html.theme--documenter-dark .notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .notification strong{color:currentColor}html.theme--documenter-dark .notification code,html.theme--documenter-dark .notification pre{background:#fff}html.theme--documenter-dark .notification pre code{background:transparent}html.theme--documenter-dark .notification>.delete{right:.5rem;position:absolute;top:0.5rem}html.theme--documenter-dark .notification .title,html.theme--documenter-dark .notification .subtitle,html.theme--documenter-dark .notification .content{color:currentColor}html.theme--documenter-dark .notification.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .notification.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .notification.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .notification.is-dark,html.theme--documenter-dark .content kbd.notification{background-color:#282f2f;color:#fff}html.theme--documenter-dark .notification.is-primary,html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .notification.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.notification.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .notification.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .notification.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .notification.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .notification.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .notification.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .notification.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .notification.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .notification.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .notification.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .notification.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}html.theme--documenter-dark .progress::-webkit-progress-bar{background-color:#343c3d}html.theme--documenter-dark .progress::-webkit-progress-value{background-color:#dbdee0}html.theme--documenter-dark .progress::-moz-progress-bar{background-color:#dbdee0}html.theme--documenter-dark .progress::-ms-fill{background-color:#dbdee0;border:none}html.theme--documenter-dark .progress.is-white::-webkit-progress-value{background-color:#fff}html.theme--documenter-dark .progress.is-white::-moz-progress-bar{background-color:#fff}html.theme--documenter-dark .progress.is-white::-ms-fill{background-color:#fff}html.theme--documenter-dark .progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-black::-webkit-progress-value{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-moz-progress-bar{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-ms-fill{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-light::-webkit-progress-value{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-moz-progress-bar{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-ms-fill{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light:indeterminate{background-image:linear-gradient(to right, #ecf0f1 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-dark::-webkit-progress-value,html.theme--documenter-dark .content kbd.progress::-webkit-progress-value{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-moz-progress-bar,html.theme--documenter-dark .content kbd.progress::-moz-progress-bar{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-ms-fill,html.theme--documenter-dark .content kbd.progress::-ms-fill{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark:indeterminate,html.theme--documenter-dark .content kbd.progress:indeterminate{background-image:linear-gradient(to right, #282f2f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-primary::-webkit-progress-value,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-moz-progress-bar,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-ms-fill,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary:indeterminate,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #375a7f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-link::-webkit-progress-value{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-moz-progress-bar{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-ms-fill{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link:indeterminate{background-image:linear-gradient(to right, #1abc9c 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-info::-webkit-progress-value{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-moz-progress-bar{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-ms-fill{background-color:#024c7d}html.theme--documenter-dark .progress.is-info:indeterminate{background-image:linear-gradient(to right, #024c7d 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-success::-webkit-progress-value{background-color:#008438}html.theme--documenter-dark .progress.is-success::-moz-progress-bar{background-color:#008438}html.theme--documenter-dark .progress.is-success::-ms-fill{background-color:#008438}html.theme--documenter-dark .progress.is-success:indeterminate{background-image:linear-gradient(to right, #008438 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-warning::-webkit-progress-value{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-moz-progress-bar{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-ms-fill{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ad8100 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-danger::-webkit-progress-value{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-moz-progress-bar{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-ms-fill{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger:indeterminate{background-image:linear-gradient(to right, #9e1b0d 30%, #343c3d 30%)}html.theme--documenter-dark .progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#343c3d;background-image:linear-gradient(to right, #fff 30%, #343c3d 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}html.theme--documenter-dark .progress:indeterminate::-webkit-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-moz-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-ms-fill{animation-name:none}html.theme--documenter-dark .progress.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}html.theme--documenter-dark .progress.is-medium{height:1.25rem}html.theme--documenter-dark .progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}html.theme--documenter-dark .table{background-color:#343c3d;color:#fff}html.theme--documenter-dark .table td,html.theme--documenter-dark .table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .table td.is-white,html.theme--documenter-dark .table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .table td.is-black,html.theme--documenter-dark .table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .table td.is-light,html.theme--documenter-dark .table th.is-light{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .table td.is-dark,html.theme--documenter-dark .table th.is-dark{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .table td.is-primary,html.theme--documenter-dark .table th.is-primary{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-link,html.theme--documenter-dark .table th.is-link{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .table td.is-info,html.theme--documenter-dark .table th.is-info{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .table td.is-success,html.theme--documenter-dark .table th.is-success{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .table td.is-warning,html.theme--documenter-dark .table th.is-warning{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .table td.is-danger,html.theme--documenter-dark .table th.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .table td.is-narrow,html.theme--documenter-dark .table th.is-narrow{white-space:nowrap;width:1%}html.theme--documenter-dark .table td.is-selected,html.theme--documenter-dark .table th.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-selected a,html.theme--documenter-dark .table td.is-selected strong,html.theme--documenter-dark .table th.is-selected a,html.theme--documenter-dark .table th.is-selected strong{color:currentColor}html.theme--documenter-dark .table td.is-vcentered,html.theme--documenter-dark .table th.is-vcentered{vertical-align:middle}html.theme--documenter-dark .table th{color:#f2f2f2}html.theme--documenter-dark .table th:not([align]){text-align:left}html.theme--documenter-dark .table tr.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table tr.is-selected a,html.theme--documenter-dark .table tr.is-selected strong{color:currentColor}html.theme--documenter-dark .table tr.is-selected td,html.theme--documenter-dark .table tr.is-selected th{border-color:#fff;color:currentColor}html.theme--documenter-dark .table thead{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table thead td,html.theme--documenter-dark .table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .table tfoot{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tfoot td,html.theme--documenter-dark .table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .table tbody{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tbody tr:last-child td,html.theme--documenter-dark .table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .table.is-bordered td,html.theme--documenter-dark .table.is-bordered th{border-width:1px}html.theme--documenter-dark .table.is-bordered tr:last-child td,html.theme--documenter-dark .table.is-bordered tr:last-child th{border-bottom-width:1px}html.theme--documenter-dark .table.is-fullwidth{width:100%}html.theme--documenter-dark .table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#2d3435}html.theme--documenter-dark .table.is-narrow td,html.theme--documenter-dark .table.is-narrow th{padding:0.25em 0.5em}html.theme--documenter-dark .table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#282f2f}html.theme--documenter-dark .table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}html.theme--documenter-dark .tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .tags .tag,html.theme--documenter-dark .tags .content kbd,html.theme--documenter-dark .content .tags kbd,html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}html.theme--documenter-dark .tags .tag:not(:last-child),html.theme--documenter-dark .tags .content kbd:not(:last-child),html.theme--documenter-dark .content .tags kbd:not(:last-child),html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:.5rem}html.theme--documenter-dark .tags:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .tags:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .tags.are-medium .tag:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .content kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .content .tags.are-medium kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}html.theme--documenter-dark .tags.are-large .tag:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .content kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .content .tags.are-large kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}html.theme--documenter-dark .tags.is-centered{justify-content:center}html.theme--documenter-dark .tags.is-centered .tag,html.theme--documenter-dark .tags.is-centered .content kbd,html.theme--documenter-dark .content .tags.is-centered kbd,html.theme--documenter-dark .tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}html.theme--documenter-dark .tags.is-right{justify-content:flex-end}html.theme--documenter-dark .tags.is-right .tag:not(:first-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:first-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}html.theme--documenter-dark .tags.is-right .tag:not(:last-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:last-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}html.theme--documenter-dark .tags.has-addons .tag,html.theme--documenter-dark .tags.has-addons .content kbd,html.theme--documenter-dark .content .tags.has-addons kbd,html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}html.theme--documenter-dark .tags.has-addons .tag:not(:first-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:first-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}html.theme--documenter-dark .tags.has-addons .tag:not(:last-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:last-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}html.theme--documenter-dark .tag:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#282f2f;border-radius:.4em;color:#fff;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}html.theme--documenter-dark .tag:not(body) .delete,html.theme--documenter-dark .content kbd:not(body) .delete,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}html.theme--documenter-dark .tag.is-white:not(body),html.theme--documenter-dark .content kbd.is-white:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .tag.is-black:not(body),html.theme--documenter-dark .content kbd.is-black:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .tag.is-light:not(body),html.theme--documenter-dark .content kbd.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .tag.is-dark:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-dark:not(body),html.theme--documenter-dark .content .docstring>section>kbd:not(body){background-color:#282f2f;color:#fff}html.theme--documenter-dark .tag.is-primary:not(body),html.theme--documenter-dark .content kbd.is-primary:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){background-color:#375a7f;color:#fff}html.theme--documenter-dark .tag.is-primary.is-light:not(body),html.theme--documenter-dark .content kbd.is-primary.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .tag.is-link:not(body),html.theme--documenter-dark .content kbd.is-link:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#1abc9c;color:#fff}html.theme--documenter-dark .tag.is-link.is-light:not(body),html.theme--documenter-dark .content kbd.is-link.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .tag.is-info:not(body),html.theme--documenter-dark .content kbd.is-info:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#024c7d;color:#fff}html.theme--documenter-dark .tag.is-info.is-light:not(body),html.theme--documenter-dark .content kbd.is-info.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .tag.is-success:not(body),html.theme--documenter-dark .content kbd.is-success:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#008438;color:#fff}html.theme--documenter-dark .tag.is-success.is-light:not(body),html.theme--documenter-dark .content kbd.is-success.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .tag.is-warning:not(body),html.theme--documenter-dark .content kbd.is-warning:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ad8100;color:#fff}html.theme--documenter-dark .tag.is-warning.is-light:not(body),html.theme--documenter-dark .content kbd.is-warning.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .tag.is-danger:not(body),html.theme--documenter-dark .content kbd.is-danger:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .tag.is-danger.is-light:not(body),html.theme--documenter-dark .content kbd.is-danger.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .tag.is-normal:not(body),html.theme--documenter-dark .content kbd.is-normal:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}html.theme--documenter-dark .tag.is-medium:not(body),html.theme--documenter-dark .content kbd.is-medium:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}html.theme--documenter-dark .tag.is-large:not(body),html.theme--documenter-dark .content kbd.is-large:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}html.theme--documenter-dark .tag:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .content kbd:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}html.theme--documenter-dark .tag:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .content kbd:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}html.theme--documenter-dark .tag:not(body) .icon:first-child:last-child,html.theme--documenter-dark .content kbd:not(body) .icon:first-child:last-child,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}html.theme--documenter-dark .tag.is-delete:not(body),html.theme--documenter-dark .content kbd.is-delete:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before,html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}html.theme--documenter-dark .tag.is-delete:not(body):hover,html.theme--documenter-dark .content kbd.is-delete:not(body):hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):hover,html.theme--documenter-dark .tag.is-delete:not(body):focus,html.theme--documenter-dark .content kbd.is-delete:not(body):focus,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#1d2122}html.theme--documenter-dark .tag.is-delete:not(body):active,html.theme--documenter-dark .content kbd.is-delete:not(body):active,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#111414}html.theme--documenter-dark .tag.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:not(body),html.theme--documenter-dark .content kbd.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:9999px}html.theme--documenter-dark a.tag:hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:hover{text-decoration:underline}html.theme--documenter-dark .title,html.theme--documenter-dark .subtitle{word-break:break-word}html.theme--documenter-dark .title em,html.theme--documenter-dark .title span,html.theme--documenter-dark .subtitle em,html.theme--documenter-dark .subtitle span{font-weight:inherit}html.theme--documenter-dark .title sub,html.theme--documenter-dark .subtitle sub{font-size:.75em}html.theme--documenter-dark .title sup,html.theme--documenter-dark .subtitle sup{font-size:.75em}html.theme--documenter-dark .title .tag,html.theme--documenter-dark .title .content kbd,html.theme--documenter-dark .content .title kbd,html.theme--documenter-dark .title .docstring>section>a.docs-sourcelink,html.theme--documenter-dark .subtitle .tag,html.theme--documenter-dark .subtitle .content kbd,html.theme--documenter-dark .content .subtitle kbd,html.theme--documenter-dark .subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}html.theme--documenter-dark .title{color:#fff;font-size:2rem;font-weight:500;line-height:1.125}html.theme--documenter-dark .title strong{color:inherit;font-weight:inherit}html.theme--documenter-dark .title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}html.theme--documenter-dark .title.is-1{font-size:3rem}html.theme--documenter-dark .title.is-2{font-size:2.5rem}html.theme--documenter-dark .title.is-3{font-size:2rem}html.theme--documenter-dark .title.is-4{font-size:1.5rem}html.theme--documenter-dark .title.is-5{font-size:1.25rem}html.theme--documenter-dark .title.is-6{font-size:1rem}html.theme--documenter-dark .title.is-7{font-size:.75rem}html.theme--documenter-dark .subtitle{color:#8c9b9d;font-size:1.25rem;font-weight:400;line-height:1.25}html.theme--documenter-dark .subtitle strong{color:#8c9b9d;font-weight:600}html.theme--documenter-dark .subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}html.theme--documenter-dark .subtitle.is-1{font-size:3rem}html.theme--documenter-dark .subtitle.is-2{font-size:2.5rem}html.theme--documenter-dark .subtitle.is-3{font-size:2rem}html.theme--documenter-dark .subtitle.is-4{font-size:1.5rem}html.theme--documenter-dark .subtitle.is-5{font-size:1.25rem}html.theme--documenter-dark .subtitle.is-6{font-size:1rem}html.theme--documenter-dark .subtitle.is-7{font-size:.75rem}html.theme--documenter-dark .heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}html.theme--documenter-dark .number{align-items:center;background-color:#282f2f;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#1f2424;border-color:#5e6d6f;border-radius:.4em;color:#dbdee0}html.theme--documenter-dark .select select::-moz-placeholder,html.theme--documenter-dark .textarea::-moz-placeholder,html.theme--documenter-dark .input::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select::-webkit-input-placeholder,html.theme--documenter-dark .textarea::-webkit-input-placeholder,html.theme--documenter-dark .input::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:-moz-placeholder,html.theme--documenter-dark .textarea:-moz-placeholder,html.theme--documenter-dark .input:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select:-ms-input-placeholder,html.theme--documenter-dark .textarea:-ms-input-placeholder,html.theme--documenter-dark .input:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:hover,html.theme--documenter-dark .textarea:hover,html.theme--documenter-dark .input:hover,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:hover,html.theme--documenter-dark .select select.is-hovered,html.theme--documenter-dark .is-hovered.textarea,html.theme--documenter-dark .is-hovered.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#8c9b9d}html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{border-color:#1abc9c;box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#8c9b9d;border-color:#282f2f;box-shadow:none;color:#fff}html.theme--documenter-dark .select select[disabled]::-moz-placeholder,html.theme--documenter-dark .textarea[disabled]::-moz-placeholder,html.theme--documenter-dark .input[disabled]::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .textarea[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .input[disabled]::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-moz-placeholder,html.theme--documenter-dark .textarea[disabled]:-moz-placeholder,html.theme--documenter-dark .input[disabled]:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-ms-input-placeholder,html.theme--documenter-dark .textarea[disabled]:-ms-input-placeholder,html.theme--documenter-dark .input[disabled]:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 0.0625em 0.125em rgba(10,10,10,0.05);max-width:100%;width:100%}html.theme--documenter-dark .textarea[readonly],html.theme--documenter-dark .input[readonly],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}html.theme--documenter-dark .is-white.textarea,html.theme--documenter-dark .is-white.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}html.theme--documenter-dark .is-white.textarea:focus,html.theme--documenter-dark .is-white.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:focus,html.theme--documenter-dark .is-white.is-focused.textarea,html.theme--documenter-dark .is-white.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-white.textarea:active,html.theme--documenter-dark .is-white.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:active,html.theme--documenter-dark .is-white.is-active.textarea,html.theme--documenter-dark .is-white.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .is-black.textarea,html.theme--documenter-dark .is-black.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}html.theme--documenter-dark .is-black.textarea:focus,html.theme--documenter-dark .is-black.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:focus,html.theme--documenter-dark .is-black.is-focused.textarea,html.theme--documenter-dark .is-black.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-black.textarea:active,html.theme--documenter-dark .is-black.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:active,html.theme--documenter-dark .is-black.is-active.textarea,html.theme--documenter-dark .is-black.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .is-light.textarea,html.theme--documenter-dark .is-light.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light{border-color:#ecf0f1}html.theme--documenter-dark .is-light.textarea:focus,html.theme--documenter-dark .is-light.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:focus,html.theme--documenter-dark .is-light.is-focused.textarea,html.theme--documenter-dark .is-light.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-light.textarea:active,html.theme--documenter-dark .is-light.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:active,html.theme--documenter-dark .is-light.is-active.textarea,html.theme--documenter-dark .is-light.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .is-dark.textarea,html.theme--documenter-dark .content kbd.textarea,html.theme--documenter-dark .is-dark.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark,html.theme--documenter-dark .content kbd.input{border-color:#282f2f}html.theme--documenter-dark .is-dark.textarea:focus,html.theme--documenter-dark .content kbd.textarea:focus,html.theme--documenter-dark .is-dark.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:focus,html.theme--documenter-dark .content kbd.input:focus,html.theme--documenter-dark .is-dark.is-focused.textarea,html.theme--documenter-dark .content kbd.is-focused.textarea,html.theme--documenter-dark .is-dark.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .content kbd.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-focused,html.theme--documenter-dark .is-dark.textarea:active,html.theme--documenter-dark .content kbd.textarea:active,html.theme--documenter-dark .is-dark.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:active,html.theme--documenter-dark .content kbd.input:active,html.theme--documenter-dark .is-dark.is-active.textarea,html.theme--documenter-dark .content kbd.is-active.textarea,html.theme--documenter-dark .is-dark.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .content kbd.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .is-primary.textarea,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink{border-color:#375a7f}html.theme--documenter-dark .is-primary.textarea:focus,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:focus,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.is-focused.textarea,html.theme--documenter-dark .docstring>section>a.is-focused.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .docstring>section>a.is-focused.input.docs-sourcelink,html.theme--documenter-dark .is-primary.textarea:active,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:active,html.theme--documenter-dark .is-primary.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:active,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:active,html.theme--documenter-dark .is-primary.is-active.textarea,html.theme--documenter-dark .docstring>section>a.is-active.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .is-link.textarea,html.theme--documenter-dark .is-link.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link{border-color:#1abc9c}html.theme--documenter-dark .is-link.textarea:focus,html.theme--documenter-dark .is-link.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:focus,html.theme--documenter-dark .is-link.is-focused.textarea,html.theme--documenter-dark .is-link.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-link.textarea:active,html.theme--documenter-dark .is-link.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:active,html.theme--documenter-dark .is-link.is-active.textarea,html.theme--documenter-dark .is-link.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .is-info.textarea,html.theme--documenter-dark .is-info.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info{border-color:#024c7d}html.theme--documenter-dark .is-info.textarea:focus,html.theme--documenter-dark .is-info.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:focus,html.theme--documenter-dark .is-info.is-focused.textarea,html.theme--documenter-dark .is-info.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-info.textarea:active,html.theme--documenter-dark .is-info.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:active,html.theme--documenter-dark .is-info.is-active.textarea,html.theme--documenter-dark .is-info.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .is-success.textarea,html.theme--documenter-dark .is-success.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success{border-color:#008438}html.theme--documenter-dark .is-success.textarea:focus,html.theme--documenter-dark .is-success.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:focus,html.theme--documenter-dark .is-success.is-focused.textarea,html.theme--documenter-dark .is-success.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-success.textarea:active,html.theme--documenter-dark .is-success.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:active,html.theme--documenter-dark .is-success.is-active.textarea,html.theme--documenter-dark .is-success.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .is-warning.textarea,html.theme--documenter-dark .is-warning.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ad8100}html.theme--documenter-dark .is-warning.textarea:focus,html.theme--documenter-dark .is-warning.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:focus,html.theme--documenter-dark .is-warning.is-focused.textarea,html.theme--documenter-dark .is-warning.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-warning.textarea:active,html.theme--documenter-dark .is-warning.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:active,html.theme--documenter-dark .is-warning.is-active.textarea,html.theme--documenter-dark .is-warning.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .is-danger.textarea,html.theme--documenter-dark .is-danger.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#9e1b0d}html.theme--documenter-dark .is-danger.textarea:focus,html.theme--documenter-dark .is-danger.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:focus,html.theme--documenter-dark .is-danger.is-focused.textarea,html.theme--documenter-dark .is-danger.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-danger.textarea:active,html.theme--documenter-dark .is-danger.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:active,html.theme--documenter-dark .is-danger.is-active.textarea,html.theme--documenter-dark .is-danger.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .is-small.textarea,html.theme--documenter-dark .is-small.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .is-medium.textarea,html.theme--documenter-dark .is-medium.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}html.theme--documenter-dark .is-large.textarea,html.theme--documenter-dark .is-large.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}html.theme--documenter-dark .is-fullwidth.textarea,html.theme--documenter-dark .is-fullwidth.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}html.theme--documenter-dark .is-inline.textarea,html.theme--documenter-dark .is-inline.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}html.theme--documenter-dark .input.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}html.theme--documenter-dark .input.is-static,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}html.theme--documenter-dark .textarea{display:block;max-width:100%;min-width:100%;padding:calc(0.75em - 1px);resize:vertical}html.theme--documenter-dark .textarea:not([rows]){max-height:40em;min-height:8em}html.theme--documenter-dark .textarea[rows]{height:initial}html.theme--documenter-dark .textarea.has-fixed-size{resize:none}html.theme--documenter-dark .radio,html.theme--documenter-dark .checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}html.theme--documenter-dark .radio input,html.theme--documenter-dark .checkbox input{cursor:pointer}html.theme--documenter-dark .radio:hover,html.theme--documenter-dark .checkbox:hover{color:#8c9b9d}html.theme--documenter-dark .radio[disabled],html.theme--documenter-dark .checkbox[disabled],fieldset[disabled] html.theme--documenter-dark .radio,fieldset[disabled] html.theme--documenter-dark .checkbox,html.theme--documenter-dark .radio input[disabled],html.theme--documenter-dark .checkbox input[disabled]{color:#fff;cursor:not-allowed}html.theme--documenter-dark .radio+.radio{margin-left:.5em}html.theme--documenter-dark .select{display:inline-block;max-width:100%;position:relative;vertical-align:top}html.theme--documenter-dark .select:not(.is-multiple){height:2.5em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border-color:#1abc9c;right:1.125em;z-index:4}html.theme--documenter-dark .select.is-rounded select,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select select{border-radius:9999px;padding-left:1em}html.theme--documenter-dark .select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}html.theme--documenter-dark .select select::-ms-expand{display:none}html.theme--documenter-dark .select select[disabled]:hover,fieldset[disabled] html.theme--documenter-dark .select select:hover{border-color:#282f2f}html.theme--documenter-dark .select select:not([multiple]){padding-right:2.5em}html.theme--documenter-dark .select select[multiple]{height:auto;padding:0}html.theme--documenter-dark .select select[multiple] option{padding:0.5em 1em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading):hover::after{border-color:#8c9b9d}html.theme--documenter-dark .select.is-white:not(:hover)::after{border-color:#fff}html.theme--documenter-dark .select.is-white select{border-color:#fff}html.theme--documenter-dark .select.is-white select:hover,html.theme--documenter-dark .select.is-white select.is-hovered{border-color:#f2f2f2}html.theme--documenter-dark .select.is-white select:focus,html.theme--documenter-dark .select.is-white select.is-focused,html.theme--documenter-dark .select.is-white select:active,html.theme--documenter-dark .select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .select.is-black:not(:hover)::after{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select:hover,html.theme--documenter-dark .select.is-black select.is-hovered{border-color:#000}html.theme--documenter-dark .select.is-black select:focus,html.theme--documenter-dark .select.is-black select.is-focused,html.theme--documenter-dark .select.is-black select:active,html.theme--documenter-dark .select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .select.is-light:not(:hover)::after{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select:hover,html.theme--documenter-dark .select.is-light select.is-hovered{border-color:#dde4e6}html.theme--documenter-dark .select.is-light select:focus,html.theme--documenter-dark .select.is-light select.is-focused,html.theme--documenter-dark .select.is-light select:active,html.theme--documenter-dark .select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .select.is-dark:not(:hover)::after,html.theme--documenter-dark .content kbd.select:not(:hover)::after{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select,html.theme--documenter-dark .content kbd.select select{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select:hover,html.theme--documenter-dark .content kbd.select select:hover,html.theme--documenter-dark .select.is-dark select.is-hovered,html.theme--documenter-dark .content kbd.select select.is-hovered{border-color:#1d2122}html.theme--documenter-dark .select.is-dark select:focus,html.theme--documenter-dark .content kbd.select select:focus,html.theme--documenter-dark .select.is-dark select.is-focused,html.theme--documenter-dark .content kbd.select select.is-focused,html.theme--documenter-dark .select.is-dark select:active,html.theme--documenter-dark .content kbd.select select:active,html.theme--documenter-dark .select.is-dark select.is-active,html.theme--documenter-dark .content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .select.is-primary:not(:hover)::after,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select:hover,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:hover,html.theme--documenter-dark .select.is-primary select.is-hovered,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#2f4d6d}html.theme--documenter-dark .select.is-primary select:focus,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:focus,html.theme--documenter-dark .select.is-primary select.is-focused,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-focused,html.theme--documenter-dark .select.is-primary select:active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:active,html.theme--documenter-dark .select.is-primary select.is-active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .select.is-link:not(:hover)::after{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select:hover,html.theme--documenter-dark .select.is-link select.is-hovered{border-color:#17a689}html.theme--documenter-dark .select.is-link select:focus,html.theme--documenter-dark .select.is-link select.is-focused,html.theme--documenter-dark .select.is-link select:active,html.theme--documenter-dark .select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select.is-info:not(:hover)::after{border-color:#024c7d}html.theme--documenter-dark .select.is-info select{border-color:#024c7d}html.theme--documenter-dark .select.is-info select:hover,html.theme--documenter-dark .select.is-info select.is-hovered{border-color:#023d64}html.theme--documenter-dark .select.is-info select:focus,html.theme--documenter-dark .select.is-info select.is-focused,html.theme--documenter-dark .select.is-info select:active,html.theme--documenter-dark .select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .select.is-success:not(:hover)::after{border-color:#008438}html.theme--documenter-dark .select.is-success select{border-color:#008438}html.theme--documenter-dark .select.is-success select:hover,html.theme--documenter-dark .select.is-success select.is-hovered{border-color:#006b2d}html.theme--documenter-dark .select.is-success select:focus,html.theme--documenter-dark .select.is-success select.is-focused,html.theme--documenter-dark .select.is-success select:active,html.theme--documenter-dark .select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .select.is-warning:not(:hover)::after{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select:hover,html.theme--documenter-dark .select.is-warning select.is-hovered{border-color:#946e00}html.theme--documenter-dark .select.is-warning select:focus,html.theme--documenter-dark .select.is-warning select.is-focused,html.theme--documenter-dark .select.is-warning select:active,html.theme--documenter-dark .select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .select.is-danger:not(:hover)::after{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select:hover,html.theme--documenter-dark .select.is-danger select.is-hovered{border-color:#86170b}html.theme--documenter-dark .select.is-danger select:focus,html.theme--documenter-dark .select.is-danger select.is-focused,html.theme--documenter-dark .select.is-danger select:active,html.theme--documenter-dark .select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .select.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .select.is-medium{font-size:1.25rem}html.theme--documenter-dark .select.is-large{font-size:1.5rem}html.theme--documenter-dark .select.is-disabled::after{border-color:#fff !important;opacity:0.5}html.theme--documenter-dark .select.is-fullwidth{width:100%}html.theme--documenter-dark .select.is-fullwidth select{width:100%}html.theme--documenter-dark .select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:0.625em;transform:none}html.theme--documenter-dark .select.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .select.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .select.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}html.theme--documenter-dark .file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:hover .file-cta,html.theme--documenter-dark .file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:focus .file-cta,html.theme--documenter-dark .file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}html.theme--documenter-dark .file.is-white:active .file-cta,html.theme--documenter-dark .file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:hover .file-cta,html.theme--documenter-dark .file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:focus .file-cta,html.theme--documenter-dark .file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}html.theme--documenter-dark .file.is-black:active .file-cta,html.theme--documenter-dark .file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-light .file-cta{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:hover .file-cta,html.theme--documenter-dark .file.is-light.is-hovered .file-cta{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:focus .file-cta,html.theme--documenter-dark .file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(236,240,241,0.25);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:active .file-cta,html.theme--documenter-dark .file.is-light.is-active .file-cta{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-dark .file-cta,html.theme--documenter-dark .content kbd.file .file-cta{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:hover .file-cta,html.theme--documenter-dark .content kbd.file:hover .file-cta,html.theme--documenter-dark .file.is-dark.is-hovered .file-cta,html.theme--documenter-dark .content kbd.file.is-hovered .file-cta{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:focus .file-cta,html.theme--documenter-dark .content kbd.file:focus .file-cta,html.theme--documenter-dark .file.is-dark.is-focused .file-cta,html.theme--documenter-dark .content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(40,47,47,0.25);color:#fff}html.theme--documenter-dark .file.is-dark:active .file-cta,html.theme--documenter-dark .content kbd.file:active .file-cta,html.theme--documenter-dark .file.is-dark.is-active .file-cta,html.theme--documenter-dark .content kbd.file.is-active .file-cta{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink .file-cta{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:hover .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:hover .file-cta,html.theme--documenter-dark .file.is-primary.is-hovered .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:focus .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:focus .file-cta,html.theme--documenter-dark .file.is-primary.is-focused .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(55,90,127,0.25);color:#fff}html.theme--documenter-dark .file.is-primary:active .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:active .file-cta,html.theme--documenter-dark .file.is-primary.is-active .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link .file-cta{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:hover .file-cta,html.theme--documenter-dark .file.is-link.is-hovered .file-cta{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:focus .file-cta,html.theme--documenter-dark .file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(26,188,156,0.25);color:#fff}html.theme--documenter-dark .file.is-link:active .file-cta,html.theme--documenter-dark .file.is-link.is-active .file-cta{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info .file-cta{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:hover .file-cta,html.theme--documenter-dark .file.is-info.is-hovered .file-cta{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:focus .file-cta,html.theme--documenter-dark .file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(2,76,125,0.25);color:#fff}html.theme--documenter-dark .file.is-info:active .file-cta,html.theme--documenter-dark .file.is-info.is-active .file-cta{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success .file-cta{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:hover .file-cta,html.theme--documenter-dark .file.is-success.is-hovered .file-cta{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:focus .file-cta,html.theme--documenter-dark .file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(0,132,56,0.25);color:#fff}html.theme--documenter-dark .file.is-success:active .file-cta,html.theme--documenter-dark .file.is-success.is-active .file-cta{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning .file-cta{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:hover .file-cta,html.theme--documenter-dark .file.is-warning.is-hovered .file-cta{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:focus .file-cta,html.theme--documenter-dark .file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(173,129,0,0.25);color:#fff}html.theme--documenter-dark .file.is-warning:active .file-cta,html.theme--documenter-dark .file.is-warning.is-active .file-cta{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger .file-cta{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:hover .file-cta,html.theme--documenter-dark .file.is-danger.is-hovered .file-cta{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:focus .file-cta,html.theme--documenter-dark .file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(158,27,13,0.25);color:#fff}html.theme--documenter-dark .file.is-danger:active .file-cta,html.theme--documenter-dark .file.is-danger.is-active .file-cta{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}html.theme--documenter-dark .file.is-normal{font-size:1rem}html.theme--documenter-dark .file.is-medium{font-size:1.25rem}html.theme--documenter-dark .file.is-medium .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-large{font-size:1.5rem}html.theme--documenter-dark .file.is-large .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .file.has-name.is-empty .file-cta{border-radius:.4em}html.theme--documenter-dark .file.has-name.is-empty .file-name{display:none}html.theme--documenter-dark .file.is-boxed .file-label{flex-direction:column}html.theme--documenter-dark .file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}html.theme--documenter-dark .file.is-boxed .file-name{border-width:0 1px 1px}html.theme--documenter-dark .file.is-boxed .file-icon{height:1.5em;width:1.5em}html.theme--documenter-dark .file.is-boxed .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-boxed.is-small .file-icon .fa,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}html.theme--documenter-dark .file.is-boxed.is-medium .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.is-boxed.is-large .file-icon .fa{font-size:35px}html.theme--documenter-dark .file.is-boxed.has-name .file-cta{border-radius:.4em .4em 0 0}html.theme--documenter-dark .file.is-boxed.has-name .file-name{border-radius:0 0 .4em .4em;border-width:0 1px 1px}html.theme--documenter-dark .file.is-centered{justify-content:center}html.theme--documenter-dark .file.is-fullwidth .file-label{width:100%}html.theme--documenter-dark .file.is-fullwidth .file-name{flex-grow:1;max-width:none}html.theme--documenter-dark .file.is-right{justify-content:flex-end}html.theme--documenter-dark .file.is-right .file-cta{border-radius:0 .4em .4em 0}html.theme--documenter-dark .file.is-right .file-name{border-radius:.4em 0 0 .4em;border-width:1px 0 1px 1px;order:-1}html.theme--documenter-dark .file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}html.theme--documenter-dark .file-label:hover .file-cta{background-color:#232829;color:#f2f2f2}html.theme--documenter-dark .file-label:hover .file-name{border-color:#596668}html.theme--documenter-dark .file-label:active .file-cta{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .file-label:active .file-name{border-color:#535f61}html.theme--documenter-dark .file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-radius:.4em;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}html.theme--documenter-dark .file-cta{background-color:#282f2f;color:#fff}html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}html.theme--documenter-dark .file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}html.theme--documenter-dark .file-icon .fa{font-size:14px}html.theme--documenter-dark .label{color:#f2f2f2;display:block;font-size:1rem;font-weight:700}html.theme--documenter-dark .label:not(:last-child){margin-bottom:0.5em}html.theme--documenter-dark .label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}html.theme--documenter-dark .label.is-medium{font-size:1.25rem}html.theme--documenter-dark .label.is-large{font-size:1.5rem}html.theme--documenter-dark .help{display:block;font-size:.75rem;margin-top:0.25rem}html.theme--documenter-dark .help.is-white{color:#fff}html.theme--documenter-dark .help.is-black{color:#0a0a0a}html.theme--documenter-dark .help.is-light{color:#ecf0f1}html.theme--documenter-dark .help.is-dark,html.theme--documenter-dark .content kbd.help{color:#282f2f}html.theme--documenter-dark .help.is-primary,html.theme--documenter-dark .docstring>section>a.help.docs-sourcelink{color:#375a7f}html.theme--documenter-dark .help.is-link{color:#1abc9c}html.theme--documenter-dark .help.is-info{color:#024c7d}html.theme--documenter-dark .help.is-success{color:#008438}html.theme--documenter-dark .help.is-warning{color:#ad8100}html.theme--documenter-dark .help.is-danger{color:#9e1b0d}html.theme--documenter-dark .field:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.has-addons{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.has-addons .control:not(:last-child){margin-right:-1px}html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .button,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]){z-index:3}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}html.theme--documenter-dark .field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.has-addons.has-addons-centered{justify-content:center}html.theme--documenter-dark .field.has-addons.has-addons-right{justify-content:flex-end}html.theme--documenter-dark .field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .field.is-grouped{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.is-grouped>.control{flex-shrink:0}html.theme--documenter-dark .field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.is-grouped.is-grouped-centered{justify-content:center}html.theme--documenter-dark .field.is-grouped.is-grouped-right{justify-content:flex-end}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline{flex-wrap:wrap}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:last-child,html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field.is-horizontal{display:flex}}html.theme--documenter-dark .field-label .label{font-size:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}html.theme--documenter-dark .field-label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-normal{padding-top:0.375em}html.theme--documenter-dark .field-label.is-medium{font-size:1.25rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-large{font-size:1.5rem;padding-top:0.375em}}html.theme--documenter-dark .field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}html.theme--documenter-dark .field-body .field{margin-bottom:0}html.theme--documenter-dark .field-body>.field{flex-shrink:1}html.theme--documenter-dark .field-body>.field:not(.is-narrow){flex-grow:1}html.theme--documenter-dark .field-body>.field:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}html.theme--documenter-dark .control.has-icons-left .input:focus~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-left .select:focus~.icon,html.theme--documenter-dark .control.has-icons-right .input:focus~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-right .select:focus~.icon{color:#282f2f}html.theme--documenter-dark .control.has-icons-left .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-small~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-small~.icon{font-size:.75rem}html.theme--documenter-dark .control.has-icons-left .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}html.theme--documenter-dark .control.has-icons-left .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-large~.icon{font-size:1.5rem}html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon{color:#5e6d6f;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}html.theme--documenter-dark .control.has-icons-left .input,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input,html.theme--documenter-dark .control.has-icons-left .select select{padding-left:2.5em}html.theme--documenter-dark .control.has-icons-left .icon.is-left{left:0}html.theme--documenter-dark .control.has-icons-right .input,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input,html.theme--documenter-dark .control.has-icons-right .select select{padding-right:2.5em}html.theme--documenter-dark .control.has-icons-right .icon.is-right{right:0}html.theme--documenter-dark .control.is-loading::after{position:absolute !important;right:.625em;top:0.625em;z-index:4}html.theme--documenter-dark .control.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .control.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .control.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .breadcrumb{font-size:1rem;white-space:nowrap}html.theme--documenter-dark .breadcrumb a{align-items:center;color:#1abc9c;display:flex;justify-content:center;padding:0 .75em}html.theme--documenter-dark .breadcrumb a:hover{color:#1dd2af}html.theme--documenter-dark .breadcrumb li{align-items:center;display:flex}html.theme--documenter-dark .breadcrumb li:first-child a{padding-left:0}html.theme--documenter-dark .breadcrumb li.is-active a{color:#f2f2f2;cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb li+li::before{color:#8c9b9d;content:"\0002f"}html.theme--documenter-dark .breadcrumb ul,html.theme--documenter-dark .breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .breadcrumb .icon:first-child{margin-right:.5em}html.theme--documenter-dark .breadcrumb .icon:last-child{margin-left:.5em}html.theme--documenter-dark .breadcrumb.is-centered ol,html.theme--documenter-dark .breadcrumb.is-centered ul{justify-content:center}html.theme--documenter-dark .breadcrumb.is-right ol,html.theme--documenter-dark .breadcrumb.is-right ul{justify-content:flex-end}html.theme--documenter-dark .breadcrumb.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}html.theme--documenter-dark .breadcrumb.is-medium{font-size:1.25rem}html.theme--documenter-dark .breadcrumb.is-large{font-size:1.5rem}html.theme--documenter-dark .breadcrumb.has-arrow-separator li+li::before{content:"\02192"}html.theme--documenter-dark .breadcrumb.has-bullet-separator li+li::before{content:"\02022"}html.theme--documenter-dark .breadcrumb.has-dot-separator li+li::before{content:"\000b7"}html.theme--documenter-dark .breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}html.theme--documenter-dark .card{background-color:#fff;border-radius:.25rem;box-shadow:#171717;color:#fff;max-width:100%;position:relative}html.theme--documenter-dark .card-footer:first-child,html.theme--documenter-dark .card-content:first-child,html.theme--documenter-dark .card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-footer:last-child,html.theme--documenter-dark .card-content:last-child,html.theme--documenter-dark .card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);display:flex}html.theme--documenter-dark .card-header-title{align-items:center;color:#f2f2f2;display:flex;flex-grow:1;font-weight:700;padding:0.75rem 1rem}html.theme--documenter-dark .card-header-title.is-centered{justify-content:center}html.theme--documenter-dark .card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}html.theme--documenter-dark .card-image{display:block;position:relative}html.theme--documenter-dark .card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-content{background-color:rgba(0,0,0,0);padding:1.5rem}html.theme--documenter-dark .card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #ededed;align-items:stretch;display:flex}html.theme--documenter-dark .card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}html.theme--documenter-dark .card-footer-item:not(:last-child){border-right:1px solid #ededed}html.theme--documenter-dark .card .media:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .dropdown{display:inline-flex;position:relative;vertical-align:top}html.theme--documenter-dark .dropdown.is-active .dropdown-menu,html.theme--documenter-dark .dropdown.is-hoverable:hover .dropdown-menu{display:block}html.theme--documenter-dark .dropdown.is-right .dropdown-menu{left:auto;right:0}html.theme--documenter-dark .dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}html.theme--documenter-dark .dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .dropdown-content{background-color:#282f2f;border-radius:.4em;box-shadow:#171717;padding-bottom:.5rem;padding-top:.5rem}html.theme--documenter-dark .dropdown-item{color:#fff;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}html.theme--documenter-dark a.dropdown-item,html.theme--documenter-dark button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}html.theme--documenter-dark a.dropdown-item:hover,html.theme--documenter-dark button.dropdown-item:hover{background-color:#282f2f;color:#0a0a0a}html.theme--documenter-dark a.dropdown-item.is-active,html.theme--documenter-dark button.dropdown-item.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:0.5rem 0}html.theme--documenter-dark .level{align-items:center;justify-content:space-between}html.theme--documenter-dark .level code{border-radius:.4em}html.theme--documenter-dark .level img{display:inline-block;vertical-align:top}html.theme--documenter-dark .level.is-mobile{display:flex}html.theme--documenter-dark .level.is-mobile .level-left,html.theme--documenter-dark .level.is-mobile .level-right{display:flex}html.theme--documenter-dark .level.is-mobile .level-left+.level-right{margin-top:0}html.theme--documenter-dark .level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level{display:flex}html.theme--documenter-dark .level>.level-item:not(.is-narrow){flex-grow:1}}html.theme--documenter-dark .level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}html.theme--documenter-dark .level-item .title,html.theme--documenter-dark .level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){html.theme--documenter-dark .level-item:not(:last-child){margin-bottom:.75rem}}html.theme--documenter-dark .level-left,html.theme--documenter-dark .level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .level-left .level-item.is-flexible,html.theme--documenter-dark .level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left .level-item:not(:last-child),html.theme--documenter-dark .level-right .level-item:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){html.theme--documenter-dark .level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left{display:flex}}html.theme--documenter-dark .level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-right{display:flex}}html.theme--documenter-dark .media{align-items:flex-start;display:flex;text-align:inherit}html.theme--documenter-dark .media .content:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .media .media{border-top:1px solid rgba(94,109,111,0.5);display:flex;padding-top:.75rem}html.theme--documenter-dark .media .media .content:not(:last-child),html.theme--documenter-dark .media .media .control:not(:last-child){margin-bottom:.5rem}html.theme--documenter-dark .media .media .media{padding-top:.5rem}html.theme--documenter-dark .media .media .media+.media{margin-top:.5rem}html.theme--documenter-dark .media+.media{border-top:1px solid rgba(94,109,111,0.5);margin-top:1rem;padding-top:1rem}html.theme--documenter-dark .media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}html.theme--documenter-dark .media-left,html.theme--documenter-dark .media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .media-left{margin-right:1rem}html.theme--documenter-dark .media-right{margin-left:1rem}html.theme--documenter-dark .media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .media-content{overflow-x:auto}}html.theme--documenter-dark .menu{font-size:1rem}html.theme--documenter-dark .menu.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}html.theme--documenter-dark .menu.is-medium{font-size:1.25rem}html.theme--documenter-dark .menu.is-large{font-size:1.5rem}html.theme--documenter-dark .menu-list{line-height:1.25}html.theme--documenter-dark .menu-list a{border-radius:3px;color:#fff;display:block;padding:0.5em 0.75em}html.theme--documenter-dark .menu-list a:hover{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .menu-list a.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .menu-list li ul{border-left:1px solid #5e6d6f;margin:.75em;padding-left:.75em}html.theme--documenter-dark .menu-label{color:#fff;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}html.theme--documenter-dark .menu-label:not(:first-child){margin-top:1em}html.theme--documenter-dark .menu-label:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .message{background-color:#282f2f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .message strong{color:currentColor}html.theme--documenter-dark .message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .message.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}html.theme--documenter-dark .message.is-medium{font-size:1.25rem}html.theme--documenter-dark .message.is-large{font-size:1.5rem}html.theme--documenter-dark .message.is-white{background-color:#fff}html.theme--documenter-dark .message.is-white .message-header{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .message.is-white .message-body{border-color:#fff}html.theme--documenter-dark .message.is-black{background-color:#fafafa}html.theme--documenter-dark .message.is-black .message-header{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .message.is-black .message-body{border-color:#0a0a0a}html.theme--documenter-dark .message.is-light{background-color:#f9fafb}html.theme--documenter-dark .message.is-light .message-header{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .message.is-light .message-body{border-color:#ecf0f1}html.theme--documenter-dark .message.is-dark,html.theme--documenter-dark .content kbd.message{background-color:#f9fafa}html.theme--documenter-dark .message.is-dark .message-header,html.theme--documenter-dark .content kbd.message .message-header{background-color:#282f2f;color:#fff}html.theme--documenter-dark .message.is-dark .message-body,html.theme--documenter-dark .content kbd.message .message-body{border-color:#282f2f}html.theme--documenter-dark .message.is-primary,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink{background-color:#f1f5f9}html.theme--documenter-dark .message.is-primary .message-header,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-header{background-color:#375a7f;color:#fff}html.theme--documenter-dark .message.is-primary .message-body,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-body{border-color:#375a7f;color:#4d7eb2}html.theme--documenter-dark .message.is-link{background-color:#edfdf9}html.theme--documenter-dark .message.is-link .message-header{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .message.is-link .message-body{border-color:#1abc9c;color:#15987e}html.theme--documenter-dark .message.is-info{background-color:#ebf7ff}html.theme--documenter-dark .message.is-info .message-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .message.is-info .message-body{border-color:#024c7d;color:#0e9dfb}html.theme--documenter-dark .message.is-success{background-color:#ebfff3}html.theme--documenter-dark .message.is-success .message-header{background-color:#008438;color:#fff}html.theme--documenter-dark .message.is-success .message-body{border-color:#008438;color:#00eb64}html.theme--documenter-dark .message.is-warning{background-color:#fffaeb}html.theme--documenter-dark .message.is-warning .message-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .message.is-warning .message-body{border-color:#ad8100;color:#d19c00}html.theme--documenter-dark .message.is-danger{background-color:#fdeeec}html.theme--documenter-dark .message.is-danger .message-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .message.is-danger .message-body{border-color:#9e1b0d;color:#ec311d}html.theme--documenter-dark .message-header{align-items:center;background-color:#fff;border-radius:.4em .4em 0 0;color:rgba(0,0,0,0.7);display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}html.theme--documenter-dark .message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}html.theme--documenter-dark .message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}html.theme--documenter-dark .message-body{border-color:#5e6d6f;border-radius:.4em;border-style:solid;border-width:0 0 0 4px;color:#fff;padding:1.25em 1.5em}html.theme--documenter-dark .message-body code,html.theme--documenter-dark .message-body pre{background-color:#fff}html.theme--documenter-dark .message-body pre code{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}html.theme--documenter-dark .modal.is-active{display:flex}html.theme--documenter-dark .modal-background{background-color:rgba(10,10,10,0.86)}html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px){html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}html.theme--documenter-dark .modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}html.theme--documenter-dark .modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}html.theme--documenter-dark .modal-card-head,html.theme--documenter-dark .modal-card-foot{align-items:center;background-color:#282f2f;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}html.theme--documenter-dark .modal-card-head{border-bottom:1px solid #5e6d6f;border-top-left-radius:8px;border-top-right-radius:8px}html.theme--documenter-dark .modal-card-title{color:#f2f2f2;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}html.theme--documenter-dark .modal-card-foot{border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid #5e6d6f}html.theme--documenter-dark .modal-card-foot .button:not(:last-child){margin-right:.5em}html.theme--documenter-dark .modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}html.theme--documenter-dark .navbar{background-color:#375a7f;min-height:4rem;position:relative;z-index:30}html.theme--documenter-dark .navbar.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-white .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}html.theme--documenter-dark .navbar.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-black .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}html.theme--documenter-dark .navbar.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-light .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}}html.theme--documenter-dark .navbar.is-dark,html.theme--documenter-dark .content kbd.navbar{background-color:#282f2f;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-burger,html.theme--documenter-dark .content kbd.navbar .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-dark .navbar-start>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-end>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#282f2f;color:#fff}}html.theme--documenter-dark .navbar.is-primary,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-burger,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-primary .navbar-start>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-end>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#375a7f;color:#fff}}html.theme--documenter-dark .navbar.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-link .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c;color:#fff}}html.theme--documenter-dark .navbar.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-info .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#024c7d;color:#fff}}html.theme--documenter-dark .navbar.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-success .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#008438;color:#fff}}html.theme--documenter-dark .navbar.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-warning .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ad8100;color:#fff}}html.theme--documenter-dark .navbar.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-danger .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#9e1b0d;color:#fff}}html.theme--documenter-dark .navbar>.container{align-items:stretch;display:flex;min-height:4rem;width:100%}html.theme--documenter-dark .navbar.has-shadow{box-shadow:0 2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-bottom,html.theme--documenter-dark .navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-top{top:0}html.theme--documenter-dark html.has-navbar-fixed-top,html.theme--documenter-dark body.has-navbar-fixed-top{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom,html.theme--documenter-dark body.has-navbar-fixed-bottom{padding-bottom:4rem}html.theme--documenter-dark .navbar-brand,html.theme--documenter-dark .navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:4rem}html.theme--documenter-dark .navbar-brand a.navbar-item:focus,html.theme--documenter-dark .navbar-brand a.navbar-item:hover{background-color:transparent}html.theme--documenter-dark .navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}html.theme--documenter-dark .navbar-burger{color:#fff;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;cursor:pointer;display:block;height:4rem;position:relative;width:4rem;margin-left:auto}html.theme--documenter-dark .navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}html.theme--documenter-dark .navbar-burger span:nth-child(1){top:calc(50% - 6px)}html.theme--documenter-dark .navbar-burger span:nth-child(2){top:calc(50% - 1px)}html.theme--documenter-dark .navbar-burger span:nth-child(3){top:calc(50% + 4px)}html.theme--documenter-dark .navbar-burger:hover{background-color:rgba(0,0,0,0.05)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(2){opacity:0}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}html.theme--documenter-dark .navbar-menu{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{color:#fff;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}html.theme--documenter-dark .navbar-item .icon:only-child,html.theme--documenter-dark .navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}html.theme--documenter-dark a.navbar-item,html.theme--documenter-dark .navbar-link{cursor:pointer}html.theme--documenter-dark a.navbar-item:focus,html.theme--documenter-dark a.navbar-item:focus-within,html.theme--documenter-dark a.navbar-item:hover,html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link:focus,html.theme--documenter-dark .navbar-link:focus-within,html.theme--documenter-dark .navbar-link:hover,html.theme--documenter-dark .navbar-link.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-item{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .navbar-item img{max-height:1.75rem}html.theme--documenter-dark .navbar-item.has-dropdown{padding:0}html.theme--documenter-dark .navbar-item.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-item.is-tab{border-bottom:1px solid transparent;min-height:4rem;padding-bottom:calc(0.5rem - 1px)}html.theme--documenter-dark .navbar-item.is-tab:focus,html.theme--documenter-dark .navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c}html.theme--documenter-dark .navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c;border-bottom-style:solid;border-bottom-width:3px;color:#1abc9c;padding-bottom:calc(0.5rem - 3px)}html.theme--documenter-dark .navbar-content{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-link:not(.is-arrowless){padding-right:2.5em}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after{border-color:#fff;margin-top:-0.375em;right:1.125em}html.theme--documenter-dark .navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}html.theme--documenter-dark .navbar-divider{background-color:rgba(0,0,0,0.2);border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar>.container{display:block}html.theme--documenter-dark .navbar-brand .navbar-item,html.theme--documenter-dark .navbar-tabs .navbar-item{align-items:center;display:flex}html.theme--documenter-dark .navbar-link::after{display:none}html.theme--documenter-dark .navbar-menu{background-color:#375a7f;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}html.theme--documenter-dark .navbar-menu.is-active{display:block}html.theme--documenter-dark .navbar.is-fixed-bottom-touch,html.theme--documenter-dark .navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-touch{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-touch{top:0}html.theme--documenter-dark .navbar.is-fixed-top .navbar-menu,html.theme--documenter-dark .navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 4rem);overflow:auto}html.theme--documenter-dark html.has-navbar-fixed-top-touch,html.theme--documenter-dark body.has-navbar-fixed-top-touch{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-touch,html.theme--documenter-dark body.has-navbar-fixed-bottom-touch{padding-bottom:4rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar,html.theme--documenter-dark .navbar-menu,html.theme--documenter-dark .navbar-start,html.theme--documenter-dark .navbar-end{align-items:stretch;display:flex}html.theme--documenter-dark .navbar{min-height:4rem}html.theme--documenter-dark .navbar.is-spaced{padding:1rem 2rem}html.theme--documenter-dark .navbar.is-spaced .navbar-start,html.theme--documenter-dark .navbar.is-spaced .navbar-end{align-items:center}html.theme--documenter-dark .navbar.is-spaced a.navbar-item,html.theme--documenter-dark .navbar.is-spaced .navbar-link{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent a.navbar-item:hover,html.theme--documenter-dark .navbar.is-transparent a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-transparent .navbar-link:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-link:hover,html.theme--documenter-dark .navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-burger{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{align-items:center;display:flex}html.theme--documenter-dark .navbar-item.has-dropdown{align-items:stretch}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:1px solid rgba(0,0,0,0.2);border-radius:8px 8px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}html.theme--documenter-dark .navbar-menu{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .navbar-start{justify-content:flex-start;margin-right:auto}html.theme--documenter-dark .navbar-end{justify-content:flex-end;margin-left:auto}html.theme--documenter-dark .navbar-dropdown{background-color:#375a7f;border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid rgba(0,0,0,0.2);box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}html.theme--documenter-dark .navbar-dropdown a.navbar-item{padding-right:3rem}html.theme--documenter-dark .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}.navbar.is-spaced html.theme--documenter-dark .navbar-dropdown,html.theme--documenter-dark .navbar-dropdown.is-boxed{border-radius:8px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}html.theme--documenter-dark .navbar-dropdown.is-right{left:auto;right:0}html.theme--documenter-dark .navbar-divider{display:block}html.theme--documenter-dark .navbar>.container .navbar-brand,html.theme--documenter-dark .container>.navbar .navbar-brand{margin-left:-.75rem}html.theme--documenter-dark .navbar>.container .navbar-menu,html.theme--documenter-dark .container>.navbar .navbar-menu{margin-right:-.75rem}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop,html.theme--documenter-dark .navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-desktop{top:0}html.theme--documenter-dark html.has-navbar-fixed-top-desktop,html.theme--documenter-dark body.has-navbar-fixed-top-desktop{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-desktop,html.theme--documenter-dark body.has-navbar-fixed-bottom-desktop{padding-bottom:4rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-top,html.theme--documenter-dark body.has-spaced-navbar-fixed-top{padding-top:6rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-bottom,html.theme--documenter-dark body.has-spaced-navbar-fixed-bottom{padding-bottom:6rem}html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link.is-active{color:#1abc9c}html.theme--documenter-dark a.navbar-item.is-active:not(:focus):not(:hover),html.theme--documenter-dark .navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}html.theme--documenter-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown.is-active .navbar-link{background-color:rgba(0,0,0,0)}}html.theme--documenter-dark .hero.is-fullheight-with-navbar{min-height:calc(100vh - 4rem)}html.theme--documenter-dark .pagination{font-size:1rem;margin:-.25rem}html.theme--documenter-dark .pagination.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}html.theme--documenter-dark .pagination.is-medium{font-size:1.25rem}html.theme--documenter-dark .pagination.is-large{font-size:1.5rem}html.theme--documenter-dark .pagination.is-rounded .pagination-previous,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,html.theme--documenter-dark .pagination.is-rounded .pagination-next,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:9999px}html.theme--documenter-dark .pagination.is-rounded .pagination-link,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}html.theme--documenter-dark .pagination,html.theme--documenter-dark .pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link{border-color:#5e6d6f;color:#1abc9c;min-width:2.5em}html.theme--documenter-dark .pagination-previous:hover,html.theme--documenter-dark .pagination-next:hover,html.theme--documenter-dark .pagination-link:hover{border-color:#8c9b9d;color:#1dd2af}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus{border-color:#8c9b9d}html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-previous.is-disabled,html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-next.is-disabled,html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-link.is-disabled{background-color:#5e6d6f;border-color:#5e6d6f;box-shadow:none;color:#fff;opacity:0.5}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{padding-left:.75em;padding-right:.75em;white-space:nowrap}html.theme--documenter-dark .pagination-link.is-current{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .pagination-ellipsis{color:#8c9b9d;pointer-events:none}html.theme--documenter-dark .pagination-list{flex-wrap:wrap}html.theme--documenter-dark .pagination-list li{list-style:none}@media screen and (max-width: 768px){html.theme--documenter-dark .pagination{flex-wrap:wrap}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination-previous{order:2}html.theme--documenter-dark .pagination-next{order:3}html.theme--documenter-dark .pagination{justify-content:space-between;margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination.is-centered .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-centered .pagination-list{justify-content:center;order:2}html.theme--documenter-dark .pagination.is-centered .pagination-next{order:3}html.theme--documenter-dark .pagination.is-right .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-right .pagination-next{order:2}html.theme--documenter-dark .pagination.is-right .pagination-list{justify-content:flex-end;order:3}}html.theme--documenter-dark .panel{border-radius:8px;box-shadow:#171717;font-size:1rem}html.theme--documenter-dark .panel:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}html.theme--documenter-dark .panel.is-white .panel-block.is-active .panel-icon{color:#fff}html.theme--documenter-dark .panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}html.theme--documenter-dark .panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}html.theme--documenter-dark .panel.is-light .panel-heading{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .panel.is-light .panel-tabs a.is-active{border-bottom-color:#ecf0f1}html.theme--documenter-dark .panel.is-light .panel-block.is-active .panel-icon{color:#ecf0f1}html.theme--documenter-dark .panel.is-dark .panel-heading,html.theme--documenter-dark .content kbd.panel .panel-heading{background-color:#282f2f;color:#fff}html.theme--documenter-dark .panel.is-dark .panel-tabs a.is-active,html.theme--documenter-dark .content kbd.panel .panel-tabs a.is-active{border-bottom-color:#282f2f}html.theme--documenter-dark .panel.is-dark .panel-block.is-active .panel-icon,html.theme--documenter-dark .content kbd.panel .panel-block.is-active .panel-icon{color:#282f2f}html.theme--documenter-dark .panel.is-primary .panel-heading,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#375a7f;color:#fff}html.theme--documenter-dark .panel.is-primary .panel-tabs a.is-active,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#375a7f}html.theme--documenter-dark .panel.is-primary .panel-block.is-active .panel-icon,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#375a7f}html.theme--documenter-dark .panel.is-link .panel-heading{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .panel.is-link .panel-tabs a.is-active{border-bottom-color:#1abc9c}html.theme--documenter-dark .panel.is-link .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel.is-info .panel-heading{background-color:#024c7d;color:#fff}html.theme--documenter-dark .panel.is-info .panel-tabs a.is-active{border-bottom-color:#024c7d}html.theme--documenter-dark .panel.is-info .panel-block.is-active .panel-icon{color:#024c7d}html.theme--documenter-dark .panel.is-success .panel-heading{background-color:#008438;color:#fff}html.theme--documenter-dark .panel.is-success .panel-tabs a.is-active{border-bottom-color:#008438}html.theme--documenter-dark .panel.is-success .panel-block.is-active .panel-icon{color:#008438}html.theme--documenter-dark .panel.is-warning .panel-heading{background-color:#ad8100;color:#fff}html.theme--documenter-dark .panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ad8100}html.theme--documenter-dark .panel.is-warning .panel-block.is-active .panel-icon{color:#ad8100}html.theme--documenter-dark .panel.is-danger .panel-heading{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .panel.is-danger .panel-tabs a.is-active{border-bottom-color:#9e1b0d}html.theme--documenter-dark .panel.is-danger .panel-block.is-active .panel-icon{color:#9e1b0d}html.theme--documenter-dark .panel-tabs:not(:last-child),html.theme--documenter-dark .panel-block:not(:last-child){border-bottom:1px solid #ededed}html.theme--documenter-dark .panel-heading{background-color:#343c3d;border-radius:8px 8px 0 0;color:#f2f2f2;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}html.theme--documenter-dark .panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}html.theme--documenter-dark .panel-tabs a{border-bottom:1px solid #5e6d6f;margin-bottom:-1px;padding:0.5em}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#343c3d;color:#17a689}html.theme--documenter-dark .panel-list a{color:#fff}html.theme--documenter-dark .panel-list a:hover{color:#1abc9c}html.theme--documenter-dark .panel-block{align-items:center;color:#f2f2f2;display:flex;justify-content:flex-start;padding:0.5em 0.75em}html.theme--documenter-dark .panel-block input[type="checkbox"]{margin-right:.75em}html.theme--documenter-dark .panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}html.theme--documenter-dark .panel-block.is-wrapped{flex-wrap:wrap}html.theme--documenter-dark .panel-block.is-active{border-left-color:#1abc9c;color:#17a689}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel-block:last-child{border-bottom-left-radius:8px;border-bottom-right-radius:8px}html.theme--documenter-dark a.panel-block,html.theme--documenter-dark label.panel-block{cursor:pointer}html.theme--documenter-dark a.panel-block:hover,html.theme--documenter-dark label.panel-block:hover{background-color:#282f2f}html.theme--documenter-dark .panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#fff;margin-right:.75em}html.theme--documenter-dark .panel-icon .fa{font-size:inherit;line-height:inherit}html.theme--documenter-dark .tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}html.theme--documenter-dark .tabs a{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;color:#fff;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}html.theme--documenter-dark .tabs a:hover{border-bottom-color:#f2f2f2;color:#f2f2f2}html.theme--documenter-dark .tabs li{display:block}html.theme--documenter-dark .tabs li.is-active a{border-bottom-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .tabs ul{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}html.theme--documenter-dark .tabs ul.is-left{padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}html.theme--documenter-dark .tabs .icon:first-child{margin-right:.5em}html.theme--documenter-dark .tabs .icon:last-child{margin-left:.5em}html.theme--documenter-dark .tabs.is-centered ul{justify-content:center}html.theme--documenter-dark .tabs.is-right ul{justify-content:flex-end}html.theme--documenter-dark .tabs.is-boxed a{border:1px solid transparent;border-radius:.4em .4em 0 0}html.theme--documenter-dark .tabs.is-boxed a:hover{background-color:#282f2f;border-bottom-color:#5e6d6f}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#fff;border-color:#5e6d6f;border-bottom-color:rgba(0,0,0,0) !important}html.theme--documenter-dark .tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .tabs.is-toggle a{border-color:#5e6d6f;border-style:solid;border-width:1px;margin-bottom:0;position:relative}html.theme--documenter-dark .tabs.is-toggle a:hover{background-color:#282f2f;border-color:#8c9b9d;z-index:2}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .tabs.is-toggle li:first-child a{border-top-left-radius:.4em;border-bottom-left-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li:last-child a{border-top-right-radius:.4em;border-bottom-right-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li.is-active a{background-color:#1abc9c;border-color:#1abc9c;color:#fff;z-index:1}html.theme--documenter-dark .tabs.is-toggle ul{border-bottom:none}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}html.theme--documenter-dark .tabs.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}html.theme--documenter-dark .tabs.is-medium{font-size:1.25rem}html.theme--documenter-dark .tabs.is-large{font-size:1.5rem}html.theme--documenter-dark .column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>html.theme--documenter-dark .column.is-narrow{flex:none;width:unset}.columns.is-mobile>html.theme--documenter-dark .column.is-full{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-half{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-half{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-0{flex:none;width:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-0{margin-left:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-1{flex:none;width:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-2{margin-left:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-3{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-3{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-4{flex:none;width:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-5{margin-left:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-6{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-6{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-7{flex:none;width:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-8{margin-left:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-9{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-9{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-10{flex:none;width:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-11{margin-left:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-12{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){html.theme--documenter-dark .column.is-narrow-mobile{flex:none;width:unset}html.theme--documenter-dark .column.is-full-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-mobile{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-mobile{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-mobile{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-mobile{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-mobile{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-mobile{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-mobile{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-mobile{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-mobile{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-mobile{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-mobile{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-mobile{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-mobile{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-mobile{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-mobile{margin-left:80%}html.theme--documenter-dark .column.is-0-mobile{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-mobile{margin-left:0%}html.theme--documenter-dark .column.is-1-mobile{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-mobile{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-mobile{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-mobile{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-mobile{margin-left:25%}html.theme--documenter-dark .column.is-4-mobile{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-mobile{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-mobile{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-mobile{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-mobile{margin-left:50%}html.theme--documenter-dark .column.is-7-mobile{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-mobile{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-mobile{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-mobile{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-mobile{margin-left:75%}html.theme--documenter-dark .column.is-10-mobile{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-mobile{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-mobile{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-mobile{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .column.is-narrow,html.theme--documenter-dark .column.is-narrow-tablet{flex:none;width:unset}html.theme--documenter-dark .column.is-full,html.theme--documenter-dark .column.is-full-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters,html.theme--documenter-dark .column.is-three-quarters-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds,html.theme--documenter-dark .column.is-two-thirds-tablet{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half,html.theme--documenter-dark .column.is-half-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third,html.theme--documenter-dark .column.is-one-third-tablet{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter,html.theme--documenter-dark .column.is-one-quarter-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth,html.theme--documenter-dark .column.is-one-fifth-tablet{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths,html.theme--documenter-dark .column.is-two-fifths-tablet{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths,html.theme--documenter-dark .column.is-three-fifths-tablet{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths,html.theme--documenter-dark .column.is-four-fifths-tablet{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters,html.theme--documenter-dark .column.is-offset-three-quarters-tablet{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds,html.theme--documenter-dark .column.is-offset-two-thirds-tablet{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half,html.theme--documenter-dark .column.is-offset-half-tablet{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third,html.theme--documenter-dark .column.is-offset-one-third-tablet{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter,html.theme--documenter-dark .column.is-offset-one-quarter-tablet{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth,html.theme--documenter-dark .column.is-offset-one-fifth-tablet{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths,html.theme--documenter-dark .column.is-offset-two-fifths-tablet{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths,html.theme--documenter-dark .column.is-offset-three-fifths-tablet{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths,html.theme--documenter-dark .column.is-offset-four-fifths-tablet{margin-left:80%}html.theme--documenter-dark .column.is-0,html.theme--documenter-dark .column.is-0-tablet{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0,html.theme--documenter-dark .column.is-offset-0-tablet{margin-left:0%}html.theme--documenter-dark .column.is-1,html.theme--documenter-dark .column.is-1-tablet{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1,html.theme--documenter-dark .column.is-offset-1-tablet{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2,html.theme--documenter-dark .column.is-2-tablet{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2,html.theme--documenter-dark .column.is-offset-2-tablet{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3,html.theme--documenter-dark .column.is-3-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3,html.theme--documenter-dark .column.is-offset-3-tablet{margin-left:25%}html.theme--documenter-dark .column.is-4,html.theme--documenter-dark .column.is-4-tablet{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4,html.theme--documenter-dark .column.is-offset-4-tablet{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5,html.theme--documenter-dark .column.is-5-tablet{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5,html.theme--documenter-dark .column.is-offset-5-tablet{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6,html.theme--documenter-dark .column.is-6-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6,html.theme--documenter-dark .column.is-offset-6-tablet{margin-left:50%}html.theme--documenter-dark .column.is-7,html.theme--documenter-dark .column.is-7-tablet{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7,html.theme--documenter-dark .column.is-offset-7-tablet{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8,html.theme--documenter-dark .column.is-8-tablet{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8,html.theme--documenter-dark .column.is-offset-8-tablet{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9,html.theme--documenter-dark .column.is-9-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9,html.theme--documenter-dark .column.is-offset-9-tablet{margin-left:75%}html.theme--documenter-dark .column.is-10,html.theme--documenter-dark .column.is-10-tablet{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10,html.theme--documenter-dark .column.is-offset-10-tablet{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11,html.theme--documenter-dark .column.is-11-tablet{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11,html.theme--documenter-dark .column.is-offset-11-tablet{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12,html.theme--documenter-dark .column.is-12-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12,html.theme--documenter-dark .column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){html.theme--documenter-dark .column.is-narrow-touch{flex:none;width:unset}html.theme--documenter-dark .column.is-full-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-touch{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-touch{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-touch{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-touch{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-touch{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-touch{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-touch{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-touch{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-touch{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-touch{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-touch{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-touch{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-touch{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-touch{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-touch{margin-left:80%}html.theme--documenter-dark .column.is-0-touch{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-touch{margin-left:0%}html.theme--documenter-dark .column.is-1-touch{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-touch{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-touch{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-touch{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-touch{margin-left:25%}html.theme--documenter-dark .column.is-4-touch{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-touch{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-touch{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-touch{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-touch{margin-left:50%}html.theme--documenter-dark .column.is-7-touch{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-touch{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-touch{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-touch{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-touch{margin-left:75%}html.theme--documenter-dark .column.is-10-touch{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-touch{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-touch{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-touch{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){html.theme--documenter-dark .column.is-narrow-desktop{flex:none;width:unset}html.theme--documenter-dark .column.is-full-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-desktop{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-desktop{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-desktop{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-desktop{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-desktop{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-desktop{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-desktop{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-desktop{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-desktop{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-desktop{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-desktop{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-desktop{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-desktop{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-desktop{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-desktop{margin-left:80%}html.theme--documenter-dark .column.is-0-desktop{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-desktop{margin-left:0%}html.theme--documenter-dark .column.is-1-desktop{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-desktop{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-desktop{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-desktop{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-desktop{margin-left:25%}html.theme--documenter-dark .column.is-4-desktop{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-desktop{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-desktop{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-desktop{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-desktop{margin-left:50%}html.theme--documenter-dark .column.is-7-desktop{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-desktop{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-desktop{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-desktop{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-desktop{margin-left:75%}html.theme--documenter-dark .column.is-10-desktop{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-desktop{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-desktop{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-desktop{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){html.theme--documenter-dark .column.is-narrow-widescreen{flex:none;width:unset}html.theme--documenter-dark .column.is-full-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-widescreen{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-widescreen{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-widescreen{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-widescreen{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-widescreen{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-widescreen{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-widescreen{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-widescreen{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-widescreen{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-widescreen{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-widescreen{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-widescreen{margin-left:80%}html.theme--documenter-dark .column.is-0-widescreen{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-widescreen{margin-left:0%}html.theme--documenter-dark .column.is-1-widescreen{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-widescreen{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-widescreen{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-widescreen{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-4-widescreen{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-widescreen{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-widescreen{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-widescreen{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-7-widescreen{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-widescreen{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-widescreen{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-widescreen{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-10-widescreen{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-widescreen{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-widescreen{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-widescreen{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){html.theme--documenter-dark .column.is-narrow-fullhd{flex:none;width:unset}html.theme--documenter-dark .column.is-full-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-fullhd{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-fullhd{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-fullhd{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-fullhd{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-fullhd{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-fullhd{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-fullhd{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-fullhd{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-fullhd{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-fullhd{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-fullhd{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-fullhd{margin-left:80%}html.theme--documenter-dark .column.is-0-fullhd{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-fullhd{margin-left:0%}html.theme--documenter-dark .column.is-1-fullhd{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-fullhd{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-fullhd{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-fullhd{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-4-fullhd{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-fullhd{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-fullhd{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-fullhd{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-7-fullhd{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-fullhd{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-fullhd{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-fullhd{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-10-fullhd{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-fullhd{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-fullhd{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-fullhd{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-fullhd{margin-left:100%}}html.theme--documenter-dark .columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .columns:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}html.theme--documenter-dark .columns.is-centered{justify-content:center}html.theme--documenter-dark .columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}html.theme--documenter-dark .columns.is-gapless>.column{margin:0;padding:0 !important}html.theme--documenter-dark .columns.is-gapless:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .columns.is-gapless:last-child{margin-bottom:0}html.theme--documenter-dark .columns.is-mobile{display:flex}html.theme--documenter-dark .columns.is-multiline{flex-wrap:wrap}html.theme--documenter-dark .columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-desktop{display:flex}}html.theme--documenter-dark .columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}html.theme--documenter-dark .columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}html.theme--documenter-dark .columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-0-fullhd{--columnGap: 0rem}}html.theme--documenter-dark .columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-1-fullhd{--columnGap: .25rem}}html.theme--documenter-dark .columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-2-fullhd{--columnGap: .5rem}}html.theme--documenter-dark .columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-3-fullhd{--columnGap: .75rem}}html.theme--documenter-dark .columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-4-fullhd{--columnGap: 1rem}}html.theme--documenter-dark .columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}html.theme--documenter-dark .columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}html.theme--documenter-dark .columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}html.theme--documenter-dark .columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-8-fullhd{--columnGap: 2rem}}html.theme--documenter-dark .tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}html.theme--documenter-dark .tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .tile.is-ancestor:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .tile.is-ancestor:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .tile.is-child{margin:0 !important}html.theme--documenter-dark .tile.is-parent{padding:.75rem}html.theme--documenter-dark .tile.is-vertical{flex-direction:column}html.theme--documenter-dark .tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{html.theme--documenter-dark .tile:not(.is-child){display:flex}html.theme--documenter-dark .tile.is-1{flex:none;width:8.33333337%}html.theme--documenter-dark .tile.is-2{flex:none;width:16.66666674%}html.theme--documenter-dark .tile.is-3{flex:none;width:25%}html.theme--documenter-dark .tile.is-4{flex:none;width:33.33333337%}html.theme--documenter-dark .tile.is-5{flex:none;width:41.66666674%}html.theme--documenter-dark .tile.is-6{flex:none;width:50%}html.theme--documenter-dark .tile.is-7{flex:none;width:58.33333337%}html.theme--documenter-dark .tile.is-8{flex:none;width:66.66666674%}html.theme--documenter-dark .tile.is-9{flex:none;width:75%}html.theme--documenter-dark .tile.is-10{flex:none;width:83.33333337%}html.theme--documenter-dark .tile.is-11{flex:none;width:91.66666674%}html.theme--documenter-dark .tile.is-12{flex:none;width:100%}}html.theme--documenter-dark .hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}html.theme--documenter-dark .hero .navbar{background:none}html.theme--documenter-dark .hero .tabs ul{border-bottom:none}html.theme--documenter-dark .hero.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-white strong{color:inherit}html.theme--documenter-dark .hero.is-white .title{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .subtitle{color:rgba(10,10,10,0.9)}html.theme--documenter-dark .hero.is-white .subtitle a:not(.button),html.theme--documenter-dark .hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-white .navbar-menu{background-color:#fff}}html.theme--documenter-dark .hero.is-white .navbar-item,html.theme--documenter-dark .hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}html.theme--documenter-dark .hero.is-white a.navbar-item:hover,html.theme--documenter-dark .hero.is-white a.navbar-item.is-active,html.theme--documenter-dark .hero.is-white .navbar-link:hover,html.theme--documenter-dark .hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}html.theme--documenter-dark .hero.is-white .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-white .tabs li.is-active a{color:#fff !important;opacity:1}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}html.theme--documenter-dark .hero.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-black strong{color:inherit}html.theme--documenter-dark .hero.is-black .title{color:#fff}html.theme--documenter-dark .hero.is-black .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-black .subtitle a:not(.button),html.theme--documenter-dark .hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-black .navbar-menu{background-color:#0a0a0a}}html.theme--documenter-dark .hero.is-black .navbar-item,html.theme--documenter-dark .hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-black a.navbar-item:hover,html.theme--documenter-dark .hero.is-black a.navbar-item.is-active,html.theme--documenter-dark .hero.is-black .navbar-link:hover,html.theme--documenter-dark .hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .hero.is-black .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-black .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-black .tabs li.is-active a{color:#0a0a0a !important;opacity:1}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}html.theme--documenter-dark .hero.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-light strong{color:inherit}html.theme--documenter-dark .hero.is-light .title{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .subtitle{color:rgba(0,0,0,0.9)}html.theme--documenter-dark .hero.is-light .subtitle a:not(.button),html.theme--documenter-dark .hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-light .navbar-menu{background-color:#ecf0f1}}html.theme--documenter-dark .hero.is-light .navbar-item,html.theme--documenter-dark .hero.is-light .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a.navbar-item:hover,html.theme--documenter-dark .hero.is-light a.navbar-item.is-active,html.theme--documenter-dark .hero.is-light .navbar-link:hover,html.theme--documenter-dark .hero.is-light .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}html.theme--documenter-dark .hero.is-light .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-light .tabs li.is-active a{color:#ecf0f1 !important;opacity:1}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .hero.is-light.is-bold{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}}html.theme--documenter-dark .hero.is-dark,html.theme--documenter-dark .content kbd.hero{background-color:#282f2f;color:#fff}html.theme--documenter-dark .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-dark strong,html.theme--documenter-dark .content kbd.hero strong{color:inherit}html.theme--documenter-dark .hero.is-dark .title,html.theme--documenter-dark .content kbd.hero .title{color:#fff}html.theme--documenter-dark .hero.is-dark .subtitle,html.theme--documenter-dark .content kbd.hero .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-dark .subtitle a:not(.button),html.theme--documenter-dark .content kbd.hero .subtitle a:not(.button),html.theme--documenter-dark .hero.is-dark .subtitle strong,html.theme--documenter-dark .content kbd.hero .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-dark .navbar-menu,html.theme--documenter-dark .content kbd.hero .navbar-menu{background-color:#282f2f}}html.theme--documenter-dark .hero.is-dark .navbar-item,html.theme--documenter-dark .content kbd.hero .navbar-item,html.theme--documenter-dark .hero.is-dark .navbar-link,html.theme--documenter-dark .content kbd.hero .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-dark a.navbar-item:hover,html.theme--documenter-dark .content kbd.hero a.navbar-item:hover,html.theme--documenter-dark .hero.is-dark a.navbar-item.is-active,html.theme--documenter-dark .content kbd.hero a.navbar-item.is-active,html.theme--documenter-dark .hero.is-dark .navbar-link:hover,html.theme--documenter-dark .content kbd.hero .navbar-link:hover,html.theme--documenter-dark .hero.is-dark .navbar-link.is-active,html.theme--documenter-dark .content kbd.hero .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .hero.is-dark .tabs a,html.theme--documenter-dark .content kbd.hero .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-dark .tabs a:hover,html.theme--documenter-dark .content kbd.hero .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-dark .tabs li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs li.is-active a{color:#282f2f !important;opacity:1}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#282f2f}html.theme--documenter-dark .hero.is-dark.is-bold,html.theme--documenter-dark .content kbd.hero.is-bold{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-dark.is-bold .navbar-menu,html.theme--documenter-dark .content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}}html.theme--documenter-dark .hero.is-primary,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-primary strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink strong{color:inherit}html.theme--documenter-dark .hero.is-primary .title,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .title{color:#fff}html.theme--documenter-dark .hero.is-primary .subtitle,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-primary .subtitle a:not(.button),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),html.theme--documenter-dark .hero.is-primary .subtitle strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-primary .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#375a7f}}html.theme--documenter-dark .hero.is-primary .navbar-item,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-item,html.theme--documenter-dark .hero.is-primary .navbar-link,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-primary a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,html.theme--documenter-dark .hero.is-primary a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,html.theme--documenter-dark .hero.is-primary .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link:hover,html.theme--documenter-dark .hero.is-primary .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .hero.is-primary .tabs a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-primary .tabs a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-primary .tabs li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{color:#375a7f !important;opacity:1}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#375a7f}html.theme--documenter-dark .hero.is-primary.is-bold,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-primary.is-bold .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}}html.theme--documenter-dark .hero.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-link strong{color:inherit}html.theme--documenter-dark .hero.is-link .title{color:#fff}html.theme--documenter-dark .hero.is-link .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-link .subtitle a:not(.button),html.theme--documenter-dark .hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-link .navbar-menu{background-color:#1abc9c}}html.theme--documenter-dark .hero.is-link .navbar-item,html.theme--documenter-dark .hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-link a.navbar-item:hover,html.theme--documenter-dark .hero.is-link a.navbar-item.is-active,html.theme--documenter-dark .hero.is-link .navbar-link:hover,html.theme--documenter-dark .hero.is-link .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .hero.is-link .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-link .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-link .tabs li.is-active a{color:#1abc9c !important;opacity:1}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#1abc9c}html.theme--documenter-dark .hero.is-link.is-bold{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}}html.theme--documenter-dark .hero.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-info strong{color:inherit}html.theme--documenter-dark .hero.is-info .title{color:#fff}html.theme--documenter-dark .hero.is-info .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-info .subtitle a:not(.button),html.theme--documenter-dark .hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-info .navbar-menu{background-color:#024c7d}}html.theme--documenter-dark .hero.is-info .navbar-item,html.theme--documenter-dark .hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-info a.navbar-item:hover,html.theme--documenter-dark .hero.is-info a.navbar-item.is-active,html.theme--documenter-dark .hero.is-info .navbar-link:hover,html.theme--documenter-dark .hero.is-info .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .hero.is-info .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-info .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-info .tabs li.is-active a{color:#024c7d !important;opacity:1}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#024c7d}html.theme--documenter-dark .hero.is-info.is-bold{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}}html.theme--documenter-dark .hero.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-success strong{color:inherit}html.theme--documenter-dark .hero.is-success .title{color:#fff}html.theme--documenter-dark .hero.is-success .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-success .subtitle a:not(.button),html.theme--documenter-dark .hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-success .navbar-menu{background-color:#008438}}html.theme--documenter-dark .hero.is-success .navbar-item,html.theme--documenter-dark .hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-success a.navbar-item:hover,html.theme--documenter-dark .hero.is-success a.navbar-item.is-active,html.theme--documenter-dark .hero.is-success .navbar-link:hover,html.theme--documenter-dark .hero.is-success .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .hero.is-success .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-success .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-success .tabs li.is-active a{color:#008438 !important;opacity:1}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#008438}html.theme--documenter-dark .hero.is-success.is-bold{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}}html.theme--documenter-dark .hero.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-warning strong{color:inherit}html.theme--documenter-dark .hero.is-warning .title{color:#fff}html.theme--documenter-dark .hero.is-warning .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-warning .subtitle a:not(.button),html.theme--documenter-dark .hero.is-warning .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-warning .navbar-menu{background-color:#ad8100}}html.theme--documenter-dark .hero.is-warning .navbar-item,html.theme--documenter-dark .hero.is-warning .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-warning a.navbar-item:hover,html.theme--documenter-dark .hero.is-warning a.navbar-item.is-active,html.theme--documenter-dark .hero.is-warning .navbar-link:hover,html.theme--documenter-dark .hero.is-warning .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .hero.is-warning .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-warning .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-warning .tabs li.is-active a{color:#ad8100 !important;opacity:1}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ad8100}html.theme--documenter-dark .hero.is-warning.is-bold{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}}html.theme--documenter-dark .hero.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-danger strong{color:inherit}html.theme--documenter-dark .hero.is-danger .title{color:#fff}html.theme--documenter-dark .hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-danger .subtitle a:not(.button),html.theme--documenter-dark .hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-danger .navbar-menu{background-color:#9e1b0d}}html.theme--documenter-dark .hero.is-danger .navbar-item,html.theme--documenter-dark .hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-danger a.navbar-item:hover,html.theme--documenter-dark .hero.is-danger a.navbar-item.is-active,html.theme--documenter-dark .hero.is-danger .navbar-link:hover,html.theme--documenter-dark .hero.is-danger .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .hero.is-danger .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-danger .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-danger .tabs li.is-active a{color:#9e1b0d !important;opacity:1}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#9e1b0d}html.theme--documenter-dark .hero.is-danger.is-bold{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}}html.theme--documenter-dark .hero.is-small .hero-body,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding:1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-large .hero-body{padding:18rem 6rem}}html.theme--documenter-dark .hero.is-halfheight .hero-body,html.theme--documenter-dark .hero.is-fullheight .hero-body,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}html.theme--documenter-dark .hero.is-halfheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .hero.is-halfheight{min-height:50vh}html.theme--documenter-dark .hero.is-fullheight{min-height:100vh}html.theme--documenter-dark .hero-video{overflow:hidden}html.theme--documenter-dark .hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}html.theme--documenter-dark .hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-video{display:none}}html.theme--documenter-dark .hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-buttons .button{display:flex}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-buttons{display:flex;justify-content:center}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-right:1.5rem}}html.theme--documenter-dark .hero-head,html.theme--documenter-dark .hero-foot{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-body{padding:3rem 3rem}}html.theme--documenter-dark .section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){html.theme--documenter-dark .section{padding:3rem 3rem}html.theme--documenter-dark .section.is-medium{padding:9rem 4.5rem}html.theme--documenter-dark .section.is-large{padding:18rem 6rem}}html.theme--documenter-dark .footer{background-color:#282f2f;padding:3rem 1.5rem 6rem}html.theme--documenter-dark hr{height:1px}html.theme--documenter-dark h6{text-transform:uppercase;letter-spacing:0.5px}html.theme--documenter-dark .hero{background-color:#343c3d}html.theme--documenter-dark a{transition:all 200ms ease}html.theme--documenter-dark .button{transition:all 200ms ease;border-width:1px;color:#fff}html.theme--documenter-dark .button.is-active,html.theme--documenter-dark .button.is-focused,html.theme--documenter-dark .button:active,html.theme--documenter-dark .button:focus{box-shadow:0 0 0 2px rgba(140,155,157,0.5)}html.theme--documenter-dark .button.is-white.is-hovered,html.theme--documenter-dark .button.is-white:hover{background-color:#fff}html.theme--documenter-dark .button.is-white.is-active,html.theme--documenter-dark .button.is-white.is-focused,html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white:focus{border-color:#fff;box-shadow:0 0 0 2px rgba(255,255,255,0.5)}html.theme--documenter-dark .button.is-black.is-hovered,html.theme--documenter-dark .button.is-black:hover{background-color:#1d1d1d}html.theme--documenter-dark .button.is-black.is-active,html.theme--documenter-dark .button.is-black.is-focused,html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black:focus{border-color:#0a0a0a;box-shadow:0 0 0 2px rgba(10,10,10,0.5)}html.theme--documenter-dark .button.is-light.is-hovered,html.theme--documenter-dark .button.is-light:hover{background-color:#fff}html.theme--documenter-dark .button.is-light.is-active,html.theme--documenter-dark .button.is-light.is-focused,html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light:focus{border-color:#ecf0f1;box-shadow:0 0 0 2px rgba(236,240,241,0.5)}html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered,html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover{background-color:#3a4344}html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused,html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus{border-color:#282f2f;box-shadow:0 0 0 2px rgba(40,47,47,0.5)}html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover{background-color:#436d9a}html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink,html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus{border-color:#375a7f;box-shadow:0 0 0 2px rgba(55,90,127,0.5)}html.theme--documenter-dark .button.is-link.is-hovered,html.theme--documenter-dark .button.is-link:hover{background-color:#1fdeb8}html.theme--documenter-dark .button.is-link.is-active,html.theme--documenter-dark .button.is-link.is-focused,html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link:focus{border-color:#1abc9c;box-shadow:0 0 0 2px rgba(26,188,156,0.5)}html.theme--documenter-dark .button.is-info.is-hovered,html.theme--documenter-dark .button.is-info:hover{background-color:#0363a3}html.theme--documenter-dark .button.is-info.is-active,html.theme--documenter-dark .button.is-info.is-focused,html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info:focus{border-color:#024c7d;box-shadow:0 0 0 2px rgba(2,76,125,0.5)}html.theme--documenter-dark .button.is-success.is-hovered,html.theme--documenter-dark .button.is-success:hover{background-color:#00aa48}html.theme--documenter-dark .button.is-success.is-active,html.theme--documenter-dark .button.is-success.is-focused,html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success:focus{border-color:#008438;box-shadow:0 0 0 2px rgba(0,132,56,0.5)}html.theme--documenter-dark .button.is-warning.is-hovered,html.theme--documenter-dark .button.is-warning:hover{background-color:#d39e00}html.theme--documenter-dark .button.is-warning.is-active,html.theme--documenter-dark .button.is-warning.is-focused,html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning:focus{border-color:#ad8100;box-shadow:0 0 0 2px rgba(173,129,0,0.5)}html.theme--documenter-dark .button.is-danger.is-hovered,html.theme--documenter-dark .button.is-danger:hover{background-color:#c12110}html.theme--documenter-dark .button.is-danger.is-active,html.theme--documenter-dark .button.is-danger.is-focused,html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger:focus{border-color:#9e1b0d;box-shadow:0 0 0 2px rgba(158,27,13,0.5)}html.theme--documenter-dark .label{color:#dbdee0}html.theme--documenter-dark .button,html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .select,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea{height:2.5em}html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .textarea{transition:all 200ms ease;box-shadow:none;border-width:1px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .select:after,html.theme--documenter-dark .select select{border-width:1px}html.theme--documenter-dark .control.has-addons .button,html.theme--documenter-dark .control.has-addons .input,html.theme--documenter-dark .control.has-addons #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-addons form.docs-search>input,html.theme--documenter-dark .control.has-addons .select{margin-right:-1px}html.theme--documenter-dark .notification{background-color:#343c3d}html.theme--documenter-dark .card{box-shadow:none;border:1px solid #343c3d;background-color:#282f2f;border-radius:.4em}html.theme--documenter-dark .card .card-image img{border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-header{box-shadow:none;background-color:rgba(18,18,18,0.2);border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-footer{background-color:rgba(18,18,18,0.2)}html.theme--documenter-dark .card .card-footer,html.theme--documenter-dark .card .card-footer-item{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .notification.is-white a:not(.button){color:#0a0a0a;text-decoration:underline}html.theme--documenter-dark .notification.is-black a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-light a:not(.button){color:rgba(0,0,0,0.7);text-decoration:underline}html.theme--documenter-dark .notification.is-dark a:not(.button),html.theme--documenter-dark .content kbd.notification a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-primary a:not(.button),html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-link a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-info a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-success a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-warning a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-danger a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .tag,html.theme--documenter-dark .content kbd,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{border-radius:.4em}html.theme--documenter-dark .menu-list a{transition:all 300ms ease}html.theme--documenter-dark .modal-card-body{background-color:#282f2f}html.theme--documenter-dark .modal-card-foot,html.theme--documenter-dark .modal-card-head{border-color:#343c3d}html.theme--documenter-dark .message-header{font-weight:700;background-color:#343c3d;color:#fff}html.theme--documenter-dark .message-body{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .navbar{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent{background:none}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar .navbar-menu{background-color:#375a7f;border-radius:0 0 .4em .4em}}html.theme--documenter-dark .hero .navbar,html.theme--documenter-dark body>.navbar{border-radius:0}html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous{border-width:1px}html.theme--documenter-dark .panel-block,html.theme--documenter-dark .panel-heading,html.theme--documenter-dark .panel-tabs{border-width:1px}html.theme--documenter-dark .panel-block:first-child,html.theme--documenter-dark .panel-heading:first-child,html.theme--documenter-dark .panel-tabs:first-child{border-top-width:1px}html.theme--documenter-dark .panel-heading{font-weight:700}html.theme--documenter-dark .panel-tabs a{border-width:1px;margin-bottom:-1px}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#17a689}html.theme--documenter-dark .panel-block:hover{color:#1dd2af}html.theme--documenter-dark .panel-block:hover .panel-icon{color:#1dd2af}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#17a689}html.theme--documenter-dark .tabs a{border-bottom-width:1px;margin-bottom:-1px}html.theme--documenter-dark .tabs ul{border-bottom-width:1px}html.theme--documenter-dark .tabs.is-boxed a{border-width:1px}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#1f2424}html.theme--documenter-dark .tabs.is-toggle li a{border-width:1px;margin-bottom:0}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .hero.is-white .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-black .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-light .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-dark .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .content kbd.hero .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-primary .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-link .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-info .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-success .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-warning .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-danger .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark h1 .docs-heading-anchor,html.theme--documenter-dark h1 .docs-heading-anchor:hover,html.theme--documenter-dark h1 .docs-heading-anchor:visited,html.theme--documenter-dark h2 .docs-heading-anchor,html.theme--documenter-dark h2 .docs-heading-anchor:hover,html.theme--documenter-dark h2 .docs-heading-anchor:visited,html.theme--documenter-dark h3 .docs-heading-anchor,html.theme--documenter-dark h3 .docs-heading-anchor:hover,html.theme--documenter-dark h3 .docs-heading-anchor:visited,html.theme--documenter-dark h4 .docs-heading-anchor,html.theme--documenter-dark h4 .docs-heading-anchor:hover,html.theme--documenter-dark h4 .docs-heading-anchor:visited,html.theme--documenter-dark h5 .docs-heading-anchor,html.theme--documenter-dark h5 .docs-heading-anchor:hover,html.theme--documenter-dark h5 .docs-heading-anchor:visited,html.theme--documenter-dark h6 .docs-heading-anchor,html.theme--documenter-dark h6 .docs-heading-anchor:hover,html.theme--documenter-dark h6 .docs-heading-anchor:visited{color:#f2f2f2}html.theme--documenter-dark h1 .docs-heading-anchor-permalink,html.theme--documenter-dark h2 .docs-heading-anchor-permalink,html.theme--documenter-dark h3 .docs-heading-anchor-permalink,html.theme--documenter-dark h4 .docs-heading-anchor-permalink,html.theme--documenter-dark h5 .docs-heading-anchor-permalink,html.theme--documenter-dark h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}html.theme--documenter-dark h1 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h2 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h3 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h4 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h5 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f0c1"}html.theme--documenter-dark h1:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h2:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h3:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h4:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h5:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h6:hover .docs-heading-anchor-permalink{visibility:visible}html.theme--documenter-dark .docs-light-only{display:none !important}html.theme--documenter-dark pre{position:relative;overflow:hidden}html.theme--documenter-dark pre code,html.theme--documenter-dark pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}html.theme--documenter-dark pre code:first-of-type,html.theme--documenter-dark pre code.hljs:first-of-type{padding-top:0.5rem !important}html.theme--documenter-dark pre code:last-of-type,html.theme--documenter-dark pre code.hljs:last-of-type{padding-bottom:0.5rem !important}html.theme--documenter-dark pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 6 Free";color:#fff;cursor:pointer;text-align:center}html.theme--documenter-dark pre .copy-button:focus,html.theme--documenter-dark pre .copy-button:hover{opacity:1;background:rgba(255,255,255,0.1);color:#1abc9c}html.theme--documenter-dark pre .copy-button.success{color:#259a12;opacity:1}html.theme--documenter-dark pre .copy-button.error{color:#cb3c33;opacity:1}html.theme--documenter-dark pre:hover .copy-button{opacity:1}html.theme--documenter-dark .admonition{background-color:#282f2f;border-style:solid;border-width:1px;border-color:#5e6d6f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .admonition strong{color:currentColor}html.theme--documenter-dark .admonition.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}html.theme--documenter-dark .admonition.is-medium{font-size:1.25rem}html.theme--documenter-dark .admonition.is-large{font-size:1.5rem}html.theme--documenter-dark .admonition.is-default{background-color:#282f2f;border-color:#5e6d6f}html.theme--documenter-dark .admonition.is-default>.admonition-header{background-color:#5e6d6f;color:#fff}html.theme--documenter-dark .admonition.is-default>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-info{background-color:#282f2f;border-color:#024c7d}html.theme--documenter-dark .admonition.is-info>.admonition-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .admonition.is-info>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-success{background-color:#282f2f;border-color:#008438}html.theme--documenter-dark .admonition.is-success>.admonition-header{background-color:#008438;color:#fff}html.theme--documenter-dark .admonition.is-success>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-warning{background-color:#282f2f;border-color:#ad8100}html.theme--documenter-dark .admonition.is-warning>.admonition-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .admonition.is-warning>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-danger{background-color:#282f2f;border-color:#9e1b0d}html.theme--documenter-dark .admonition.is-danger>.admonition-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .admonition.is-danger>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-compat{background-color:#282f2f;border-color:#137886}html.theme--documenter-dark .admonition.is-compat>.admonition-header{background-color:#137886;color:#fff}html.theme--documenter-dark .admonition.is-compat>.admonition-body{color:#fff}html.theme--documenter-dark .admonition-header{color:#fff;background-color:#5e6d6f;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}html.theme--documenter-dark .admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}html.theme--documenter-dark details.admonition.is-details>.admonition-header{list-style:none}html.theme--documenter-dark details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}html.theme--documenter-dark details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}html.theme--documenter-dark .admonition-body{color:#fff;padding:0.5rem .75rem}html.theme--documenter-dark .admonition-body pre{background-color:#282f2f}html.theme--documenter-dark .admonition-body code{background-color:rgba(255,255,255,0.05)}html.theme--documenter-dark .docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #5e6d6f;box-shadow:none;max-width:100%}html.theme--documenter-dark .docstring>header{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#282f2f;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>header code{background-color:transparent}html.theme--documenter-dark .docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}html.theme--documenter-dark .docstring>header .docstring-binding{margin-right:0.3em}html.theme--documenter-dark .docstring>header .docstring-category{margin-left:0.3em}html.theme--documenter-dark .docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>section:last-child{border-bottom:none}html.theme--documenter-dark .docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}html.theme--documenter-dark .docstring>section>a.docs-sourcelink:focus{opacity:1 !important}html.theme--documenter-dark .docstring:hover>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring>section:hover a.docs-sourcelink{opacity:1}html.theme--documenter-dark .documenter-example-output{background-color:#1f2424}html.theme--documenter-dark .outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#282f2f;color:#fff;border-bottom:3px solid #9e1b0d;padding:10px 35px;text-align:center;font-size:15px}html.theme--documenter-dark .outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}html.theme--documenter-dark .outdated-warning-overlay a{color:#1abc9c}html.theme--documenter-dark .outdated-warning-overlay a:hover{color:#1dd2af}html.theme--documenter-dark .content pre{border:1px solid #5e6d6f}html.theme--documenter-dark .content code{font-weight:inherit}html.theme--documenter-dark .content a code{color:#1abc9c}html.theme--documenter-dark .content h1 code,html.theme--documenter-dark .content h2 code,html.theme--documenter-dark .content h3 code,html.theme--documenter-dark .content h4 code,html.theme--documenter-dark .content h5 code,html.theme--documenter-dark .content h6 code{color:#f2f2f2}html.theme--documenter-dark .content table{display:block;width:initial;max-width:100%;overflow-x:auto}html.theme--documenter-dark .content blockquote>ul:first-child,html.theme--documenter-dark .content blockquote>ol:first-child,html.theme--documenter-dark .content .admonition-body>ul:first-child,html.theme--documenter-dark .content .admonition-body>ol:first-child{margin-top:0}html.theme--documenter-dark pre,html.theme--documenter-dark code{font-variant-ligatures:no-contextual}html.theme--documenter-dark .breadcrumb a.is-disabled{cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb a.is-disabled,html.theme--documenter-dark .breadcrumb a.is-disabled:hover{color:#f2f2f2}html.theme--documenter-dark .hljs{background:initial !important}html.theme--documenter-dark .katex .katex-mathml{top:0;right:0}html.theme--documenter-dark .katex-display,html.theme--documenter-dark mjx-container,html.theme--documenter-dark .MathJax_Display{margin:0.5em 0 !important}html.theme--documenter-dark html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}html.theme--documenter-dark li.no-marker{list-style:none}html.theme--documenter-dark #documenter .docs-main>article{overflow-wrap:break-word}html.theme--documenter-dark #documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main{width:100%}html.theme--documenter-dark #documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-main>header,html.theme--documenter-dark #documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar{background-color:#1f2424;border-bottom:1px solid #5e6d6f;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-icon,html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #171717;transition-duration:0.7s;-webkit-transition-duration:0.7s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}html.theme--documenter-dark #documenter .docs-main section.footnotes{border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-main section.footnotes li .tag:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .content kbd:first-child,html.theme--documenter-dark .content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}html.theme--documenter-dark #documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #5e6d6f;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage,html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}html.theme--documenter-dark #documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}html.theme--documenter-dark #documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}html.theme--documenter-dark #documenter .docs-sidebar{display:flex;flex-direction:column;color:#fff;background-color:#282f2f;border-right:1px solid #5e6d6f;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}html.theme--documenter-dark #documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #171717}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar{left:0;top:0}}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a,html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a:hover{color:#fff}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector{border-top:1px solid #5e6d6f;display:none;padding:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector.visible{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #5e6d6f;padding-bottom:1.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f054"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#fff;background:#282f2f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu a.tocitem:hover,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#fff;background-color:#32393a}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #5e6d6f;border-bottom:1px solid #5e6d6f;background-color:#1f2424}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#1f2424;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#32393a;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{width:14.4rem}html.theme--documenter-dark #documenter .docs-sidebar #documenter-search-query{color:#868c98;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}html.theme--documenter-dark kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(245,245,245,0.6);box-shadow:0 2px 0 1px rgba(245,245,245,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}html.theme--documenter-dark .search-min-width-50{min-width:50%}html.theme--documenter-dark .search-min-height-100{min-height:100%}html.theme--documenter-dark .search-modal-card-body{max-height:calc(100vh - 15rem)}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333;background-color:#f1f5f9}html.theme--documenter-dark .search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}html.theme--documenter-dark .search-filter:hover,html.theme--documenter-dark .search-filter:focus{color:#333}html.theme--documenter-dark .search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}html.theme--documenter-dark .search-filter-selected:hover,html.theme--documenter-dark .search-filter-selected:focus{color:#f5f5f5}html.theme--documenter-dark .search-result-highlight{background-color:#ffdd57;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .search-result-title{width:85%;color:#f5f5f5}html.theme--documenter-dark .search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-thumb,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-track,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem}html.theme--documenter-dark .gap-8{gap:2rem}html.theme--documenter-dark{background-color:#1f2424;font-size:16px;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark .ansi span.sgr1{font-weight:bolder}html.theme--documenter-dark .ansi span.sgr2{font-weight:lighter}html.theme--documenter-dark .ansi span.sgr3{font-style:italic}html.theme--documenter-dark .ansi span.sgr4{text-decoration:underline}html.theme--documenter-dark .ansi span.sgr7{color:#1f2424;background-color:#fff}html.theme--documenter-dark .ansi span.sgr8{color:transparent}html.theme--documenter-dark .ansi span.sgr8 span{color:transparent}html.theme--documenter-dark .ansi span.sgr9{text-decoration:line-through}html.theme--documenter-dark .ansi span.sgr30{color:#242424}html.theme--documenter-dark .ansi span.sgr31{color:#f6705f}html.theme--documenter-dark .ansi span.sgr32{color:#4fb43a}html.theme--documenter-dark .ansi span.sgr33{color:#f4c72f}html.theme--documenter-dark .ansi span.sgr34{color:#7587f0}html.theme--documenter-dark .ansi span.sgr35{color:#bc89d3}html.theme--documenter-dark .ansi span.sgr36{color:#49b6ca}html.theme--documenter-dark .ansi span.sgr37{color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr40{background-color:#242424}html.theme--documenter-dark .ansi span.sgr41{background-color:#f6705f}html.theme--documenter-dark .ansi span.sgr42{background-color:#4fb43a}html.theme--documenter-dark .ansi span.sgr43{background-color:#f4c72f}html.theme--documenter-dark .ansi span.sgr44{background-color:#7587f0}html.theme--documenter-dark .ansi span.sgr45{background-color:#bc89d3}html.theme--documenter-dark .ansi span.sgr46{background-color:#49b6ca}html.theme--documenter-dark .ansi span.sgr47{background-color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr90{color:#92a0a2}html.theme--documenter-dark .ansi span.sgr91{color:#ff8674}html.theme--documenter-dark .ansi span.sgr92{color:#79d462}html.theme--documenter-dark .ansi span.sgr93{color:#ffe76b}html.theme--documenter-dark .ansi span.sgr94{color:#8a98ff}html.theme--documenter-dark .ansi span.sgr95{color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr96{color:#6bc8db}html.theme--documenter-dark .ansi span.sgr97{color:#ecf0f1}html.theme--documenter-dark .ansi span.sgr100{background-color:#92a0a2}html.theme--documenter-dark .ansi span.sgr101{background-color:#ff8674}html.theme--documenter-dark .ansi span.sgr102{background-color:#79d462}html.theme--documenter-dark .ansi span.sgr103{background-color:#ffe76b}html.theme--documenter-dark .ansi span.sgr104{background-color:#8a98ff}html.theme--documenter-dark .ansi span.sgr105{background-color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr106{background-color:#6bc8db}html.theme--documenter-dark .ansi span.sgr107{background-color:#ecf0f1}html.theme--documenter-dark code.language-julia-repl>span.hljs-meta{color:#4fb43a;font-weight:bolder}html.theme--documenter-dark .hljs{background:#2b2b2b;color:#f8f8f2}html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-quote{color:#d4d0ab}html.theme--documenter-dark .hljs-variable,html.theme--documenter-dark .hljs-template-variable,html.theme--documenter-dark .hljs-tag,html.theme--documenter-dark .hljs-name,html.theme--documenter-dark .hljs-selector-id,html.theme--documenter-dark .hljs-selector-class,html.theme--documenter-dark .hljs-regexp,html.theme--documenter-dark .hljs-deletion{color:#ffa07a}html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-link{color:#f5ab35}html.theme--documenter-dark .hljs-attribute{color:#ffd700}html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-addition{color:#abe338}html.theme--documenter-dark .hljs-title,html.theme--documenter-dark .hljs-section{color:#00e0e0}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{color:#dcc6e0}html.theme--documenter-dark .hljs-emphasis{font-style:italic}html.theme--documenter-dark .hljs-strong{font-weight:bold}@media screen and (-ms-high-contrast: active){html.theme--documenter-dark .hljs-addition,html.theme--documenter-dark .hljs-attribute,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-link,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-quote{color:highlight}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{font-weight:bold}}html.theme--documenter-dark .hljs-subst{color:#f8f8f2} +*/}html.theme--documenter-dark html{background-color:#1f2424;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark article,html.theme--documenter-dark aside,html.theme--documenter-dark figure,html.theme--documenter-dark footer,html.theme--documenter-dark header,html.theme--documenter-dark hgroup,html.theme--documenter-dark section{display:block}html.theme--documenter-dark body,html.theme--documenter-dark button,html.theme--documenter-dark input,html.theme--documenter-dark optgroup,html.theme--documenter-dark select,html.theme--documenter-dark textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}html.theme--documenter-dark code,html.theme--documenter-dark pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark body{color:#fff;font-size:1em;font-weight:400;line-height:1.5}html.theme--documenter-dark a{color:#1abc9c;cursor:pointer;text-decoration:none}html.theme--documenter-dark a strong{color:currentColor}html.theme--documenter-dark a:hover{color:#1dd2af}html.theme--documenter-dark code{background-color:rgba(255,255,255,0.05);color:#ececec;font-size:.875em;font-weight:normal;padding:.1em}html.theme--documenter-dark hr{background-color:#282f2f;border:none;display:block;height:2px;margin:1.5rem 0}html.theme--documenter-dark img{height:auto;max-width:100%}html.theme--documenter-dark input[type="checkbox"],html.theme--documenter-dark input[type="radio"]{vertical-align:baseline}html.theme--documenter-dark small{font-size:.875em}html.theme--documenter-dark span{font-style:inherit;font-weight:inherit}html.theme--documenter-dark strong{color:#f2f2f2;font-weight:700}html.theme--documenter-dark fieldset{border:none}html.theme--documenter-dark pre{-webkit-overflow-scrolling:touch;background-color:#282f2f;color:#fff;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}html.theme--documenter-dark pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}html.theme--documenter-dark table td,html.theme--documenter-dark table th{vertical-align:top}html.theme--documenter-dark table td:not([align]),html.theme--documenter-dark table th:not([align]){text-align:inherit}html.theme--documenter-dark table th{color:#f2f2f2}html.theme--documenter-dark .box{background-color:#343c3d;border-radius:8px;box-shadow:none;color:#fff;display:block;padding:1.25rem}html.theme--documenter-dark a.box:hover,html.theme--documenter-dark a.box:focus{box-shadow:0 0.5em 1em -0.125em rgba(10,10,10,0.1),0 0 0 1px #1abc9c}html.theme--documenter-dark a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #1abc9c}html.theme--documenter-dark .button{background-color:#282f2f;border-color:#4c5759;border-width:1px;color:#375a7f;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 1px);text-align:center;white-space:nowrap}html.theme--documenter-dark .button strong{color:inherit}html.theme--documenter-dark .button .icon,html.theme--documenter-dark .button .icon.is-small,html.theme--documenter-dark .button #documenter .docs-sidebar form.docs-search>input.icon,html.theme--documenter-dark #documenter .docs-sidebar .button form.docs-search>input.icon,html.theme--documenter-dark .button .icon.is-medium,html.theme--documenter-dark .button .icon.is-large{height:1.5em;width:1.5em}html.theme--documenter-dark .button .icon:first-child:not(:last-child){margin-left:calc(-0.5em - 1px);margin-right:.25em}html.theme--documenter-dark .button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button:hover,html.theme--documenter-dark .button.is-hovered{border-color:#8c9b9d;color:#f2f2f2}html.theme--documenter-dark .button:focus,html.theme--documenter-dark .button.is-focused{border-color:#8c9b9d;color:#17a689}html.theme--documenter-dark .button:focus:not(:active),html.theme--documenter-dark .button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button:active,html.theme--documenter-dark .button.is-active{border-color:#343c3d;color:#f2f2f2}html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;color:#fff;text-decoration:underline}html.theme--documenter-dark .button.is-text:hover,html.theme--documenter-dark .button.is-text.is-hovered,html.theme--documenter-dark .button.is-text:focus,html.theme--documenter-dark .button.is-text.is-focused{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .button.is-text:active,html.theme--documenter-dark .button.is-text.is-active{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .button.is-text[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-ghost{background:none;border-color:rgba(0,0,0,0);color:#1abc9c;text-decoration:none}html.theme--documenter-dark .button.is-ghost:hover,html.theme--documenter-dark .button.is-ghost.is-hovered{color:#1abc9c;text-decoration:underline}html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:hover,html.theme--documenter-dark .button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus,html.theme--documenter-dark .button.is-white.is-focused{border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus:not(:active),html.theme--documenter-dark .button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-hovered{background-color:#000}html.theme--documenter-dark .button.is-white.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-white.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:hover,html.theme--documenter-dark .button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus,html.theme--documenter-dark .button.is-black.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus:not(:active),html.theme--documenter-dark .button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-black.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:hover,html.theme--documenter-dark .button.is-light.is-hovered{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus,html.theme--documenter-dark .button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus:not(:active),html.theme--documenter-dark .button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light.is-active{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:#ecf0f1;box-shadow:none}html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-outlined.is-focused{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-dark,html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover,html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus:not(:active),html.theme--documenter-dark .content kbd.button:focus:not(:active),html.theme--documenter-dark .button.is-dark.is-focused:not(:active),html.theme--documenter-dark .content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark[disabled],html.theme--documenter-dark .content kbd.button[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark,fieldset[disabled] html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:#282f2f;box-shadow:none}html.theme--documenter-dark .button.is-dark.is-inverted,html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted:hover,html.theme--documenter-dark .content kbd.button.is-inverted:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-dark.is-inverted[disabled],html.theme--documenter-dark .content kbd.button.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-loading::after,html.theme--documenter-dark .content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined,html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-outlined.is-focused{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-focused{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus:not(:active),html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus:not(:active),html.theme--documenter-dark .button.is-primary.is-focused:not(:active),html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary[disabled],html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;box-shadow:none}html.theme--documenter-dark .button.is-primary.is-inverted,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}html.theme--documenter-dark .button.is-primary.is-inverted[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:hover,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-light.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e8eef5;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:active,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-light.is-active,html.theme--documenter-dark .docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#dfe8f1;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:hover,html.theme--documenter-dark .button.is-link.is-hovered{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus,html.theme--documenter-dark .button.is-link.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus:not(:active),html.theme--documenter-dark .button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link.is-active{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:#1abc9c;box-shadow:none}html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-link.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-outlined.is-focused{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:hover,html.theme--documenter-dark .button.is-link.is-light.is-hovered{background-color:#e2fbf6;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:active,html.theme--documenter-dark .button.is-link.is-light.is-active{background-color:#d7f9f3;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:hover,html.theme--documenter-dark .button.is-info.is-hovered{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus,html.theme--documenter-dark .button.is-info.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus:not(:active),html.theme--documenter-dark .button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info.is-active{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:#024c7d;box-shadow:none}html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-info.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;color:#024c7d}html.theme--documenter-dark .button.is-info.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-outlined.is-focused{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:hover,html.theme--documenter-dark .button.is-info.is-light.is-hovered{background-color:#def2fe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:active,html.theme--documenter-dark .button.is-info.is-light.is-active{background-color:#d2edfe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:hover,html.theme--documenter-dark .button.is-success.is-hovered{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus,html.theme--documenter-dark .button.is-success.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus:not(:active),html.theme--documenter-dark .button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success.is-active{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:#008438;box-shadow:none}html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-success.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;color:#008438}html.theme--documenter-dark .button.is-success.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-outlined.is-focused{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:hover,html.theme--documenter-dark .button.is-success.is-light.is-hovered{background-color:#deffec;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:active,html.theme--documenter-dark .button.is-success.is-light.is-active{background-color:#d1ffe5;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:hover,html.theme--documenter-dark .button.is-warning.is-hovered{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus,html.theme--documenter-dark .button.is-warning.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus:not(:active),html.theme--documenter-dark .button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning.is-active{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:#ad8100;box-shadow:none}html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-warning.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-outlined.is-focused{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-focused{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:hover,html.theme--documenter-dark .button.is-warning.is-light.is-hovered{background-color:#fff7de;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:active,html.theme--documenter-dark .button.is-warning.is-light.is-active{background-color:#fff3d1;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:hover,html.theme--documenter-dark .button.is-danger.is-hovered{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus,html.theme--documenter-dark .button.is-danger.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus:not(:active),html.theme--documenter-dark .button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger.is-active{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;box-shadow:none}html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-danger.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-outlined.is-focused{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:hover,html.theme--documenter-dark .button.is-danger.is-light.is-hovered{background-color:#fce3e0;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:active,html.theme--documenter-dark .button.is-danger.is-light.is-active{background-color:#fcd8d5;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}html.theme--documenter-dark .button.is-small:not(.is-rounded),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:3px}html.theme--documenter-dark .button.is-normal{font-size:1rem}html.theme--documenter-dark .button.is-medium{font-size:1.25rem}html.theme--documenter-dark .button.is-large{font-size:1.5rem}html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .button{background-color:#8c9b9d;border-color:#5e6d6f;box-shadow:none;opacity:.5}html.theme--documenter-dark .button.is-fullwidth{display:flex;width:100%}html.theme--documenter-dark .button.is-loading{color:transparent !important;pointer-events:none}html.theme--documenter-dark .button.is-loading::after{position:absolute;left:calc(50% - (1em * 0.5));top:calc(50% - (1em * 0.5));position:absolute !important}html.theme--documenter-dark .button.is-static{background-color:#282f2f;border-color:#5e6d6f;color:#dbdee0;box-shadow:none;pointer-events:none}html.theme--documenter-dark .button.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{border-radius:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}html.theme--documenter-dark .buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .buttons .button{margin-bottom:0.5rem}html.theme--documenter-dark .buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}html.theme--documenter-dark .buttons:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .buttons:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:3px}html.theme--documenter-dark .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}html.theme--documenter-dark .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}html.theme--documenter-dark .buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}html.theme--documenter-dark .buttons.has-addons .button:last-child{margin-right:0}html.theme--documenter-dark .buttons.has-addons .button:hover,html.theme--documenter-dark .buttons.has-addons .button.is-hovered{z-index:2}html.theme--documenter-dark .buttons.has-addons .button:focus,html.theme--documenter-dark .buttons.has-addons .button.is-focused,html.theme--documenter-dark .buttons.has-addons .button:active,html.theme--documenter-dark .buttons.has-addons .button.is-active,html.theme--documenter-dark .buttons.has-addons .button.is-selected{z-index:3}html.theme--documenter-dark .buttons.has-addons .button:focus:hover,html.theme--documenter-dark .buttons.has-addons .button.is-focused:hover,html.theme--documenter-dark .buttons.has-addons .button:active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-selected:hover{z-index:4}html.theme--documenter-dark .buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .buttons.is-centered{justify-content:center}html.theme--documenter-dark .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}html.theme--documenter-dark .buttons.is-right{justify-content:flex-end}html.theme--documenter-dark .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:1rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1.25rem}}html.theme--documenter-dark .container{flex-grow:1;margin:0 auto;position:relative;width:auto}html.theme--documenter-dark .container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){html.theme--documenter-dark .container{max-width:992px}}@media screen and (max-width: 1215px){html.theme--documenter-dark .container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){html.theme--documenter-dark .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){html.theme--documenter-dark .container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){html.theme--documenter-dark .container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}html.theme--documenter-dark .content li+li{margin-top:0.25em}html.theme--documenter-dark .content p:not(:last-child),html.theme--documenter-dark .content dl:not(:last-child),html.theme--documenter-dark .content ol:not(:last-child),html.theme--documenter-dark .content ul:not(:last-child),html.theme--documenter-dark .content blockquote:not(:last-child),html.theme--documenter-dark .content pre:not(:last-child),html.theme--documenter-dark .content table:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .content h1,html.theme--documenter-dark .content h2,html.theme--documenter-dark .content h3,html.theme--documenter-dark .content h4,html.theme--documenter-dark .content h5,html.theme--documenter-dark .content h6{color:#f2f2f2;font-weight:600;line-height:1.125}html.theme--documenter-dark .content h1{font-size:2em;margin-bottom:0.5em}html.theme--documenter-dark .content h1:not(:first-child){margin-top:1em}html.theme--documenter-dark .content h2{font-size:1.75em;margin-bottom:0.5714em}html.theme--documenter-dark .content h2:not(:first-child){margin-top:1.1428em}html.theme--documenter-dark .content h3{font-size:1.5em;margin-bottom:0.6666em}html.theme--documenter-dark .content h3:not(:first-child){margin-top:1.3333em}html.theme--documenter-dark .content h4{font-size:1.25em;margin-bottom:0.8em}html.theme--documenter-dark .content h5{font-size:1.125em;margin-bottom:0.8888em}html.theme--documenter-dark .content h6{font-size:1em;margin-bottom:1em}html.theme--documenter-dark .content blockquote{background-color:#282f2f;border-left:5px solid #5e6d6f;padding:1.25em 1.5em}html.theme--documenter-dark .content ol{list-style-position:outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ol:not([type]){list-style-type:decimal}html.theme--documenter-dark .content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}html.theme--documenter-dark .content ol.is-lower-roman:not([type]){list-style-type:lower-roman}html.theme--documenter-dark .content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}html.theme--documenter-dark .content ol.is-upper-roman:not([type]){list-style-type:upper-roman}html.theme--documenter-dark .content ul{list-style:disc outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ul ul{list-style-type:circle;margin-top:0.5em}html.theme--documenter-dark .content ul ul ul{list-style-type:square}html.theme--documenter-dark .content dd{margin-left:2em}html.theme--documenter-dark .content figure{margin-left:2em;margin-right:2em;text-align:center}html.theme--documenter-dark .content figure:not(:first-child){margin-top:2em}html.theme--documenter-dark .content figure:not(:last-child){margin-bottom:2em}html.theme--documenter-dark .content figure img{display:inline-block}html.theme--documenter-dark .content figure figcaption{font-style:italic}html.theme--documenter-dark .content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}html.theme--documenter-dark .content sup,html.theme--documenter-dark .content sub{font-size:75%}html.theme--documenter-dark .content table{width:100%}html.theme--documenter-dark .content table td,html.theme--documenter-dark .content table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .content table th{color:#f2f2f2}html.theme--documenter-dark .content table th:not([align]){text-align:inherit}html.theme--documenter-dark .content table thead td,html.theme--documenter-dark .content table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .content table tfoot td,html.theme--documenter-dark .content table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .content table tbody tr:last-child td,html.theme--documenter-dark .content table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .content .tabs li+li{margin-top:0}html.theme--documenter-dark .content.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}html.theme--documenter-dark .content.is-normal{font-size:1rem}html.theme--documenter-dark .content.is-medium{font-size:1.25rem}html.theme--documenter-dark .content.is-large{font-size:1.5rem}html.theme--documenter-dark .icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}html.theme--documenter-dark .icon.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}html.theme--documenter-dark .icon.is-medium{height:2rem;width:2rem}html.theme--documenter-dark .icon.is-large{height:3rem;width:3rem}html.theme--documenter-dark .icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}html.theme--documenter-dark .icon-text .icon{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .icon-text .icon:not(:last-child){margin-right:.25em}html.theme--documenter-dark .icon-text .icon:not(:first-child){margin-left:.25em}html.theme--documenter-dark div.icon-text{display:flex}html.theme--documenter-dark .image,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{display:block;position:relative}html.theme--documenter-dark .image img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}html.theme--documenter-dark .image img.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:9999px}html.theme--documenter-dark .image.is-fullwidth,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}html.theme--documenter-dark .image.is-square,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square,html.theme--documenter-dark .image.is-1by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}html.theme--documenter-dark .image.is-5by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}html.theme--documenter-dark .image.is-4by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}html.theme--documenter-dark .image.is-3by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}html.theme--documenter-dark .image.is-5by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}html.theme--documenter-dark .image.is-16by9,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}html.theme--documenter-dark .image.is-2by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}html.theme--documenter-dark .image.is-3by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}html.theme--documenter-dark .image.is-4by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}html.theme--documenter-dark .image.is-3by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}html.theme--documenter-dark .image.is-2by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}html.theme--documenter-dark .image.is-3by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}html.theme--documenter-dark .image.is-9by16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}html.theme--documenter-dark .image.is-1by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}html.theme--documenter-dark .image.is-1by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}html.theme--documenter-dark .image.is-16x16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}html.theme--documenter-dark .image.is-24x24,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}html.theme--documenter-dark .image.is-32x32,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}html.theme--documenter-dark .image.is-48x48,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}html.theme--documenter-dark .image.is-64x64,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}html.theme--documenter-dark .image.is-96x96,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}html.theme--documenter-dark .image.is-128x128,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}html.theme--documenter-dark .notification{background-color:#282f2f;border-radius:.4em;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}html.theme--documenter-dark .notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .notification strong{color:currentColor}html.theme--documenter-dark .notification code,html.theme--documenter-dark .notification pre{background:#fff}html.theme--documenter-dark .notification pre code{background:transparent}html.theme--documenter-dark .notification>.delete{right:.5rem;position:absolute;top:0.5rem}html.theme--documenter-dark .notification .title,html.theme--documenter-dark .notification .subtitle,html.theme--documenter-dark .notification .content{color:currentColor}html.theme--documenter-dark .notification.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .notification.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .notification.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .notification.is-dark,html.theme--documenter-dark .content kbd.notification{background-color:#282f2f;color:#fff}html.theme--documenter-dark .notification.is-primary,html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .notification.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.notification.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .notification.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .notification.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .notification.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .notification.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .notification.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .notification.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .notification.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .notification.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .notification.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .notification.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}html.theme--documenter-dark .progress::-webkit-progress-bar{background-color:#343c3d}html.theme--documenter-dark .progress::-webkit-progress-value{background-color:#dbdee0}html.theme--documenter-dark .progress::-moz-progress-bar{background-color:#dbdee0}html.theme--documenter-dark .progress::-ms-fill{background-color:#dbdee0;border:none}html.theme--documenter-dark .progress.is-white::-webkit-progress-value{background-color:#fff}html.theme--documenter-dark .progress.is-white::-moz-progress-bar{background-color:#fff}html.theme--documenter-dark .progress.is-white::-ms-fill{background-color:#fff}html.theme--documenter-dark .progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-black::-webkit-progress-value{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-moz-progress-bar{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-ms-fill{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-light::-webkit-progress-value{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-moz-progress-bar{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-ms-fill{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light:indeterminate{background-image:linear-gradient(to right, #ecf0f1 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-dark::-webkit-progress-value,html.theme--documenter-dark .content kbd.progress::-webkit-progress-value{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-moz-progress-bar,html.theme--documenter-dark .content kbd.progress::-moz-progress-bar{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-ms-fill,html.theme--documenter-dark .content kbd.progress::-ms-fill{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark:indeterminate,html.theme--documenter-dark .content kbd.progress:indeterminate{background-image:linear-gradient(to right, #282f2f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-primary::-webkit-progress-value,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-moz-progress-bar,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-ms-fill,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary:indeterminate,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #375a7f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-link::-webkit-progress-value{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-moz-progress-bar{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-ms-fill{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link:indeterminate{background-image:linear-gradient(to right, #1abc9c 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-info::-webkit-progress-value{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-moz-progress-bar{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-ms-fill{background-color:#024c7d}html.theme--documenter-dark .progress.is-info:indeterminate{background-image:linear-gradient(to right, #024c7d 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-success::-webkit-progress-value{background-color:#008438}html.theme--documenter-dark .progress.is-success::-moz-progress-bar{background-color:#008438}html.theme--documenter-dark .progress.is-success::-ms-fill{background-color:#008438}html.theme--documenter-dark .progress.is-success:indeterminate{background-image:linear-gradient(to right, #008438 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-warning::-webkit-progress-value{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-moz-progress-bar{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-ms-fill{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ad8100 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-danger::-webkit-progress-value{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-moz-progress-bar{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-ms-fill{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger:indeterminate{background-image:linear-gradient(to right, #9e1b0d 30%, #343c3d 30%)}html.theme--documenter-dark .progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#343c3d;background-image:linear-gradient(to right, #fff 30%, #343c3d 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}html.theme--documenter-dark .progress:indeterminate::-webkit-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-moz-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-ms-fill{animation-name:none}html.theme--documenter-dark .progress.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}html.theme--documenter-dark .progress.is-medium{height:1.25rem}html.theme--documenter-dark .progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}html.theme--documenter-dark .table{background-color:#343c3d;color:#fff}html.theme--documenter-dark .table td,html.theme--documenter-dark .table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .table td.is-white,html.theme--documenter-dark .table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .table td.is-black,html.theme--documenter-dark .table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .table td.is-light,html.theme--documenter-dark .table th.is-light{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .table td.is-dark,html.theme--documenter-dark .table th.is-dark{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .table td.is-primary,html.theme--documenter-dark .table th.is-primary{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-link,html.theme--documenter-dark .table th.is-link{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .table td.is-info,html.theme--documenter-dark .table th.is-info{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .table td.is-success,html.theme--documenter-dark .table th.is-success{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .table td.is-warning,html.theme--documenter-dark .table th.is-warning{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .table td.is-danger,html.theme--documenter-dark .table th.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .table td.is-narrow,html.theme--documenter-dark .table th.is-narrow{white-space:nowrap;width:1%}html.theme--documenter-dark .table td.is-selected,html.theme--documenter-dark .table th.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-selected a,html.theme--documenter-dark .table td.is-selected strong,html.theme--documenter-dark .table th.is-selected a,html.theme--documenter-dark .table th.is-selected strong{color:currentColor}html.theme--documenter-dark .table td.is-vcentered,html.theme--documenter-dark .table th.is-vcentered{vertical-align:middle}html.theme--documenter-dark .table th{color:#f2f2f2}html.theme--documenter-dark .table th:not([align]){text-align:left}html.theme--documenter-dark .table tr.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table tr.is-selected a,html.theme--documenter-dark .table tr.is-selected strong{color:currentColor}html.theme--documenter-dark .table tr.is-selected td,html.theme--documenter-dark .table tr.is-selected th{border-color:#fff;color:currentColor}html.theme--documenter-dark .table thead{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table thead td,html.theme--documenter-dark .table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .table tfoot{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tfoot td,html.theme--documenter-dark .table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .table tbody{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tbody tr:last-child td,html.theme--documenter-dark .table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .table.is-bordered td,html.theme--documenter-dark .table.is-bordered th{border-width:1px}html.theme--documenter-dark .table.is-bordered tr:last-child td,html.theme--documenter-dark .table.is-bordered tr:last-child th{border-bottom-width:1px}html.theme--documenter-dark .table.is-fullwidth{width:100%}html.theme--documenter-dark .table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#2d3435}html.theme--documenter-dark .table.is-narrow td,html.theme--documenter-dark .table.is-narrow th{padding:0.25em 0.5em}html.theme--documenter-dark .table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#282f2f}html.theme--documenter-dark .table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}html.theme--documenter-dark .tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .tags .tag,html.theme--documenter-dark .tags .content kbd,html.theme--documenter-dark .content .tags kbd,html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}html.theme--documenter-dark .tags .tag:not(:last-child),html.theme--documenter-dark .tags .content kbd:not(:last-child),html.theme--documenter-dark .content .tags kbd:not(:last-child),html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:.5rem}html.theme--documenter-dark .tags:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .tags:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .tags.are-medium .tag:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .content kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .content .tags.are-medium kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}html.theme--documenter-dark .tags.are-large .tag:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .content kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .content .tags.are-large kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}html.theme--documenter-dark .tags.is-centered{justify-content:center}html.theme--documenter-dark .tags.is-centered .tag,html.theme--documenter-dark .tags.is-centered .content kbd,html.theme--documenter-dark .content .tags.is-centered kbd,html.theme--documenter-dark .tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}html.theme--documenter-dark .tags.is-right{justify-content:flex-end}html.theme--documenter-dark .tags.is-right .tag:not(:first-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:first-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}html.theme--documenter-dark .tags.is-right .tag:not(:last-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:last-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}html.theme--documenter-dark .tags.has-addons .tag,html.theme--documenter-dark .tags.has-addons .content kbd,html.theme--documenter-dark .content .tags.has-addons kbd,html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}html.theme--documenter-dark .tags.has-addons .tag:not(:first-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:first-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}html.theme--documenter-dark .tags.has-addons .tag:not(:last-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:last-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}html.theme--documenter-dark .tag:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#282f2f;border-radius:.4em;color:#fff;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}html.theme--documenter-dark .tag:not(body) .delete,html.theme--documenter-dark .content kbd:not(body) .delete,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}html.theme--documenter-dark .tag.is-white:not(body),html.theme--documenter-dark .content kbd.is-white:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .tag.is-black:not(body),html.theme--documenter-dark .content kbd.is-black:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .tag.is-light:not(body),html.theme--documenter-dark .content kbd.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .tag.is-dark:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-dark:not(body),html.theme--documenter-dark .content .docstring>section>kbd:not(body){background-color:#282f2f;color:#fff}html.theme--documenter-dark .tag.is-primary:not(body),html.theme--documenter-dark .content kbd.is-primary:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){background-color:#375a7f;color:#fff}html.theme--documenter-dark .tag.is-primary.is-light:not(body),html.theme--documenter-dark .content kbd.is-primary.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .tag.is-link:not(body),html.theme--documenter-dark .content kbd.is-link:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#1abc9c;color:#fff}html.theme--documenter-dark .tag.is-link.is-light:not(body),html.theme--documenter-dark .content kbd.is-link.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .tag.is-info:not(body),html.theme--documenter-dark .content kbd.is-info:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#024c7d;color:#fff}html.theme--documenter-dark .tag.is-info.is-light:not(body),html.theme--documenter-dark .content kbd.is-info.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .tag.is-success:not(body),html.theme--documenter-dark .content kbd.is-success:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#008438;color:#fff}html.theme--documenter-dark .tag.is-success.is-light:not(body),html.theme--documenter-dark .content kbd.is-success.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .tag.is-warning:not(body),html.theme--documenter-dark .content kbd.is-warning:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ad8100;color:#fff}html.theme--documenter-dark .tag.is-warning.is-light:not(body),html.theme--documenter-dark .content kbd.is-warning.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .tag.is-danger:not(body),html.theme--documenter-dark .content kbd.is-danger:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .tag.is-danger.is-light:not(body),html.theme--documenter-dark .content kbd.is-danger.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .tag.is-normal:not(body),html.theme--documenter-dark .content kbd.is-normal:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}html.theme--documenter-dark .tag.is-medium:not(body),html.theme--documenter-dark .content kbd.is-medium:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}html.theme--documenter-dark .tag.is-large:not(body),html.theme--documenter-dark .content kbd.is-large:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}html.theme--documenter-dark .tag:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .content kbd:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}html.theme--documenter-dark .tag:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .content kbd:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}html.theme--documenter-dark .tag:not(body) .icon:first-child:last-child,html.theme--documenter-dark .content kbd:not(body) .icon:first-child:last-child,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}html.theme--documenter-dark .tag.is-delete:not(body),html.theme--documenter-dark .content kbd.is-delete:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before,html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}html.theme--documenter-dark .tag.is-delete:not(body):hover,html.theme--documenter-dark .content kbd.is-delete:not(body):hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):hover,html.theme--documenter-dark .tag.is-delete:not(body):focus,html.theme--documenter-dark .content kbd.is-delete:not(body):focus,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#1d2122}html.theme--documenter-dark .tag.is-delete:not(body):active,html.theme--documenter-dark .content kbd.is-delete:not(body):active,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#111414}html.theme--documenter-dark .tag.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:not(body),html.theme--documenter-dark .content kbd.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:9999px}html.theme--documenter-dark a.tag:hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:hover{text-decoration:underline}html.theme--documenter-dark .title,html.theme--documenter-dark .subtitle{word-break:break-word}html.theme--documenter-dark .title em,html.theme--documenter-dark .title span,html.theme--documenter-dark .subtitle em,html.theme--documenter-dark .subtitle span{font-weight:inherit}html.theme--documenter-dark .title sub,html.theme--documenter-dark .subtitle sub{font-size:.75em}html.theme--documenter-dark .title sup,html.theme--documenter-dark .subtitle sup{font-size:.75em}html.theme--documenter-dark .title .tag,html.theme--documenter-dark .title .content kbd,html.theme--documenter-dark .content .title kbd,html.theme--documenter-dark .title .docstring>section>a.docs-sourcelink,html.theme--documenter-dark .subtitle .tag,html.theme--documenter-dark .subtitle .content kbd,html.theme--documenter-dark .content .subtitle kbd,html.theme--documenter-dark .subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}html.theme--documenter-dark .title{color:#fff;font-size:2rem;font-weight:500;line-height:1.125}html.theme--documenter-dark .title strong{color:inherit;font-weight:inherit}html.theme--documenter-dark .title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}html.theme--documenter-dark .title.is-1{font-size:3rem}html.theme--documenter-dark .title.is-2{font-size:2.5rem}html.theme--documenter-dark .title.is-3{font-size:2rem}html.theme--documenter-dark .title.is-4{font-size:1.5rem}html.theme--documenter-dark .title.is-5{font-size:1.25rem}html.theme--documenter-dark .title.is-6{font-size:1rem}html.theme--documenter-dark .title.is-7{font-size:.75rem}html.theme--documenter-dark .subtitle{color:#8c9b9d;font-size:1.25rem;font-weight:400;line-height:1.25}html.theme--documenter-dark .subtitle strong{color:#8c9b9d;font-weight:600}html.theme--documenter-dark .subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}html.theme--documenter-dark .subtitle.is-1{font-size:3rem}html.theme--documenter-dark .subtitle.is-2{font-size:2.5rem}html.theme--documenter-dark .subtitle.is-3{font-size:2rem}html.theme--documenter-dark .subtitle.is-4{font-size:1.5rem}html.theme--documenter-dark .subtitle.is-5{font-size:1.25rem}html.theme--documenter-dark .subtitle.is-6{font-size:1rem}html.theme--documenter-dark .subtitle.is-7{font-size:.75rem}html.theme--documenter-dark .heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}html.theme--documenter-dark .number{align-items:center;background-color:#282f2f;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#1f2424;border-color:#5e6d6f;border-radius:.4em;color:#dbdee0}html.theme--documenter-dark .select select::-moz-placeholder,html.theme--documenter-dark .textarea::-moz-placeholder,html.theme--documenter-dark .input::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select::-webkit-input-placeholder,html.theme--documenter-dark .textarea::-webkit-input-placeholder,html.theme--documenter-dark .input::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:-moz-placeholder,html.theme--documenter-dark .textarea:-moz-placeholder,html.theme--documenter-dark .input:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select:-ms-input-placeholder,html.theme--documenter-dark .textarea:-ms-input-placeholder,html.theme--documenter-dark .input:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:hover,html.theme--documenter-dark .textarea:hover,html.theme--documenter-dark .input:hover,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:hover,html.theme--documenter-dark .select select.is-hovered,html.theme--documenter-dark .is-hovered.textarea,html.theme--documenter-dark .is-hovered.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#8c9b9d}html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{border-color:#1abc9c;box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#8c9b9d;border-color:#282f2f;box-shadow:none;color:#fff}html.theme--documenter-dark .select select[disabled]::-moz-placeholder,html.theme--documenter-dark .textarea[disabled]::-moz-placeholder,html.theme--documenter-dark .input[disabled]::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .textarea[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .input[disabled]::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-moz-placeholder,html.theme--documenter-dark .textarea[disabled]:-moz-placeholder,html.theme--documenter-dark .input[disabled]:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-ms-input-placeholder,html.theme--documenter-dark .textarea[disabled]:-ms-input-placeholder,html.theme--documenter-dark .input[disabled]:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 0.0625em 0.125em rgba(10,10,10,0.05);max-width:100%;width:100%}html.theme--documenter-dark .textarea[readonly],html.theme--documenter-dark .input[readonly],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}html.theme--documenter-dark .is-white.textarea,html.theme--documenter-dark .is-white.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}html.theme--documenter-dark .is-white.textarea:focus,html.theme--documenter-dark .is-white.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:focus,html.theme--documenter-dark .is-white.is-focused.textarea,html.theme--documenter-dark .is-white.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-white.textarea:active,html.theme--documenter-dark .is-white.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:active,html.theme--documenter-dark .is-white.is-active.textarea,html.theme--documenter-dark .is-white.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .is-black.textarea,html.theme--documenter-dark .is-black.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}html.theme--documenter-dark .is-black.textarea:focus,html.theme--documenter-dark .is-black.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:focus,html.theme--documenter-dark .is-black.is-focused.textarea,html.theme--documenter-dark .is-black.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-black.textarea:active,html.theme--documenter-dark .is-black.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:active,html.theme--documenter-dark .is-black.is-active.textarea,html.theme--documenter-dark .is-black.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .is-light.textarea,html.theme--documenter-dark .is-light.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light{border-color:#ecf0f1}html.theme--documenter-dark .is-light.textarea:focus,html.theme--documenter-dark .is-light.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:focus,html.theme--documenter-dark .is-light.is-focused.textarea,html.theme--documenter-dark .is-light.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-light.textarea:active,html.theme--documenter-dark .is-light.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:active,html.theme--documenter-dark .is-light.is-active.textarea,html.theme--documenter-dark .is-light.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .is-dark.textarea,html.theme--documenter-dark .content kbd.textarea,html.theme--documenter-dark .is-dark.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark,html.theme--documenter-dark .content kbd.input{border-color:#282f2f}html.theme--documenter-dark .is-dark.textarea:focus,html.theme--documenter-dark .content kbd.textarea:focus,html.theme--documenter-dark .is-dark.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:focus,html.theme--documenter-dark .content kbd.input:focus,html.theme--documenter-dark .is-dark.is-focused.textarea,html.theme--documenter-dark .content kbd.is-focused.textarea,html.theme--documenter-dark .is-dark.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .content kbd.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-focused,html.theme--documenter-dark .is-dark.textarea:active,html.theme--documenter-dark .content kbd.textarea:active,html.theme--documenter-dark .is-dark.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:active,html.theme--documenter-dark .content kbd.input:active,html.theme--documenter-dark .is-dark.is-active.textarea,html.theme--documenter-dark .content kbd.is-active.textarea,html.theme--documenter-dark .is-dark.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .content kbd.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .is-primary.textarea,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink{border-color:#375a7f}html.theme--documenter-dark .is-primary.textarea:focus,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:focus,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.is-focused.textarea,html.theme--documenter-dark .docstring>section>a.is-focused.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .docstring>section>a.is-focused.input.docs-sourcelink,html.theme--documenter-dark .is-primary.textarea:active,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:active,html.theme--documenter-dark .is-primary.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:active,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:active,html.theme--documenter-dark .is-primary.is-active.textarea,html.theme--documenter-dark .docstring>section>a.is-active.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .is-link.textarea,html.theme--documenter-dark .is-link.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link{border-color:#1abc9c}html.theme--documenter-dark .is-link.textarea:focus,html.theme--documenter-dark .is-link.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:focus,html.theme--documenter-dark .is-link.is-focused.textarea,html.theme--documenter-dark .is-link.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-link.textarea:active,html.theme--documenter-dark .is-link.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:active,html.theme--documenter-dark .is-link.is-active.textarea,html.theme--documenter-dark .is-link.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .is-info.textarea,html.theme--documenter-dark .is-info.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info{border-color:#024c7d}html.theme--documenter-dark .is-info.textarea:focus,html.theme--documenter-dark .is-info.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:focus,html.theme--documenter-dark .is-info.is-focused.textarea,html.theme--documenter-dark .is-info.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-info.textarea:active,html.theme--documenter-dark .is-info.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:active,html.theme--documenter-dark .is-info.is-active.textarea,html.theme--documenter-dark .is-info.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .is-success.textarea,html.theme--documenter-dark .is-success.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success{border-color:#008438}html.theme--documenter-dark .is-success.textarea:focus,html.theme--documenter-dark .is-success.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:focus,html.theme--documenter-dark .is-success.is-focused.textarea,html.theme--documenter-dark .is-success.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-success.textarea:active,html.theme--documenter-dark .is-success.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:active,html.theme--documenter-dark .is-success.is-active.textarea,html.theme--documenter-dark .is-success.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .is-warning.textarea,html.theme--documenter-dark .is-warning.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ad8100}html.theme--documenter-dark .is-warning.textarea:focus,html.theme--documenter-dark .is-warning.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:focus,html.theme--documenter-dark .is-warning.is-focused.textarea,html.theme--documenter-dark .is-warning.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-warning.textarea:active,html.theme--documenter-dark .is-warning.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:active,html.theme--documenter-dark .is-warning.is-active.textarea,html.theme--documenter-dark .is-warning.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .is-danger.textarea,html.theme--documenter-dark .is-danger.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#9e1b0d}html.theme--documenter-dark .is-danger.textarea:focus,html.theme--documenter-dark .is-danger.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:focus,html.theme--documenter-dark .is-danger.is-focused.textarea,html.theme--documenter-dark .is-danger.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-danger.textarea:active,html.theme--documenter-dark .is-danger.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:active,html.theme--documenter-dark .is-danger.is-active.textarea,html.theme--documenter-dark .is-danger.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .is-small.textarea,html.theme--documenter-dark .is-small.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .is-medium.textarea,html.theme--documenter-dark .is-medium.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}html.theme--documenter-dark .is-large.textarea,html.theme--documenter-dark .is-large.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}html.theme--documenter-dark .is-fullwidth.textarea,html.theme--documenter-dark .is-fullwidth.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}html.theme--documenter-dark .is-inline.textarea,html.theme--documenter-dark .is-inline.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}html.theme--documenter-dark .input.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}html.theme--documenter-dark .input.is-static,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}html.theme--documenter-dark .textarea{display:block;max-width:100%;min-width:100%;padding:calc(0.75em - 1px);resize:vertical}html.theme--documenter-dark .textarea:not([rows]){max-height:40em;min-height:8em}html.theme--documenter-dark .textarea[rows]{height:initial}html.theme--documenter-dark .textarea.has-fixed-size{resize:none}html.theme--documenter-dark .radio,html.theme--documenter-dark .checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}html.theme--documenter-dark .radio input,html.theme--documenter-dark .checkbox input{cursor:pointer}html.theme--documenter-dark .radio:hover,html.theme--documenter-dark .checkbox:hover{color:#8c9b9d}html.theme--documenter-dark .radio[disabled],html.theme--documenter-dark .checkbox[disabled],fieldset[disabled] html.theme--documenter-dark .radio,fieldset[disabled] html.theme--documenter-dark .checkbox,html.theme--documenter-dark .radio input[disabled],html.theme--documenter-dark .checkbox input[disabled]{color:#fff;cursor:not-allowed}html.theme--documenter-dark .radio+.radio{margin-left:.5em}html.theme--documenter-dark .select{display:inline-block;max-width:100%;position:relative;vertical-align:top}html.theme--documenter-dark .select:not(.is-multiple){height:2.5em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border-color:#1abc9c;right:1.125em;z-index:4}html.theme--documenter-dark .select.is-rounded select,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select select{border-radius:9999px;padding-left:1em}html.theme--documenter-dark .select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}html.theme--documenter-dark .select select::-ms-expand{display:none}html.theme--documenter-dark .select select[disabled]:hover,fieldset[disabled] html.theme--documenter-dark .select select:hover{border-color:#282f2f}html.theme--documenter-dark .select select:not([multiple]){padding-right:2.5em}html.theme--documenter-dark .select select[multiple]{height:auto;padding:0}html.theme--documenter-dark .select select[multiple] option{padding:0.5em 1em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading):hover::after{border-color:#8c9b9d}html.theme--documenter-dark .select.is-white:not(:hover)::after{border-color:#fff}html.theme--documenter-dark .select.is-white select{border-color:#fff}html.theme--documenter-dark .select.is-white select:hover,html.theme--documenter-dark .select.is-white select.is-hovered{border-color:#f2f2f2}html.theme--documenter-dark .select.is-white select:focus,html.theme--documenter-dark .select.is-white select.is-focused,html.theme--documenter-dark .select.is-white select:active,html.theme--documenter-dark .select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .select.is-black:not(:hover)::after{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select:hover,html.theme--documenter-dark .select.is-black select.is-hovered{border-color:#000}html.theme--documenter-dark .select.is-black select:focus,html.theme--documenter-dark .select.is-black select.is-focused,html.theme--documenter-dark .select.is-black select:active,html.theme--documenter-dark .select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .select.is-light:not(:hover)::after{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select:hover,html.theme--documenter-dark .select.is-light select.is-hovered{border-color:#dde4e6}html.theme--documenter-dark .select.is-light select:focus,html.theme--documenter-dark .select.is-light select.is-focused,html.theme--documenter-dark .select.is-light select:active,html.theme--documenter-dark .select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .select.is-dark:not(:hover)::after,html.theme--documenter-dark .content kbd.select:not(:hover)::after{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select,html.theme--documenter-dark .content kbd.select select{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select:hover,html.theme--documenter-dark .content kbd.select select:hover,html.theme--documenter-dark .select.is-dark select.is-hovered,html.theme--documenter-dark .content kbd.select select.is-hovered{border-color:#1d2122}html.theme--documenter-dark .select.is-dark select:focus,html.theme--documenter-dark .content kbd.select select:focus,html.theme--documenter-dark .select.is-dark select.is-focused,html.theme--documenter-dark .content kbd.select select.is-focused,html.theme--documenter-dark .select.is-dark select:active,html.theme--documenter-dark .content kbd.select select:active,html.theme--documenter-dark .select.is-dark select.is-active,html.theme--documenter-dark .content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .select.is-primary:not(:hover)::after,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select:hover,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:hover,html.theme--documenter-dark .select.is-primary select.is-hovered,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#2f4d6d}html.theme--documenter-dark .select.is-primary select:focus,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:focus,html.theme--documenter-dark .select.is-primary select.is-focused,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-focused,html.theme--documenter-dark .select.is-primary select:active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:active,html.theme--documenter-dark .select.is-primary select.is-active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .select.is-link:not(:hover)::after{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select:hover,html.theme--documenter-dark .select.is-link select.is-hovered{border-color:#17a689}html.theme--documenter-dark .select.is-link select:focus,html.theme--documenter-dark .select.is-link select.is-focused,html.theme--documenter-dark .select.is-link select:active,html.theme--documenter-dark .select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select.is-info:not(:hover)::after{border-color:#024c7d}html.theme--documenter-dark .select.is-info select{border-color:#024c7d}html.theme--documenter-dark .select.is-info select:hover,html.theme--documenter-dark .select.is-info select.is-hovered{border-color:#023d64}html.theme--documenter-dark .select.is-info select:focus,html.theme--documenter-dark .select.is-info select.is-focused,html.theme--documenter-dark .select.is-info select:active,html.theme--documenter-dark .select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .select.is-success:not(:hover)::after{border-color:#008438}html.theme--documenter-dark .select.is-success select{border-color:#008438}html.theme--documenter-dark .select.is-success select:hover,html.theme--documenter-dark .select.is-success select.is-hovered{border-color:#006b2d}html.theme--documenter-dark .select.is-success select:focus,html.theme--documenter-dark .select.is-success select.is-focused,html.theme--documenter-dark .select.is-success select:active,html.theme--documenter-dark .select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .select.is-warning:not(:hover)::after{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select:hover,html.theme--documenter-dark .select.is-warning select.is-hovered{border-color:#946e00}html.theme--documenter-dark .select.is-warning select:focus,html.theme--documenter-dark .select.is-warning select.is-focused,html.theme--documenter-dark .select.is-warning select:active,html.theme--documenter-dark .select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .select.is-danger:not(:hover)::after{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select:hover,html.theme--documenter-dark .select.is-danger select.is-hovered{border-color:#86170b}html.theme--documenter-dark .select.is-danger select:focus,html.theme--documenter-dark .select.is-danger select.is-focused,html.theme--documenter-dark .select.is-danger select:active,html.theme--documenter-dark .select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .select.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .select.is-medium{font-size:1.25rem}html.theme--documenter-dark .select.is-large{font-size:1.5rem}html.theme--documenter-dark .select.is-disabled::after{border-color:#fff !important;opacity:0.5}html.theme--documenter-dark .select.is-fullwidth{width:100%}html.theme--documenter-dark .select.is-fullwidth select{width:100%}html.theme--documenter-dark .select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:0.625em;transform:none}html.theme--documenter-dark .select.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .select.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .select.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}html.theme--documenter-dark .file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:hover .file-cta,html.theme--documenter-dark .file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:focus .file-cta,html.theme--documenter-dark .file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}html.theme--documenter-dark .file.is-white:active .file-cta,html.theme--documenter-dark .file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:hover .file-cta,html.theme--documenter-dark .file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:focus .file-cta,html.theme--documenter-dark .file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}html.theme--documenter-dark .file.is-black:active .file-cta,html.theme--documenter-dark .file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-light .file-cta{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:hover .file-cta,html.theme--documenter-dark .file.is-light.is-hovered .file-cta{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:focus .file-cta,html.theme--documenter-dark .file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(236,240,241,0.25);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:active .file-cta,html.theme--documenter-dark .file.is-light.is-active .file-cta{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-dark .file-cta,html.theme--documenter-dark .content kbd.file .file-cta{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:hover .file-cta,html.theme--documenter-dark .content kbd.file:hover .file-cta,html.theme--documenter-dark .file.is-dark.is-hovered .file-cta,html.theme--documenter-dark .content kbd.file.is-hovered .file-cta{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:focus .file-cta,html.theme--documenter-dark .content kbd.file:focus .file-cta,html.theme--documenter-dark .file.is-dark.is-focused .file-cta,html.theme--documenter-dark .content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(40,47,47,0.25);color:#fff}html.theme--documenter-dark .file.is-dark:active .file-cta,html.theme--documenter-dark .content kbd.file:active .file-cta,html.theme--documenter-dark .file.is-dark.is-active .file-cta,html.theme--documenter-dark .content kbd.file.is-active .file-cta{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink .file-cta{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:hover .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:hover .file-cta,html.theme--documenter-dark .file.is-primary.is-hovered .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:focus .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:focus .file-cta,html.theme--documenter-dark .file.is-primary.is-focused .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(55,90,127,0.25);color:#fff}html.theme--documenter-dark .file.is-primary:active .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:active .file-cta,html.theme--documenter-dark .file.is-primary.is-active .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link .file-cta{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:hover .file-cta,html.theme--documenter-dark .file.is-link.is-hovered .file-cta{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:focus .file-cta,html.theme--documenter-dark .file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(26,188,156,0.25);color:#fff}html.theme--documenter-dark .file.is-link:active .file-cta,html.theme--documenter-dark .file.is-link.is-active .file-cta{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info .file-cta{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:hover .file-cta,html.theme--documenter-dark .file.is-info.is-hovered .file-cta{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:focus .file-cta,html.theme--documenter-dark .file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(2,76,125,0.25);color:#fff}html.theme--documenter-dark .file.is-info:active .file-cta,html.theme--documenter-dark .file.is-info.is-active .file-cta{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success .file-cta{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:hover .file-cta,html.theme--documenter-dark .file.is-success.is-hovered .file-cta{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:focus .file-cta,html.theme--documenter-dark .file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(0,132,56,0.25);color:#fff}html.theme--documenter-dark .file.is-success:active .file-cta,html.theme--documenter-dark .file.is-success.is-active .file-cta{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning .file-cta{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:hover .file-cta,html.theme--documenter-dark .file.is-warning.is-hovered .file-cta{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:focus .file-cta,html.theme--documenter-dark .file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(173,129,0,0.25);color:#fff}html.theme--documenter-dark .file.is-warning:active .file-cta,html.theme--documenter-dark .file.is-warning.is-active .file-cta{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger .file-cta{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:hover .file-cta,html.theme--documenter-dark .file.is-danger.is-hovered .file-cta{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:focus .file-cta,html.theme--documenter-dark .file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(158,27,13,0.25);color:#fff}html.theme--documenter-dark .file.is-danger:active .file-cta,html.theme--documenter-dark .file.is-danger.is-active .file-cta{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}html.theme--documenter-dark .file.is-normal{font-size:1rem}html.theme--documenter-dark .file.is-medium{font-size:1.25rem}html.theme--documenter-dark .file.is-medium .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-large{font-size:1.5rem}html.theme--documenter-dark .file.is-large .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .file.has-name.is-empty .file-cta{border-radius:.4em}html.theme--documenter-dark .file.has-name.is-empty .file-name{display:none}html.theme--documenter-dark .file.is-boxed .file-label{flex-direction:column}html.theme--documenter-dark .file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}html.theme--documenter-dark .file.is-boxed .file-name{border-width:0 1px 1px}html.theme--documenter-dark .file.is-boxed .file-icon{height:1.5em;width:1.5em}html.theme--documenter-dark .file.is-boxed .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-boxed.is-small .file-icon .fa,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}html.theme--documenter-dark .file.is-boxed.is-medium .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.is-boxed.is-large .file-icon .fa{font-size:35px}html.theme--documenter-dark .file.is-boxed.has-name .file-cta{border-radius:.4em .4em 0 0}html.theme--documenter-dark .file.is-boxed.has-name .file-name{border-radius:0 0 .4em .4em;border-width:0 1px 1px}html.theme--documenter-dark .file.is-centered{justify-content:center}html.theme--documenter-dark .file.is-fullwidth .file-label{width:100%}html.theme--documenter-dark .file.is-fullwidth .file-name{flex-grow:1;max-width:none}html.theme--documenter-dark .file.is-right{justify-content:flex-end}html.theme--documenter-dark .file.is-right .file-cta{border-radius:0 .4em .4em 0}html.theme--documenter-dark .file.is-right .file-name{border-radius:.4em 0 0 .4em;border-width:1px 0 1px 1px;order:-1}html.theme--documenter-dark .file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}html.theme--documenter-dark .file-label:hover .file-cta{background-color:#232829;color:#f2f2f2}html.theme--documenter-dark .file-label:hover .file-name{border-color:#596668}html.theme--documenter-dark .file-label:active .file-cta{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .file-label:active .file-name{border-color:#535f61}html.theme--documenter-dark .file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-radius:.4em;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}html.theme--documenter-dark .file-cta{background-color:#282f2f;color:#fff}html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}html.theme--documenter-dark .file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}html.theme--documenter-dark .file-icon .fa{font-size:14px}html.theme--documenter-dark .label{color:#f2f2f2;display:block;font-size:1rem;font-weight:700}html.theme--documenter-dark .label:not(:last-child){margin-bottom:0.5em}html.theme--documenter-dark .label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}html.theme--documenter-dark .label.is-medium{font-size:1.25rem}html.theme--documenter-dark .label.is-large{font-size:1.5rem}html.theme--documenter-dark .help{display:block;font-size:.75rem;margin-top:0.25rem}html.theme--documenter-dark .help.is-white{color:#fff}html.theme--documenter-dark .help.is-black{color:#0a0a0a}html.theme--documenter-dark .help.is-light{color:#ecf0f1}html.theme--documenter-dark .help.is-dark,html.theme--documenter-dark .content kbd.help{color:#282f2f}html.theme--documenter-dark .help.is-primary,html.theme--documenter-dark .docstring>section>a.help.docs-sourcelink{color:#375a7f}html.theme--documenter-dark .help.is-link{color:#1abc9c}html.theme--documenter-dark .help.is-info{color:#024c7d}html.theme--documenter-dark .help.is-success{color:#008438}html.theme--documenter-dark .help.is-warning{color:#ad8100}html.theme--documenter-dark .help.is-danger{color:#9e1b0d}html.theme--documenter-dark .field:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.has-addons{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.has-addons .control:not(:last-child){margin-right:-1px}html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .button,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]){z-index:3}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}html.theme--documenter-dark .field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.has-addons.has-addons-centered{justify-content:center}html.theme--documenter-dark .field.has-addons.has-addons-right{justify-content:flex-end}html.theme--documenter-dark .field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .field.is-grouped{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.is-grouped>.control{flex-shrink:0}html.theme--documenter-dark .field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.is-grouped.is-grouped-centered{justify-content:center}html.theme--documenter-dark .field.is-grouped.is-grouped-right{justify-content:flex-end}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline{flex-wrap:wrap}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:last-child,html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field.is-horizontal{display:flex}}html.theme--documenter-dark .field-label .label{font-size:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}html.theme--documenter-dark .field-label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-normal{padding-top:0.375em}html.theme--documenter-dark .field-label.is-medium{font-size:1.25rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-large{font-size:1.5rem;padding-top:0.375em}}html.theme--documenter-dark .field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}html.theme--documenter-dark .field-body .field{margin-bottom:0}html.theme--documenter-dark .field-body>.field{flex-shrink:1}html.theme--documenter-dark .field-body>.field:not(.is-narrow){flex-grow:1}html.theme--documenter-dark .field-body>.field:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}html.theme--documenter-dark .control.has-icons-left .input:focus~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-left .select:focus~.icon,html.theme--documenter-dark .control.has-icons-right .input:focus~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-right .select:focus~.icon{color:#282f2f}html.theme--documenter-dark .control.has-icons-left .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-small~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-small~.icon{font-size:.75rem}html.theme--documenter-dark .control.has-icons-left .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}html.theme--documenter-dark .control.has-icons-left .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-large~.icon{font-size:1.5rem}html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon{color:#5e6d6f;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}html.theme--documenter-dark .control.has-icons-left .input,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input,html.theme--documenter-dark .control.has-icons-left .select select{padding-left:2.5em}html.theme--documenter-dark .control.has-icons-left .icon.is-left{left:0}html.theme--documenter-dark .control.has-icons-right .input,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input,html.theme--documenter-dark .control.has-icons-right .select select{padding-right:2.5em}html.theme--documenter-dark .control.has-icons-right .icon.is-right{right:0}html.theme--documenter-dark .control.is-loading::after{position:absolute !important;right:.625em;top:0.625em;z-index:4}html.theme--documenter-dark .control.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .control.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .control.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .breadcrumb{font-size:1rem;white-space:nowrap}html.theme--documenter-dark .breadcrumb a{align-items:center;color:#1abc9c;display:flex;justify-content:center;padding:0 .75em}html.theme--documenter-dark .breadcrumb a:hover{color:#1dd2af}html.theme--documenter-dark .breadcrumb li{align-items:center;display:flex}html.theme--documenter-dark .breadcrumb li:first-child a{padding-left:0}html.theme--documenter-dark .breadcrumb li.is-active a{color:#f2f2f2;cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb li+li::before{color:#8c9b9d;content:"\0002f"}html.theme--documenter-dark .breadcrumb ul,html.theme--documenter-dark .breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .breadcrumb .icon:first-child{margin-right:.5em}html.theme--documenter-dark .breadcrumb .icon:last-child{margin-left:.5em}html.theme--documenter-dark .breadcrumb.is-centered ol,html.theme--documenter-dark .breadcrumb.is-centered ul{justify-content:center}html.theme--documenter-dark .breadcrumb.is-right ol,html.theme--documenter-dark .breadcrumb.is-right ul{justify-content:flex-end}html.theme--documenter-dark .breadcrumb.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}html.theme--documenter-dark .breadcrumb.is-medium{font-size:1.25rem}html.theme--documenter-dark .breadcrumb.is-large{font-size:1.5rem}html.theme--documenter-dark .breadcrumb.has-arrow-separator li+li::before{content:"\02192"}html.theme--documenter-dark .breadcrumb.has-bullet-separator li+li::before{content:"\02022"}html.theme--documenter-dark .breadcrumb.has-dot-separator li+li::before{content:"\000b7"}html.theme--documenter-dark .breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}html.theme--documenter-dark .card{background-color:#fff;border-radius:.25rem;box-shadow:#171717;color:#fff;max-width:100%;position:relative}html.theme--documenter-dark .card-footer:first-child,html.theme--documenter-dark .card-content:first-child,html.theme--documenter-dark .card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-footer:last-child,html.theme--documenter-dark .card-content:last-child,html.theme--documenter-dark .card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);display:flex}html.theme--documenter-dark .card-header-title{align-items:center;color:#f2f2f2;display:flex;flex-grow:1;font-weight:700;padding:0.75rem 1rem}html.theme--documenter-dark .card-header-title.is-centered{justify-content:center}html.theme--documenter-dark .card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}html.theme--documenter-dark .card-image{display:block;position:relative}html.theme--documenter-dark .card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-content{background-color:rgba(0,0,0,0);padding:1.5rem}html.theme--documenter-dark .card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #ededed;align-items:stretch;display:flex}html.theme--documenter-dark .card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}html.theme--documenter-dark .card-footer-item:not(:last-child){border-right:1px solid #ededed}html.theme--documenter-dark .card .media:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .dropdown{display:inline-flex;position:relative;vertical-align:top}html.theme--documenter-dark .dropdown.is-active .dropdown-menu,html.theme--documenter-dark .dropdown.is-hoverable:hover .dropdown-menu{display:block}html.theme--documenter-dark .dropdown.is-right .dropdown-menu{left:auto;right:0}html.theme--documenter-dark .dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}html.theme--documenter-dark .dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .dropdown-content{background-color:#282f2f;border-radius:.4em;box-shadow:#171717;padding-bottom:.5rem;padding-top:.5rem}html.theme--documenter-dark .dropdown-item{color:#fff;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}html.theme--documenter-dark a.dropdown-item,html.theme--documenter-dark button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}html.theme--documenter-dark a.dropdown-item:hover,html.theme--documenter-dark button.dropdown-item:hover{background-color:#282f2f;color:#0a0a0a}html.theme--documenter-dark a.dropdown-item.is-active,html.theme--documenter-dark button.dropdown-item.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:0.5rem 0}html.theme--documenter-dark .level{align-items:center;justify-content:space-between}html.theme--documenter-dark .level code{border-radius:.4em}html.theme--documenter-dark .level img{display:inline-block;vertical-align:top}html.theme--documenter-dark .level.is-mobile{display:flex}html.theme--documenter-dark .level.is-mobile .level-left,html.theme--documenter-dark .level.is-mobile .level-right{display:flex}html.theme--documenter-dark .level.is-mobile .level-left+.level-right{margin-top:0}html.theme--documenter-dark .level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level{display:flex}html.theme--documenter-dark .level>.level-item:not(.is-narrow){flex-grow:1}}html.theme--documenter-dark .level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}html.theme--documenter-dark .level-item .title,html.theme--documenter-dark .level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){html.theme--documenter-dark .level-item:not(:last-child){margin-bottom:.75rem}}html.theme--documenter-dark .level-left,html.theme--documenter-dark .level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .level-left .level-item.is-flexible,html.theme--documenter-dark .level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left .level-item:not(:last-child),html.theme--documenter-dark .level-right .level-item:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){html.theme--documenter-dark .level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left{display:flex}}html.theme--documenter-dark .level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-right{display:flex}}html.theme--documenter-dark .media{align-items:flex-start;display:flex;text-align:inherit}html.theme--documenter-dark .media .content:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .media .media{border-top:1px solid rgba(94,109,111,0.5);display:flex;padding-top:.75rem}html.theme--documenter-dark .media .media .content:not(:last-child),html.theme--documenter-dark .media .media .control:not(:last-child){margin-bottom:.5rem}html.theme--documenter-dark .media .media .media{padding-top:.5rem}html.theme--documenter-dark .media .media .media+.media{margin-top:.5rem}html.theme--documenter-dark .media+.media{border-top:1px solid rgba(94,109,111,0.5);margin-top:1rem;padding-top:1rem}html.theme--documenter-dark .media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}html.theme--documenter-dark .media-left,html.theme--documenter-dark .media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .media-left{margin-right:1rem}html.theme--documenter-dark .media-right{margin-left:1rem}html.theme--documenter-dark .media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .media-content{overflow-x:auto}}html.theme--documenter-dark .menu{font-size:1rem}html.theme--documenter-dark .menu.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}html.theme--documenter-dark .menu.is-medium{font-size:1.25rem}html.theme--documenter-dark .menu.is-large{font-size:1.5rem}html.theme--documenter-dark .menu-list{line-height:1.25}html.theme--documenter-dark .menu-list a{border-radius:3px;color:#fff;display:block;padding:0.5em 0.75em}html.theme--documenter-dark .menu-list a:hover{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .menu-list a.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .menu-list li ul{border-left:1px solid #5e6d6f;margin:.75em;padding-left:.75em}html.theme--documenter-dark .menu-label{color:#fff;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}html.theme--documenter-dark .menu-label:not(:first-child){margin-top:1em}html.theme--documenter-dark .menu-label:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .message{background-color:#282f2f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .message strong{color:currentColor}html.theme--documenter-dark .message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .message.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}html.theme--documenter-dark .message.is-medium{font-size:1.25rem}html.theme--documenter-dark .message.is-large{font-size:1.5rem}html.theme--documenter-dark .message.is-white{background-color:#fff}html.theme--documenter-dark .message.is-white .message-header{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .message.is-white .message-body{border-color:#fff}html.theme--documenter-dark .message.is-black{background-color:#fafafa}html.theme--documenter-dark .message.is-black .message-header{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .message.is-black .message-body{border-color:#0a0a0a}html.theme--documenter-dark .message.is-light{background-color:#f9fafb}html.theme--documenter-dark .message.is-light .message-header{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .message.is-light .message-body{border-color:#ecf0f1}html.theme--documenter-dark .message.is-dark,html.theme--documenter-dark .content kbd.message{background-color:#f9fafa}html.theme--documenter-dark .message.is-dark .message-header,html.theme--documenter-dark .content kbd.message .message-header{background-color:#282f2f;color:#fff}html.theme--documenter-dark .message.is-dark .message-body,html.theme--documenter-dark .content kbd.message .message-body{border-color:#282f2f}html.theme--documenter-dark .message.is-primary,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink{background-color:#f1f5f9}html.theme--documenter-dark .message.is-primary .message-header,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-header{background-color:#375a7f;color:#fff}html.theme--documenter-dark .message.is-primary .message-body,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-body{border-color:#375a7f;color:#4d7eb2}html.theme--documenter-dark .message.is-link{background-color:#edfdf9}html.theme--documenter-dark .message.is-link .message-header{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .message.is-link .message-body{border-color:#1abc9c;color:#15987e}html.theme--documenter-dark .message.is-info{background-color:#ebf7ff}html.theme--documenter-dark .message.is-info .message-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .message.is-info .message-body{border-color:#024c7d;color:#0e9dfb}html.theme--documenter-dark .message.is-success{background-color:#ebfff3}html.theme--documenter-dark .message.is-success .message-header{background-color:#008438;color:#fff}html.theme--documenter-dark .message.is-success .message-body{border-color:#008438;color:#00eb64}html.theme--documenter-dark .message.is-warning{background-color:#fffaeb}html.theme--documenter-dark .message.is-warning .message-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .message.is-warning .message-body{border-color:#ad8100;color:#d19c00}html.theme--documenter-dark .message.is-danger{background-color:#fdeeec}html.theme--documenter-dark .message.is-danger .message-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .message.is-danger .message-body{border-color:#9e1b0d;color:#ec311d}html.theme--documenter-dark .message-header{align-items:center;background-color:#fff;border-radius:.4em .4em 0 0;color:rgba(0,0,0,0.7);display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}html.theme--documenter-dark .message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}html.theme--documenter-dark .message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}html.theme--documenter-dark .message-body{border-color:#5e6d6f;border-radius:.4em;border-style:solid;border-width:0 0 0 4px;color:#fff;padding:1.25em 1.5em}html.theme--documenter-dark .message-body code,html.theme--documenter-dark .message-body pre{background-color:#fff}html.theme--documenter-dark .message-body pre code{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}html.theme--documenter-dark .modal.is-active{display:flex}html.theme--documenter-dark .modal-background{background-color:rgba(10,10,10,0.86)}html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px){html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}html.theme--documenter-dark .modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}html.theme--documenter-dark .modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}html.theme--documenter-dark .modal-card-head,html.theme--documenter-dark .modal-card-foot{align-items:center;background-color:#282f2f;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}html.theme--documenter-dark .modal-card-head{border-bottom:1px solid #5e6d6f;border-top-left-radius:8px;border-top-right-radius:8px}html.theme--documenter-dark .modal-card-title{color:#f2f2f2;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}html.theme--documenter-dark .modal-card-foot{border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid #5e6d6f}html.theme--documenter-dark .modal-card-foot .button:not(:last-child){margin-right:.5em}html.theme--documenter-dark .modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}html.theme--documenter-dark .navbar{background-color:#375a7f;min-height:4rem;position:relative;z-index:30}html.theme--documenter-dark .navbar.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-white .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}html.theme--documenter-dark .navbar.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-black .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}html.theme--documenter-dark .navbar.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-light .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}}html.theme--documenter-dark .navbar.is-dark,html.theme--documenter-dark .content kbd.navbar{background-color:#282f2f;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-burger,html.theme--documenter-dark .content kbd.navbar .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-dark .navbar-start>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-end>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#282f2f;color:#fff}}html.theme--documenter-dark .navbar.is-primary,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-burger,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-primary .navbar-start>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-end>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#375a7f;color:#fff}}html.theme--documenter-dark .navbar.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-link .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c;color:#fff}}html.theme--documenter-dark .navbar.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-info .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#024c7d;color:#fff}}html.theme--documenter-dark .navbar.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-success .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#008438;color:#fff}}html.theme--documenter-dark .navbar.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-warning .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ad8100;color:#fff}}html.theme--documenter-dark .navbar.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-danger .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#9e1b0d;color:#fff}}html.theme--documenter-dark .navbar>.container{align-items:stretch;display:flex;min-height:4rem;width:100%}html.theme--documenter-dark .navbar.has-shadow{box-shadow:0 2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-bottom,html.theme--documenter-dark .navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-top{top:0}html.theme--documenter-dark html.has-navbar-fixed-top,html.theme--documenter-dark body.has-navbar-fixed-top{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom,html.theme--documenter-dark body.has-navbar-fixed-bottom{padding-bottom:4rem}html.theme--documenter-dark .navbar-brand,html.theme--documenter-dark .navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:4rem}html.theme--documenter-dark .navbar-brand a.navbar-item:focus,html.theme--documenter-dark .navbar-brand a.navbar-item:hover{background-color:transparent}html.theme--documenter-dark .navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}html.theme--documenter-dark .navbar-burger{color:#fff;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;cursor:pointer;display:block;height:4rem;position:relative;width:4rem;margin-left:auto}html.theme--documenter-dark .navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}html.theme--documenter-dark .navbar-burger span:nth-child(1){top:calc(50% - 6px)}html.theme--documenter-dark .navbar-burger span:nth-child(2){top:calc(50% - 1px)}html.theme--documenter-dark .navbar-burger span:nth-child(3){top:calc(50% + 4px)}html.theme--documenter-dark .navbar-burger:hover{background-color:rgba(0,0,0,0.05)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(2){opacity:0}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}html.theme--documenter-dark .navbar-menu{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{color:#fff;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}html.theme--documenter-dark .navbar-item .icon:only-child,html.theme--documenter-dark .navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}html.theme--documenter-dark a.navbar-item,html.theme--documenter-dark .navbar-link{cursor:pointer}html.theme--documenter-dark a.navbar-item:focus,html.theme--documenter-dark a.navbar-item:focus-within,html.theme--documenter-dark a.navbar-item:hover,html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link:focus,html.theme--documenter-dark .navbar-link:focus-within,html.theme--documenter-dark .navbar-link:hover,html.theme--documenter-dark .navbar-link.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-item{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .navbar-item img{max-height:1.75rem}html.theme--documenter-dark .navbar-item.has-dropdown{padding:0}html.theme--documenter-dark .navbar-item.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-item.is-tab{border-bottom:1px solid transparent;min-height:4rem;padding-bottom:calc(0.5rem - 1px)}html.theme--documenter-dark .navbar-item.is-tab:focus,html.theme--documenter-dark .navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c}html.theme--documenter-dark .navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c;border-bottom-style:solid;border-bottom-width:3px;color:#1abc9c;padding-bottom:calc(0.5rem - 3px)}html.theme--documenter-dark .navbar-content{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-link:not(.is-arrowless){padding-right:2.5em}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after{border-color:#fff;margin-top:-0.375em;right:1.125em}html.theme--documenter-dark .navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}html.theme--documenter-dark .navbar-divider{background-color:rgba(0,0,0,0.2);border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar>.container{display:block}html.theme--documenter-dark .navbar-brand .navbar-item,html.theme--documenter-dark .navbar-tabs .navbar-item{align-items:center;display:flex}html.theme--documenter-dark .navbar-link::after{display:none}html.theme--documenter-dark .navbar-menu{background-color:#375a7f;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}html.theme--documenter-dark .navbar-menu.is-active{display:block}html.theme--documenter-dark .navbar.is-fixed-bottom-touch,html.theme--documenter-dark .navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-touch{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-touch{top:0}html.theme--documenter-dark .navbar.is-fixed-top .navbar-menu,html.theme--documenter-dark .navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 4rem);overflow:auto}html.theme--documenter-dark html.has-navbar-fixed-top-touch,html.theme--documenter-dark body.has-navbar-fixed-top-touch{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-touch,html.theme--documenter-dark body.has-navbar-fixed-bottom-touch{padding-bottom:4rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar,html.theme--documenter-dark .navbar-menu,html.theme--documenter-dark .navbar-start,html.theme--documenter-dark .navbar-end{align-items:stretch;display:flex}html.theme--documenter-dark .navbar{min-height:4rem}html.theme--documenter-dark .navbar.is-spaced{padding:1rem 2rem}html.theme--documenter-dark .navbar.is-spaced .navbar-start,html.theme--documenter-dark .navbar.is-spaced .navbar-end{align-items:center}html.theme--documenter-dark .navbar.is-spaced a.navbar-item,html.theme--documenter-dark .navbar.is-spaced .navbar-link{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent a.navbar-item:hover,html.theme--documenter-dark .navbar.is-transparent a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-transparent .navbar-link:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-link:hover,html.theme--documenter-dark .navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-burger{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{align-items:center;display:flex}html.theme--documenter-dark .navbar-item.has-dropdown{align-items:stretch}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:1px solid rgba(0,0,0,0.2);border-radius:8px 8px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}html.theme--documenter-dark .navbar-menu{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .navbar-start{justify-content:flex-start;margin-right:auto}html.theme--documenter-dark .navbar-end{justify-content:flex-end;margin-left:auto}html.theme--documenter-dark .navbar-dropdown{background-color:#375a7f;border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid rgba(0,0,0,0.2);box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}html.theme--documenter-dark .navbar-dropdown a.navbar-item{padding-right:3rem}html.theme--documenter-dark .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}.navbar.is-spaced html.theme--documenter-dark .navbar-dropdown,html.theme--documenter-dark .navbar-dropdown.is-boxed{border-radius:8px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}html.theme--documenter-dark .navbar-dropdown.is-right{left:auto;right:0}html.theme--documenter-dark .navbar-divider{display:block}html.theme--documenter-dark .navbar>.container .navbar-brand,html.theme--documenter-dark .container>.navbar .navbar-brand{margin-left:-.75rem}html.theme--documenter-dark .navbar>.container .navbar-menu,html.theme--documenter-dark .container>.navbar .navbar-menu{margin-right:-.75rem}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop,html.theme--documenter-dark .navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-desktop{top:0}html.theme--documenter-dark html.has-navbar-fixed-top-desktop,html.theme--documenter-dark body.has-navbar-fixed-top-desktop{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-desktop,html.theme--documenter-dark body.has-navbar-fixed-bottom-desktop{padding-bottom:4rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-top,html.theme--documenter-dark body.has-spaced-navbar-fixed-top{padding-top:6rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-bottom,html.theme--documenter-dark body.has-spaced-navbar-fixed-bottom{padding-bottom:6rem}html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link.is-active{color:#1abc9c}html.theme--documenter-dark a.navbar-item.is-active:not(:focus):not(:hover),html.theme--documenter-dark .navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}html.theme--documenter-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown.is-active .navbar-link{background-color:rgba(0,0,0,0)}}html.theme--documenter-dark .hero.is-fullheight-with-navbar{min-height:calc(100vh - 4rem)}html.theme--documenter-dark .pagination{font-size:1rem;margin:-.25rem}html.theme--documenter-dark .pagination.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}html.theme--documenter-dark .pagination.is-medium{font-size:1.25rem}html.theme--documenter-dark .pagination.is-large{font-size:1.5rem}html.theme--documenter-dark .pagination.is-rounded .pagination-previous,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,html.theme--documenter-dark .pagination.is-rounded .pagination-next,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:9999px}html.theme--documenter-dark .pagination.is-rounded .pagination-link,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}html.theme--documenter-dark .pagination,html.theme--documenter-dark .pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link{border-color:#5e6d6f;color:#1abc9c;min-width:2.5em}html.theme--documenter-dark .pagination-previous:hover,html.theme--documenter-dark .pagination-next:hover,html.theme--documenter-dark .pagination-link:hover{border-color:#8c9b9d;color:#1dd2af}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus{border-color:#8c9b9d}html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-previous.is-disabled,html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-next.is-disabled,html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-link.is-disabled{background-color:#5e6d6f;border-color:#5e6d6f;box-shadow:none;color:#fff;opacity:0.5}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{padding-left:.75em;padding-right:.75em;white-space:nowrap}html.theme--documenter-dark .pagination-link.is-current{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .pagination-ellipsis{color:#8c9b9d;pointer-events:none}html.theme--documenter-dark .pagination-list{flex-wrap:wrap}html.theme--documenter-dark .pagination-list li{list-style:none}@media screen and (max-width: 768px){html.theme--documenter-dark .pagination{flex-wrap:wrap}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination-previous{order:2}html.theme--documenter-dark .pagination-next{order:3}html.theme--documenter-dark .pagination{justify-content:space-between;margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination.is-centered .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-centered .pagination-list{justify-content:center;order:2}html.theme--documenter-dark .pagination.is-centered .pagination-next{order:3}html.theme--documenter-dark .pagination.is-right .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-right .pagination-next{order:2}html.theme--documenter-dark .pagination.is-right .pagination-list{justify-content:flex-end;order:3}}html.theme--documenter-dark .panel{border-radius:8px;box-shadow:#171717;font-size:1rem}html.theme--documenter-dark .panel:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}html.theme--documenter-dark .panel.is-white .panel-block.is-active .panel-icon{color:#fff}html.theme--documenter-dark .panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}html.theme--documenter-dark .panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}html.theme--documenter-dark .panel.is-light .panel-heading{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .panel.is-light .panel-tabs a.is-active{border-bottom-color:#ecf0f1}html.theme--documenter-dark .panel.is-light .panel-block.is-active .panel-icon{color:#ecf0f1}html.theme--documenter-dark .panel.is-dark .panel-heading,html.theme--documenter-dark .content kbd.panel .panel-heading{background-color:#282f2f;color:#fff}html.theme--documenter-dark .panel.is-dark .panel-tabs a.is-active,html.theme--documenter-dark .content kbd.panel .panel-tabs a.is-active{border-bottom-color:#282f2f}html.theme--documenter-dark .panel.is-dark .panel-block.is-active .panel-icon,html.theme--documenter-dark .content kbd.panel .panel-block.is-active .panel-icon{color:#282f2f}html.theme--documenter-dark .panel.is-primary .panel-heading,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#375a7f;color:#fff}html.theme--documenter-dark .panel.is-primary .panel-tabs a.is-active,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#375a7f}html.theme--documenter-dark .panel.is-primary .panel-block.is-active .panel-icon,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#375a7f}html.theme--documenter-dark .panel.is-link .panel-heading{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .panel.is-link .panel-tabs a.is-active{border-bottom-color:#1abc9c}html.theme--documenter-dark .panel.is-link .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel.is-info .panel-heading{background-color:#024c7d;color:#fff}html.theme--documenter-dark .panel.is-info .panel-tabs a.is-active{border-bottom-color:#024c7d}html.theme--documenter-dark .panel.is-info .panel-block.is-active .panel-icon{color:#024c7d}html.theme--documenter-dark .panel.is-success .panel-heading{background-color:#008438;color:#fff}html.theme--documenter-dark .panel.is-success .panel-tabs a.is-active{border-bottom-color:#008438}html.theme--documenter-dark .panel.is-success .panel-block.is-active .panel-icon{color:#008438}html.theme--documenter-dark .panel.is-warning .panel-heading{background-color:#ad8100;color:#fff}html.theme--documenter-dark .panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ad8100}html.theme--documenter-dark .panel.is-warning .panel-block.is-active .panel-icon{color:#ad8100}html.theme--documenter-dark .panel.is-danger .panel-heading{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .panel.is-danger .panel-tabs a.is-active{border-bottom-color:#9e1b0d}html.theme--documenter-dark .panel.is-danger .panel-block.is-active .panel-icon{color:#9e1b0d}html.theme--documenter-dark .panel-tabs:not(:last-child),html.theme--documenter-dark .panel-block:not(:last-child){border-bottom:1px solid #ededed}html.theme--documenter-dark .panel-heading{background-color:#343c3d;border-radius:8px 8px 0 0;color:#f2f2f2;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}html.theme--documenter-dark .panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}html.theme--documenter-dark .panel-tabs a{border-bottom:1px solid #5e6d6f;margin-bottom:-1px;padding:0.5em}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#343c3d;color:#17a689}html.theme--documenter-dark .panel-list a{color:#fff}html.theme--documenter-dark .panel-list a:hover{color:#1abc9c}html.theme--documenter-dark .panel-block{align-items:center;color:#f2f2f2;display:flex;justify-content:flex-start;padding:0.5em 0.75em}html.theme--documenter-dark .panel-block input[type="checkbox"]{margin-right:.75em}html.theme--documenter-dark .panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}html.theme--documenter-dark .panel-block.is-wrapped{flex-wrap:wrap}html.theme--documenter-dark .panel-block.is-active{border-left-color:#1abc9c;color:#17a689}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel-block:last-child{border-bottom-left-radius:8px;border-bottom-right-radius:8px}html.theme--documenter-dark a.panel-block,html.theme--documenter-dark label.panel-block{cursor:pointer}html.theme--documenter-dark a.panel-block:hover,html.theme--documenter-dark label.panel-block:hover{background-color:#282f2f}html.theme--documenter-dark .panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#fff;margin-right:.75em}html.theme--documenter-dark .panel-icon .fa{font-size:inherit;line-height:inherit}html.theme--documenter-dark .tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}html.theme--documenter-dark .tabs a{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;color:#fff;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}html.theme--documenter-dark .tabs a:hover{border-bottom-color:#f2f2f2;color:#f2f2f2}html.theme--documenter-dark .tabs li{display:block}html.theme--documenter-dark .tabs li.is-active a{border-bottom-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .tabs ul{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}html.theme--documenter-dark .tabs ul.is-left{padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}html.theme--documenter-dark .tabs .icon:first-child{margin-right:.5em}html.theme--documenter-dark .tabs .icon:last-child{margin-left:.5em}html.theme--documenter-dark .tabs.is-centered ul{justify-content:center}html.theme--documenter-dark .tabs.is-right ul{justify-content:flex-end}html.theme--documenter-dark .tabs.is-boxed a{border:1px solid transparent;border-radius:.4em .4em 0 0}html.theme--documenter-dark .tabs.is-boxed a:hover{background-color:#282f2f;border-bottom-color:#5e6d6f}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#fff;border-color:#5e6d6f;border-bottom-color:rgba(0,0,0,0) !important}html.theme--documenter-dark .tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .tabs.is-toggle a{border-color:#5e6d6f;border-style:solid;border-width:1px;margin-bottom:0;position:relative}html.theme--documenter-dark .tabs.is-toggle a:hover{background-color:#282f2f;border-color:#8c9b9d;z-index:2}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .tabs.is-toggle li:first-child a{border-top-left-radius:.4em;border-bottom-left-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li:last-child a{border-top-right-radius:.4em;border-bottom-right-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li.is-active a{background-color:#1abc9c;border-color:#1abc9c;color:#fff;z-index:1}html.theme--documenter-dark .tabs.is-toggle ul{border-bottom:none}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}html.theme--documenter-dark .tabs.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}html.theme--documenter-dark .tabs.is-medium{font-size:1.25rem}html.theme--documenter-dark .tabs.is-large{font-size:1.5rem}html.theme--documenter-dark .column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>html.theme--documenter-dark .column.is-narrow{flex:none;width:unset}.columns.is-mobile>html.theme--documenter-dark .column.is-full{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-half{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-half{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-0{flex:none;width:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-0{margin-left:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-1{flex:none;width:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-2{margin-left:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-3{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-3{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-4{flex:none;width:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-5{margin-left:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-6{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-6{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-7{flex:none;width:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-8{margin-left:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-9{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-9{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-10{flex:none;width:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-11{margin-left:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-12{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){html.theme--documenter-dark .column.is-narrow-mobile{flex:none;width:unset}html.theme--documenter-dark .column.is-full-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-mobile{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-mobile{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-mobile{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-mobile{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-mobile{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-mobile{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-mobile{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-mobile{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-mobile{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-mobile{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-mobile{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-mobile{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-mobile{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-mobile{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-mobile{margin-left:80%}html.theme--documenter-dark .column.is-0-mobile{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-mobile{margin-left:0%}html.theme--documenter-dark .column.is-1-mobile{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-mobile{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-mobile{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-mobile{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-mobile{margin-left:25%}html.theme--documenter-dark .column.is-4-mobile{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-mobile{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-mobile{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-mobile{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-mobile{margin-left:50%}html.theme--documenter-dark .column.is-7-mobile{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-mobile{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-mobile{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-mobile{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-mobile{margin-left:75%}html.theme--documenter-dark .column.is-10-mobile{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-mobile{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-mobile{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-mobile{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .column.is-narrow,html.theme--documenter-dark .column.is-narrow-tablet{flex:none;width:unset}html.theme--documenter-dark .column.is-full,html.theme--documenter-dark .column.is-full-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters,html.theme--documenter-dark .column.is-three-quarters-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds,html.theme--documenter-dark .column.is-two-thirds-tablet{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half,html.theme--documenter-dark .column.is-half-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third,html.theme--documenter-dark .column.is-one-third-tablet{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter,html.theme--documenter-dark .column.is-one-quarter-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth,html.theme--documenter-dark .column.is-one-fifth-tablet{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths,html.theme--documenter-dark .column.is-two-fifths-tablet{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths,html.theme--documenter-dark .column.is-three-fifths-tablet{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths,html.theme--documenter-dark .column.is-four-fifths-tablet{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters,html.theme--documenter-dark .column.is-offset-three-quarters-tablet{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds,html.theme--documenter-dark .column.is-offset-two-thirds-tablet{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half,html.theme--documenter-dark .column.is-offset-half-tablet{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third,html.theme--documenter-dark .column.is-offset-one-third-tablet{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter,html.theme--documenter-dark .column.is-offset-one-quarter-tablet{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth,html.theme--documenter-dark .column.is-offset-one-fifth-tablet{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths,html.theme--documenter-dark .column.is-offset-two-fifths-tablet{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths,html.theme--documenter-dark .column.is-offset-three-fifths-tablet{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths,html.theme--documenter-dark .column.is-offset-four-fifths-tablet{margin-left:80%}html.theme--documenter-dark .column.is-0,html.theme--documenter-dark .column.is-0-tablet{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0,html.theme--documenter-dark .column.is-offset-0-tablet{margin-left:0%}html.theme--documenter-dark .column.is-1,html.theme--documenter-dark .column.is-1-tablet{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1,html.theme--documenter-dark .column.is-offset-1-tablet{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2,html.theme--documenter-dark .column.is-2-tablet{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2,html.theme--documenter-dark .column.is-offset-2-tablet{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3,html.theme--documenter-dark .column.is-3-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3,html.theme--documenter-dark .column.is-offset-3-tablet{margin-left:25%}html.theme--documenter-dark .column.is-4,html.theme--documenter-dark .column.is-4-tablet{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4,html.theme--documenter-dark .column.is-offset-4-tablet{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5,html.theme--documenter-dark .column.is-5-tablet{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5,html.theme--documenter-dark .column.is-offset-5-tablet{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6,html.theme--documenter-dark .column.is-6-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6,html.theme--documenter-dark .column.is-offset-6-tablet{margin-left:50%}html.theme--documenter-dark .column.is-7,html.theme--documenter-dark .column.is-7-tablet{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7,html.theme--documenter-dark .column.is-offset-7-tablet{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8,html.theme--documenter-dark .column.is-8-tablet{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8,html.theme--documenter-dark .column.is-offset-8-tablet{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9,html.theme--documenter-dark .column.is-9-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9,html.theme--documenter-dark .column.is-offset-9-tablet{margin-left:75%}html.theme--documenter-dark .column.is-10,html.theme--documenter-dark .column.is-10-tablet{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10,html.theme--documenter-dark .column.is-offset-10-tablet{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11,html.theme--documenter-dark .column.is-11-tablet{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11,html.theme--documenter-dark .column.is-offset-11-tablet{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12,html.theme--documenter-dark .column.is-12-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12,html.theme--documenter-dark .column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){html.theme--documenter-dark .column.is-narrow-touch{flex:none;width:unset}html.theme--documenter-dark .column.is-full-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-touch{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-touch{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-touch{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-touch{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-touch{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-touch{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-touch{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-touch{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-touch{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-touch{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-touch{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-touch{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-touch{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-touch{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-touch{margin-left:80%}html.theme--documenter-dark .column.is-0-touch{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-touch{margin-left:0%}html.theme--documenter-dark .column.is-1-touch{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-touch{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-touch{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-touch{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-touch{margin-left:25%}html.theme--documenter-dark .column.is-4-touch{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-touch{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-touch{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-touch{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-touch{margin-left:50%}html.theme--documenter-dark .column.is-7-touch{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-touch{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-touch{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-touch{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-touch{margin-left:75%}html.theme--documenter-dark .column.is-10-touch{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-touch{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-touch{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-touch{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){html.theme--documenter-dark .column.is-narrow-desktop{flex:none;width:unset}html.theme--documenter-dark .column.is-full-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-desktop{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-desktop{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-desktop{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-desktop{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-desktop{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-desktop{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-desktop{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-desktop{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-desktop{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-desktop{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-desktop{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-desktop{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-desktop{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-desktop{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-desktop{margin-left:80%}html.theme--documenter-dark .column.is-0-desktop{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-desktop{margin-left:0%}html.theme--documenter-dark .column.is-1-desktop{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-desktop{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-desktop{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-desktop{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-desktop{margin-left:25%}html.theme--documenter-dark .column.is-4-desktop{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-desktop{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-desktop{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-desktop{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-desktop{margin-left:50%}html.theme--documenter-dark .column.is-7-desktop{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-desktop{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-desktop{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-desktop{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-desktop{margin-left:75%}html.theme--documenter-dark .column.is-10-desktop{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-desktop{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-desktop{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-desktop{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){html.theme--documenter-dark .column.is-narrow-widescreen{flex:none;width:unset}html.theme--documenter-dark .column.is-full-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-widescreen{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-widescreen{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-widescreen{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-widescreen{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-widescreen{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-widescreen{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-widescreen{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-widescreen{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-widescreen{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-widescreen{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-widescreen{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-widescreen{margin-left:80%}html.theme--documenter-dark .column.is-0-widescreen{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-widescreen{margin-left:0%}html.theme--documenter-dark .column.is-1-widescreen{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-widescreen{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-widescreen{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-widescreen{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-4-widescreen{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-widescreen{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-widescreen{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-widescreen{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-7-widescreen{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-widescreen{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-widescreen{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-widescreen{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-10-widescreen{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-widescreen{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-widescreen{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-widescreen{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){html.theme--documenter-dark .column.is-narrow-fullhd{flex:none;width:unset}html.theme--documenter-dark .column.is-full-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-fullhd{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-fullhd{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-fullhd{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-fullhd{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-fullhd{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-fullhd{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-fullhd{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-fullhd{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-fullhd{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-fullhd{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-fullhd{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-fullhd{margin-left:80%}html.theme--documenter-dark .column.is-0-fullhd{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-fullhd{margin-left:0%}html.theme--documenter-dark .column.is-1-fullhd{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-fullhd{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-fullhd{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-fullhd{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-4-fullhd{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-fullhd{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-fullhd{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-fullhd{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-7-fullhd{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-fullhd{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-fullhd{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-fullhd{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-10-fullhd{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-fullhd{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-fullhd{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-fullhd{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-fullhd{margin-left:100%}}html.theme--documenter-dark .columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .columns:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}html.theme--documenter-dark .columns.is-centered{justify-content:center}html.theme--documenter-dark .columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}html.theme--documenter-dark .columns.is-gapless>.column{margin:0;padding:0 !important}html.theme--documenter-dark .columns.is-gapless:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .columns.is-gapless:last-child{margin-bottom:0}html.theme--documenter-dark .columns.is-mobile{display:flex}html.theme--documenter-dark .columns.is-multiline{flex-wrap:wrap}html.theme--documenter-dark .columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-desktop{display:flex}}html.theme--documenter-dark .columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}html.theme--documenter-dark .columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}html.theme--documenter-dark .columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-0-fullhd{--columnGap: 0rem}}html.theme--documenter-dark .columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-1-fullhd{--columnGap: .25rem}}html.theme--documenter-dark .columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-2-fullhd{--columnGap: .5rem}}html.theme--documenter-dark .columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-3-fullhd{--columnGap: .75rem}}html.theme--documenter-dark .columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-4-fullhd{--columnGap: 1rem}}html.theme--documenter-dark .columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}html.theme--documenter-dark .columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}html.theme--documenter-dark .columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}html.theme--documenter-dark .columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-8-fullhd{--columnGap: 2rem}}html.theme--documenter-dark .tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}html.theme--documenter-dark .tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .tile.is-ancestor:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .tile.is-ancestor:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .tile.is-child{margin:0 !important}html.theme--documenter-dark .tile.is-parent{padding:.75rem}html.theme--documenter-dark .tile.is-vertical{flex-direction:column}html.theme--documenter-dark .tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{html.theme--documenter-dark .tile:not(.is-child){display:flex}html.theme--documenter-dark .tile.is-1{flex:none;width:8.33333337%}html.theme--documenter-dark .tile.is-2{flex:none;width:16.66666674%}html.theme--documenter-dark .tile.is-3{flex:none;width:25%}html.theme--documenter-dark .tile.is-4{flex:none;width:33.33333337%}html.theme--documenter-dark .tile.is-5{flex:none;width:41.66666674%}html.theme--documenter-dark .tile.is-6{flex:none;width:50%}html.theme--documenter-dark .tile.is-7{flex:none;width:58.33333337%}html.theme--documenter-dark .tile.is-8{flex:none;width:66.66666674%}html.theme--documenter-dark .tile.is-9{flex:none;width:75%}html.theme--documenter-dark .tile.is-10{flex:none;width:83.33333337%}html.theme--documenter-dark .tile.is-11{flex:none;width:91.66666674%}html.theme--documenter-dark .tile.is-12{flex:none;width:100%}}html.theme--documenter-dark .hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}html.theme--documenter-dark .hero .navbar{background:none}html.theme--documenter-dark .hero .tabs ul{border-bottom:none}html.theme--documenter-dark .hero.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-white strong{color:inherit}html.theme--documenter-dark .hero.is-white .title{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .subtitle{color:rgba(10,10,10,0.9)}html.theme--documenter-dark .hero.is-white .subtitle a:not(.button),html.theme--documenter-dark .hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-white .navbar-menu{background-color:#fff}}html.theme--documenter-dark .hero.is-white .navbar-item,html.theme--documenter-dark .hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}html.theme--documenter-dark .hero.is-white a.navbar-item:hover,html.theme--documenter-dark .hero.is-white a.navbar-item.is-active,html.theme--documenter-dark .hero.is-white .navbar-link:hover,html.theme--documenter-dark .hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}html.theme--documenter-dark .hero.is-white .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-white .tabs li.is-active a{color:#fff !important;opacity:1}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}html.theme--documenter-dark .hero.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-black strong{color:inherit}html.theme--documenter-dark .hero.is-black .title{color:#fff}html.theme--documenter-dark .hero.is-black .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-black .subtitle a:not(.button),html.theme--documenter-dark .hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-black .navbar-menu{background-color:#0a0a0a}}html.theme--documenter-dark .hero.is-black .navbar-item,html.theme--documenter-dark .hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-black a.navbar-item:hover,html.theme--documenter-dark .hero.is-black a.navbar-item.is-active,html.theme--documenter-dark .hero.is-black .navbar-link:hover,html.theme--documenter-dark .hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .hero.is-black .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-black .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-black .tabs li.is-active a{color:#0a0a0a !important;opacity:1}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}html.theme--documenter-dark .hero.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-light strong{color:inherit}html.theme--documenter-dark .hero.is-light .title{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .subtitle{color:rgba(0,0,0,0.9)}html.theme--documenter-dark .hero.is-light .subtitle a:not(.button),html.theme--documenter-dark .hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-light .navbar-menu{background-color:#ecf0f1}}html.theme--documenter-dark .hero.is-light .navbar-item,html.theme--documenter-dark .hero.is-light .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a.navbar-item:hover,html.theme--documenter-dark .hero.is-light a.navbar-item.is-active,html.theme--documenter-dark .hero.is-light .navbar-link:hover,html.theme--documenter-dark .hero.is-light .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}html.theme--documenter-dark .hero.is-light .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-light .tabs li.is-active a{color:#ecf0f1 !important;opacity:1}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .hero.is-light.is-bold{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}}html.theme--documenter-dark .hero.is-dark,html.theme--documenter-dark .content kbd.hero{background-color:#282f2f;color:#fff}html.theme--documenter-dark .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-dark strong,html.theme--documenter-dark .content kbd.hero strong{color:inherit}html.theme--documenter-dark .hero.is-dark .title,html.theme--documenter-dark .content kbd.hero .title{color:#fff}html.theme--documenter-dark .hero.is-dark .subtitle,html.theme--documenter-dark .content kbd.hero .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-dark .subtitle a:not(.button),html.theme--documenter-dark .content kbd.hero .subtitle a:not(.button),html.theme--documenter-dark .hero.is-dark .subtitle strong,html.theme--documenter-dark .content kbd.hero .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-dark .navbar-menu,html.theme--documenter-dark .content kbd.hero .navbar-menu{background-color:#282f2f}}html.theme--documenter-dark .hero.is-dark .navbar-item,html.theme--documenter-dark .content kbd.hero .navbar-item,html.theme--documenter-dark .hero.is-dark .navbar-link,html.theme--documenter-dark .content kbd.hero .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-dark a.navbar-item:hover,html.theme--documenter-dark .content kbd.hero a.navbar-item:hover,html.theme--documenter-dark .hero.is-dark a.navbar-item.is-active,html.theme--documenter-dark .content kbd.hero a.navbar-item.is-active,html.theme--documenter-dark .hero.is-dark .navbar-link:hover,html.theme--documenter-dark .content kbd.hero .navbar-link:hover,html.theme--documenter-dark .hero.is-dark .navbar-link.is-active,html.theme--documenter-dark .content kbd.hero .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .hero.is-dark .tabs a,html.theme--documenter-dark .content kbd.hero .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-dark .tabs a:hover,html.theme--documenter-dark .content kbd.hero .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-dark .tabs li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs li.is-active a{color:#282f2f !important;opacity:1}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#282f2f}html.theme--documenter-dark .hero.is-dark.is-bold,html.theme--documenter-dark .content kbd.hero.is-bold{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-dark.is-bold .navbar-menu,html.theme--documenter-dark .content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}}html.theme--documenter-dark .hero.is-primary,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-primary strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink strong{color:inherit}html.theme--documenter-dark .hero.is-primary .title,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .title{color:#fff}html.theme--documenter-dark .hero.is-primary .subtitle,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-primary .subtitle a:not(.button),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),html.theme--documenter-dark .hero.is-primary .subtitle strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-primary .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#375a7f}}html.theme--documenter-dark .hero.is-primary .navbar-item,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-item,html.theme--documenter-dark .hero.is-primary .navbar-link,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-primary a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,html.theme--documenter-dark .hero.is-primary a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,html.theme--documenter-dark .hero.is-primary .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link:hover,html.theme--documenter-dark .hero.is-primary .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .hero.is-primary .tabs a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-primary .tabs a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-primary .tabs li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{color:#375a7f !important;opacity:1}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#375a7f}html.theme--documenter-dark .hero.is-primary.is-bold,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-primary.is-bold .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}}html.theme--documenter-dark .hero.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-link strong{color:inherit}html.theme--documenter-dark .hero.is-link .title{color:#fff}html.theme--documenter-dark .hero.is-link .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-link .subtitle a:not(.button),html.theme--documenter-dark .hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-link .navbar-menu{background-color:#1abc9c}}html.theme--documenter-dark .hero.is-link .navbar-item,html.theme--documenter-dark .hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-link a.navbar-item:hover,html.theme--documenter-dark .hero.is-link a.navbar-item.is-active,html.theme--documenter-dark .hero.is-link .navbar-link:hover,html.theme--documenter-dark .hero.is-link .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .hero.is-link .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-link .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-link .tabs li.is-active a{color:#1abc9c !important;opacity:1}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#1abc9c}html.theme--documenter-dark .hero.is-link.is-bold{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}}html.theme--documenter-dark .hero.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-info strong{color:inherit}html.theme--documenter-dark .hero.is-info .title{color:#fff}html.theme--documenter-dark .hero.is-info .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-info .subtitle a:not(.button),html.theme--documenter-dark .hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-info .navbar-menu{background-color:#024c7d}}html.theme--documenter-dark .hero.is-info .navbar-item,html.theme--documenter-dark .hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-info a.navbar-item:hover,html.theme--documenter-dark .hero.is-info a.navbar-item.is-active,html.theme--documenter-dark .hero.is-info .navbar-link:hover,html.theme--documenter-dark .hero.is-info .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .hero.is-info .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-info .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-info .tabs li.is-active a{color:#024c7d !important;opacity:1}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#024c7d}html.theme--documenter-dark .hero.is-info.is-bold{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}}html.theme--documenter-dark .hero.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-success strong{color:inherit}html.theme--documenter-dark .hero.is-success .title{color:#fff}html.theme--documenter-dark .hero.is-success .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-success .subtitle a:not(.button),html.theme--documenter-dark .hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-success .navbar-menu{background-color:#008438}}html.theme--documenter-dark .hero.is-success .navbar-item,html.theme--documenter-dark .hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-success a.navbar-item:hover,html.theme--documenter-dark .hero.is-success a.navbar-item.is-active,html.theme--documenter-dark .hero.is-success .navbar-link:hover,html.theme--documenter-dark .hero.is-success .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .hero.is-success .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-success .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-success .tabs li.is-active a{color:#008438 !important;opacity:1}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#008438}html.theme--documenter-dark .hero.is-success.is-bold{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}}html.theme--documenter-dark .hero.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-warning strong{color:inherit}html.theme--documenter-dark .hero.is-warning .title{color:#fff}html.theme--documenter-dark .hero.is-warning .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-warning .subtitle a:not(.button),html.theme--documenter-dark .hero.is-warning .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-warning .navbar-menu{background-color:#ad8100}}html.theme--documenter-dark .hero.is-warning .navbar-item,html.theme--documenter-dark .hero.is-warning .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-warning a.navbar-item:hover,html.theme--documenter-dark .hero.is-warning a.navbar-item.is-active,html.theme--documenter-dark .hero.is-warning .navbar-link:hover,html.theme--documenter-dark .hero.is-warning .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .hero.is-warning .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-warning .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-warning .tabs li.is-active a{color:#ad8100 !important;opacity:1}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ad8100}html.theme--documenter-dark .hero.is-warning.is-bold{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}}html.theme--documenter-dark .hero.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-danger strong{color:inherit}html.theme--documenter-dark .hero.is-danger .title{color:#fff}html.theme--documenter-dark .hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-danger .subtitle a:not(.button),html.theme--documenter-dark .hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-danger .navbar-menu{background-color:#9e1b0d}}html.theme--documenter-dark .hero.is-danger .navbar-item,html.theme--documenter-dark .hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-danger a.navbar-item:hover,html.theme--documenter-dark .hero.is-danger a.navbar-item.is-active,html.theme--documenter-dark .hero.is-danger .navbar-link:hover,html.theme--documenter-dark .hero.is-danger .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .hero.is-danger .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-danger .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-danger .tabs li.is-active a{color:#9e1b0d !important;opacity:1}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#9e1b0d}html.theme--documenter-dark .hero.is-danger.is-bold{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}}html.theme--documenter-dark .hero.is-small .hero-body,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding:1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-large .hero-body{padding:18rem 6rem}}html.theme--documenter-dark .hero.is-halfheight .hero-body,html.theme--documenter-dark .hero.is-fullheight .hero-body,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}html.theme--documenter-dark .hero.is-halfheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .hero.is-halfheight{min-height:50vh}html.theme--documenter-dark .hero.is-fullheight{min-height:100vh}html.theme--documenter-dark .hero-video{overflow:hidden}html.theme--documenter-dark .hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}html.theme--documenter-dark .hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-video{display:none}}html.theme--documenter-dark .hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-buttons .button{display:flex}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-buttons{display:flex;justify-content:center}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-right:1.5rem}}html.theme--documenter-dark .hero-head,html.theme--documenter-dark .hero-foot{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-body{padding:3rem 3rem}}html.theme--documenter-dark .section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){html.theme--documenter-dark .section{padding:3rem 3rem}html.theme--documenter-dark .section.is-medium{padding:9rem 4.5rem}html.theme--documenter-dark .section.is-large{padding:18rem 6rem}}html.theme--documenter-dark .footer{background-color:#282f2f;padding:3rem 1.5rem 6rem}html.theme--documenter-dark hr{height:1px}html.theme--documenter-dark h6{text-transform:uppercase;letter-spacing:0.5px}html.theme--documenter-dark .hero{background-color:#343c3d}html.theme--documenter-dark a{transition:all 200ms ease}html.theme--documenter-dark .button{transition:all 200ms ease;border-width:1px;color:#fff}html.theme--documenter-dark .button.is-active,html.theme--documenter-dark .button.is-focused,html.theme--documenter-dark .button:active,html.theme--documenter-dark .button:focus{box-shadow:0 0 0 2px rgba(140,155,157,0.5)}html.theme--documenter-dark .button.is-white.is-hovered,html.theme--documenter-dark .button.is-white:hover{background-color:#fff}html.theme--documenter-dark .button.is-white.is-active,html.theme--documenter-dark .button.is-white.is-focused,html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white:focus{border-color:#fff;box-shadow:0 0 0 2px rgba(255,255,255,0.5)}html.theme--documenter-dark .button.is-black.is-hovered,html.theme--documenter-dark .button.is-black:hover{background-color:#1d1d1d}html.theme--documenter-dark .button.is-black.is-active,html.theme--documenter-dark .button.is-black.is-focused,html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black:focus{border-color:#0a0a0a;box-shadow:0 0 0 2px rgba(10,10,10,0.5)}html.theme--documenter-dark .button.is-light.is-hovered,html.theme--documenter-dark .button.is-light:hover{background-color:#fff}html.theme--documenter-dark .button.is-light.is-active,html.theme--documenter-dark .button.is-light.is-focused,html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light:focus{border-color:#ecf0f1;box-shadow:0 0 0 2px rgba(236,240,241,0.5)}html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered,html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover{background-color:#3a4344}html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused,html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus{border-color:#282f2f;box-shadow:0 0 0 2px rgba(40,47,47,0.5)}html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover{background-color:#436d9a}html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink,html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus{border-color:#375a7f;box-shadow:0 0 0 2px rgba(55,90,127,0.5)}html.theme--documenter-dark .button.is-link.is-hovered,html.theme--documenter-dark .button.is-link:hover{background-color:#1fdeb8}html.theme--documenter-dark .button.is-link.is-active,html.theme--documenter-dark .button.is-link.is-focused,html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link:focus{border-color:#1abc9c;box-shadow:0 0 0 2px rgba(26,188,156,0.5)}html.theme--documenter-dark .button.is-info.is-hovered,html.theme--documenter-dark .button.is-info:hover{background-color:#0363a3}html.theme--documenter-dark .button.is-info.is-active,html.theme--documenter-dark .button.is-info.is-focused,html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info:focus{border-color:#024c7d;box-shadow:0 0 0 2px rgba(2,76,125,0.5)}html.theme--documenter-dark .button.is-success.is-hovered,html.theme--documenter-dark .button.is-success:hover{background-color:#00aa48}html.theme--documenter-dark .button.is-success.is-active,html.theme--documenter-dark .button.is-success.is-focused,html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success:focus{border-color:#008438;box-shadow:0 0 0 2px rgba(0,132,56,0.5)}html.theme--documenter-dark .button.is-warning.is-hovered,html.theme--documenter-dark .button.is-warning:hover{background-color:#d39e00}html.theme--documenter-dark .button.is-warning.is-active,html.theme--documenter-dark .button.is-warning.is-focused,html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning:focus{border-color:#ad8100;box-shadow:0 0 0 2px rgba(173,129,0,0.5)}html.theme--documenter-dark .button.is-danger.is-hovered,html.theme--documenter-dark .button.is-danger:hover{background-color:#c12110}html.theme--documenter-dark .button.is-danger.is-active,html.theme--documenter-dark .button.is-danger.is-focused,html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger:focus{border-color:#9e1b0d;box-shadow:0 0 0 2px rgba(158,27,13,0.5)}html.theme--documenter-dark .label{color:#dbdee0}html.theme--documenter-dark .button,html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .select,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea{height:2.5em}html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .textarea{transition:all 200ms ease;box-shadow:none;border-width:1px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .select:after,html.theme--documenter-dark .select select{border-width:1px}html.theme--documenter-dark .control.has-addons .button,html.theme--documenter-dark .control.has-addons .input,html.theme--documenter-dark .control.has-addons #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-addons form.docs-search>input,html.theme--documenter-dark .control.has-addons .select{margin-right:-1px}html.theme--documenter-dark .notification{background-color:#343c3d}html.theme--documenter-dark .card{box-shadow:none;border:1px solid #343c3d;background-color:#282f2f;border-radius:.4em}html.theme--documenter-dark .card .card-image img{border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-header{box-shadow:none;background-color:rgba(18,18,18,0.2);border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-footer{background-color:rgba(18,18,18,0.2)}html.theme--documenter-dark .card .card-footer,html.theme--documenter-dark .card .card-footer-item{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .notification.is-white a:not(.button){color:#0a0a0a;text-decoration:underline}html.theme--documenter-dark .notification.is-black a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-light a:not(.button){color:rgba(0,0,0,0.7);text-decoration:underline}html.theme--documenter-dark .notification.is-dark a:not(.button),html.theme--documenter-dark .content kbd.notification a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-primary a:not(.button),html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-link a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-info a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-success a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-warning a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-danger a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .tag,html.theme--documenter-dark .content kbd,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{border-radius:.4em}html.theme--documenter-dark .menu-list a{transition:all 300ms ease}html.theme--documenter-dark .modal-card-body{background-color:#282f2f}html.theme--documenter-dark .modal-card-foot,html.theme--documenter-dark .modal-card-head{border-color:#343c3d}html.theme--documenter-dark .message-header{font-weight:700;background-color:#343c3d;color:#fff}html.theme--documenter-dark .message-body{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .navbar{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent{background:none}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar .navbar-menu{background-color:#375a7f;border-radius:0 0 .4em .4em}}html.theme--documenter-dark .hero .navbar,html.theme--documenter-dark body>.navbar{border-radius:0}html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous{border-width:1px}html.theme--documenter-dark .panel-block,html.theme--documenter-dark .panel-heading,html.theme--documenter-dark .panel-tabs{border-width:1px}html.theme--documenter-dark .panel-block:first-child,html.theme--documenter-dark .panel-heading:first-child,html.theme--documenter-dark .panel-tabs:first-child{border-top-width:1px}html.theme--documenter-dark .panel-heading{font-weight:700}html.theme--documenter-dark .panel-tabs a{border-width:1px;margin-bottom:-1px}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#17a689}html.theme--documenter-dark .panel-block:hover{color:#1dd2af}html.theme--documenter-dark .panel-block:hover .panel-icon{color:#1dd2af}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#17a689}html.theme--documenter-dark .tabs a{border-bottom-width:1px;margin-bottom:-1px}html.theme--documenter-dark .tabs ul{border-bottom-width:1px}html.theme--documenter-dark .tabs.is-boxed a{border-width:1px}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#1f2424}html.theme--documenter-dark .tabs.is-toggle li a{border-width:1px;margin-bottom:0}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .hero.is-white .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-black .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-light .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-dark .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .content kbd.hero .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-primary .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-link .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-info .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-success .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-warning .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-danger .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark h1 .docs-heading-anchor,html.theme--documenter-dark h1 .docs-heading-anchor:hover,html.theme--documenter-dark h1 .docs-heading-anchor:visited,html.theme--documenter-dark h2 .docs-heading-anchor,html.theme--documenter-dark h2 .docs-heading-anchor:hover,html.theme--documenter-dark h2 .docs-heading-anchor:visited,html.theme--documenter-dark h3 .docs-heading-anchor,html.theme--documenter-dark h3 .docs-heading-anchor:hover,html.theme--documenter-dark h3 .docs-heading-anchor:visited,html.theme--documenter-dark h4 .docs-heading-anchor,html.theme--documenter-dark h4 .docs-heading-anchor:hover,html.theme--documenter-dark h4 .docs-heading-anchor:visited,html.theme--documenter-dark h5 .docs-heading-anchor,html.theme--documenter-dark h5 .docs-heading-anchor:hover,html.theme--documenter-dark h5 .docs-heading-anchor:visited,html.theme--documenter-dark h6 .docs-heading-anchor,html.theme--documenter-dark h6 .docs-heading-anchor:hover,html.theme--documenter-dark h6 .docs-heading-anchor:visited{color:#f2f2f2}html.theme--documenter-dark h1 .docs-heading-anchor-permalink,html.theme--documenter-dark h2 .docs-heading-anchor-permalink,html.theme--documenter-dark h3 .docs-heading-anchor-permalink,html.theme--documenter-dark h4 .docs-heading-anchor-permalink,html.theme--documenter-dark h5 .docs-heading-anchor-permalink,html.theme--documenter-dark h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}html.theme--documenter-dark h1 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h2 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h3 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h4 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h5 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f0c1"}html.theme--documenter-dark h1:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h2:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h3:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h4:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h5:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h6:hover .docs-heading-anchor-permalink{visibility:visible}html.theme--documenter-dark .docs-light-only{display:none !important}html.theme--documenter-dark pre{position:relative;overflow:hidden}html.theme--documenter-dark pre code,html.theme--documenter-dark pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}html.theme--documenter-dark pre code:first-of-type,html.theme--documenter-dark pre code.hljs:first-of-type{padding-top:0.5rem !important}html.theme--documenter-dark pre code:last-of-type,html.theme--documenter-dark pre code.hljs:last-of-type{padding-bottom:0.5rem !important}html.theme--documenter-dark pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 6 Free";color:#fff;cursor:pointer;text-align:center}html.theme--documenter-dark pre .copy-button:focus,html.theme--documenter-dark pre .copy-button:hover{opacity:1;background:rgba(255,255,255,0.1);color:#1abc9c}html.theme--documenter-dark pre .copy-button.success{color:#259a12;opacity:1}html.theme--documenter-dark pre .copy-button.error{color:#cb3c33;opacity:1}html.theme--documenter-dark pre:hover .copy-button{opacity:1}html.theme--documenter-dark .admonition{background-color:#282f2f;border-style:solid;border-width:1px;border-color:#5e6d6f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .admonition strong{color:currentColor}html.theme--documenter-dark .admonition.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}html.theme--documenter-dark .admonition.is-medium{font-size:1.25rem}html.theme--documenter-dark .admonition.is-large{font-size:1.5rem}html.theme--documenter-dark .admonition.is-default{background-color:#282f2f;border-color:#5e6d6f}html.theme--documenter-dark .admonition.is-default>.admonition-header{background-color:#5e6d6f;color:#fff}html.theme--documenter-dark .admonition.is-default>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-info{background-color:#282f2f;border-color:#024c7d}html.theme--documenter-dark .admonition.is-info>.admonition-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .admonition.is-info>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-success{background-color:#282f2f;border-color:#008438}html.theme--documenter-dark .admonition.is-success>.admonition-header{background-color:#008438;color:#fff}html.theme--documenter-dark .admonition.is-success>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-warning{background-color:#282f2f;border-color:#ad8100}html.theme--documenter-dark .admonition.is-warning>.admonition-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .admonition.is-warning>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-danger{background-color:#282f2f;border-color:#9e1b0d}html.theme--documenter-dark .admonition.is-danger>.admonition-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .admonition.is-danger>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-compat{background-color:#282f2f;border-color:#137886}html.theme--documenter-dark .admonition.is-compat>.admonition-header{background-color:#137886;color:#fff}html.theme--documenter-dark .admonition.is-compat>.admonition-body{color:#fff}html.theme--documenter-dark .admonition-header{color:#fff;background-color:#5e6d6f;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}html.theme--documenter-dark .admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}html.theme--documenter-dark details.admonition.is-details>.admonition-header{list-style:none}html.theme--documenter-dark details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}html.theme--documenter-dark details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}html.theme--documenter-dark .admonition-body{color:#fff;padding:0.5rem .75rem}html.theme--documenter-dark .admonition-body pre{background-color:#282f2f}html.theme--documenter-dark .admonition-body code{background-color:rgba(255,255,255,0.05)}html.theme--documenter-dark .docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #5e6d6f;box-shadow:none;max-width:100%}html.theme--documenter-dark .docstring>header{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#282f2f;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>header code{background-color:transparent}html.theme--documenter-dark .docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}html.theme--documenter-dark .docstring>header .docstring-binding{margin-right:0.3em}html.theme--documenter-dark .docstring>header .docstring-category{margin-left:0.3em}html.theme--documenter-dark .docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>section:last-child{border-bottom:none}html.theme--documenter-dark .docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}html.theme--documenter-dark .docstring>section>a.docs-sourcelink:focus{opacity:1 !important}html.theme--documenter-dark .docstring:hover>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring>section:hover a.docs-sourcelink{opacity:1}html.theme--documenter-dark .documenter-example-output{background-color:#1f2424}html.theme--documenter-dark .outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#282f2f;color:#fff;border-bottom:3px solid #9e1b0d;padding:10px 35px;text-align:center;font-size:15px}html.theme--documenter-dark .outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}html.theme--documenter-dark .outdated-warning-overlay a{color:#1abc9c}html.theme--documenter-dark .outdated-warning-overlay a:hover{color:#1dd2af}html.theme--documenter-dark .content pre{border:1px solid #5e6d6f}html.theme--documenter-dark .content code{font-weight:inherit}html.theme--documenter-dark .content a code{color:#1abc9c}html.theme--documenter-dark .content h1 code,html.theme--documenter-dark .content h2 code,html.theme--documenter-dark .content h3 code,html.theme--documenter-dark .content h4 code,html.theme--documenter-dark .content h5 code,html.theme--documenter-dark .content h6 code{color:#f2f2f2}html.theme--documenter-dark .content table{display:block;width:initial;max-width:100%;overflow-x:auto}html.theme--documenter-dark .content blockquote>ul:first-child,html.theme--documenter-dark .content blockquote>ol:first-child,html.theme--documenter-dark .content .admonition-body>ul:first-child,html.theme--documenter-dark .content .admonition-body>ol:first-child{margin-top:0}html.theme--documenter-dark pre,html.theme--documenter-dark code{font-variant-ligatures:no-contextual}html.theme--documenter-dark .breadcrumb a.is-disabled{cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb a.is-disabled,html.theme--documenter-dark .breadcrumb a.is-disabled:hover{color:#f2f2f2}html.theme--documenter-dark .hljs{background:initial !important}html.theme--documenter-dark .katex .katex-mathml{top:0;right:0}html.theme--documenter-dark .katex-display,html.theme--documenter-dark mjx-container,html.theme--documenter-dark .MathJax_Display{margin:0.5em 0 !important}html.theme--documenter-dark html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}html.theme--documenter-dark li.no-marker{list-style:none}html.theme--documenter-dark #documenter .docs-main>article{overflow-wrap:break-word}html.theme--documenter-dark #documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main{width:100%}html.theme--documenter-dark #documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-main>header,html.theme--documenter-dark #documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar{background-color:#1f2424;border-bottom:1px solid #5e6d6f;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-icon,html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #171717;transition-duration:0.7s;-webkit-transition-duration:0.7s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}html.theme--documenter-dark #documenter .docs-main section.footnotes{border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-main section.footnotes li .tag:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .content kbd:first-child,html.theme--documenter-dark .content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}html.theme--documenter-dark #documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #5e6d6f;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage,html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}html.theme--documenter-dark #documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}html.theme--documenter-dark #documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}html.theme--documenter-dark #documenter .docs-sidebar{display:flex;flex-direction:column;color:#fff;background-color:#282f2f;border-right:1px solid #5e6d6f;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}html.theme--documenter-dark #documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #171717}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar{left:0;top:0}}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a,html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a:hover{color:#fff}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector{border-top:1px solid #5e6d6f;display:none;padding:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector.visible{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #5e6d6f;padding-bottom:1.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f054"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#fff;background:#282f2f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu a.tocitem:hover,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#fff;background-color:#32393a}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #5e6d6f;border-bottom:1px solid #5e6d6f;background-color:#1f2424}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#1f2424;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#32393a;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{width:14.4rem}html.theme--documenter-dark #documenter .docs-sidebar #documenter-search-query{color:#868c98;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}html.theme--documenter-dark kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(245,245,245,0.6);box-shadow:0 2px 0 1px rgba(245,245,245,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}html.theme--documenter-dark .search-min-width-50{min-width:50%}html.theme--documenter-dark .search-min-height-100{min-height:100%}html.theme--documenter-dark .search-modal-card-body{max-height:calc(100vh - 15rem)}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333;background-color:#f1f5f9}html.theme--documenter-dark .search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}html.theme--documenter-dark .search-filter:hover,html.theme--documenter-dark .search-filter:focus{color:#333}html.theme--documenter-dark .search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}html.theme--documenter-dark .search-filter-selected:hover,html.theme--documenter-dark .search-filter-selected:focus{color:#f5f5f5}html.theme--documenter-dark .search-result-highlight{background-color:#ffdd57;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .search-result-title{width:85%;color:#f5f5f5}html.theme--documenter-dark .search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-thumb,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-track,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem}html.theme--documenter-dark .gap-8{gap:2rem}html.theme--documenter-dark{background-color:#1f2424;font-size:16px;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark .ansi span.sgr1{font-weight:bolder}html.theme--documenter-dark .ansi span.sgr2{font-weight:lighter}html.theme--documenter-dark .ansi span.sgr3{font-style:italic}html.theme--documenter-dark .ansi span.sgr4{text-decoration:underline}html.theme--documenter-dark .ansi span.sgr7{color:#1f2424;background-color:#fff}html.theme--documenter-dark .ansi span.sgr8{color:transparent}html.theme--documenter-dark .ansi span.sgr8 span{color:transparent}html.theme--documenter-dark .ansi span.sgr9{text-decoration:line-through}html.theme--documenter-dark .ansi span.sgr30{color:#242424}html.theme--documenter-dark .ansi span.sgr31{color:#f6705f}html.theme--documenter-dark .ansi span.sgr32{color:#4fb43a}html.theme--documenter-dark .ansi span.sgr33{color:#f4c72f}html.theme--documenter-dark .ansi span.sgr34{color:#7587f0}html.theme--documenter-dark .ansi span.sgr35{color:#bc89d3}html.theme--documenter-dark .ansi span.sgr36{color:#49b6ca}html.theme--documenter-dark .ansi span.sgr37{color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr40{background-color:#242424}html.theme--documenter-dark .ansi span.sgr41{background-color:#f6705f}html.theme--documenter-dark .ansi span.sgr42{background-color:#4fb43a}html.theme--documenter-dark .ansi span.sgr43{background-color:#f4c72f}html.theme--documenter-dark .ansi span.sgr44{background-color:#7587f0}html.theme--documenter-dark .ansi span.sgr45{background-color:#bc89d3}html.theme--documenter-dark .ansi span.sgr46{background-color:#49b6ca}html.theme--documenter-dark .ansi span.sgr47{background-color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr90{color:#92a0a2}html.theme--documenter-dark .ansi span.sgr91{color:#ff8674}html.theme--documenter-dark .ansi span.sgr92{color:#79d462}html.theme--documenter-dark .ansi span.sgr93{color:#ffe76b}html.theme--documenter-dark .ansi span.sgr94{color:#8a98ff}html.theme--documenter-dark .ansi span.sgr95{color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr96{color:#6bc8db}html.theme--documenter-dark .ansi span.sgr97{color:#ecf0f1}html.theme--documenter-dark .ansi span.sgr100{background-color:#92a0a2}html.theme--documenter-dark .ansi span.sgr101{background-color:#ff8674}html.theme--documenter-dark .ansi span.sgr102{background-color:#79d462}html.theme--documenter-dark .ansi span.sgr103{background-color:#ffe76b}html.theme--documenter-dark .ansi span.sgr104{background-color:#8a98ff}html.theme--documenter-dark .ansi span.sgr105{background-color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr106{background-color:#6bc8db}html.theme--documenter-dark .ansi span.sgr107{background-color:#ecf0f1}html.theme--documenter-dark code.language-julia-repl>span.hljs-meta{color:#4fb43a;font-weight:bolder}html.theme--documenter-dark .hljs{background:#2b2b2b;color:#f8f8f2}html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-quote{color:#d4d0ab}html.theme--documenter-dark .hljs-variable,html.theme--documenter-dark .hljs-template-variable,html.theme--documenter-dark .hljs-tag,html.theme--documenter-dark .hljs-name,html.theme--documenter-dark .hljs-selector-id,html.theme--documenter-dark .hljs-selector-class,html.theme--documenter-dark .hljs-regexp,html.theme--documenter-dark .hljs-deletion{color:#ffa07a}html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-link{color:#f5ab35}html.theme--documenter-dark .hljs-attribute{color:#ffd700}html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-addition{color:#abe338}html.theme--documenter-dark .hljs-title,html.theme--documenter-dark .hljs-section{color:#00e0e0}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{color:#dcc6e0}html.theme--documenter-dark .hljs-emphasis{font-style:italic}html.theme--documenter-dark .hljs-strong{font-weight:bold}@media screen and (-ms-high-contrast: active){html.theme--documenter-dark .hljs-addition,html.theme--documenter-dark .hljs-attribute,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-link,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-quote{color:highlight}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{font-weight:bold}}html.theme--documenter-dark .hljs-subst{color:#f8f8f2}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333 !important;background-color:#f1f5f9 !important}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:whitesmoke;background-color:#33415580;border-radius:0.6rem}html.theme--documenter-dark .search-result-title{color:whitesmoke}html.theme--documenter-dark .search-result-highlight{background-color:greenyellow;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f50}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem} diff --git a/dev/assets/themes/documenter-light.css b/dev/assets/themes/documenter-light.css index 60a317a4c..1262ec506 100644 --- a/dev/assets/themes/documenter-light.css +++ b/dev/assets/themes/documenter-light.css @@ -6,4 +6,4 @@ Website: https://highlightjs.org/ License: see project LICENSE Touched: 2021 -*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#F3F3F3;color:#444}.hljs-comment{color:#697070}.hljs-tag,.hljs-punctuation{color:#444a}.hljs-tag .hljs-name,.hljs-tag .hljs-attr{color:#444}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-operator,.hljs-selector-pseudo{color:#ab5656}.hljs-literal{color:#695}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} +*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#F3F3F3;color:#444}.hljs-comment{color:#697070}.hljs-tag,.hljs-punctuation{color:#444a}.hljs-tag .hljs-name,.hljs-tag .hljs-attr{color:#444}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-operator,.hljs-selector-pseudo{color:#ab5656}.hljs-literal{color:#695}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.gap-4{gap:1rem} diff --git a/dev/contributing/index.html b/dev/contributing/index.html index 4531a91f6..e15a0ea87 100644 --- a/dev/contributing/index.html +++ b/dev/contributing/index.html @@ -30,4 +30,4 @@ # s, squash = use commit, but meld into previous commit # # If you remove a line here THAT COMMIT WILL BE LOST. - # However, if you remove everything, the rebase will be aborted.

Then in the next screen that appears, we can just delete all messages that we do not want to show in the commit. After this is done and we are back to the console, we have to force push. We need to force push because we rewrote the local commit history.

$ git push -uf origin <name_of_local_branch>

You can find more information about squashing here.

Unit testing

Currently a number of checks are run per commit for a given PR.

Unit tests are run against every new commit for a given PR, the status of the unit-tests are not checked during the merge process but act as a sanity check for developers and reviewers. Depending on the content changed in the PR, some CI checks that are not necessary will be skipped. For example doc only changes do not require the unit tests to be run.

The merge process

We use bors to manage merging PR's in the the EnsembleKalmanProcesses repo. If you're a collaborator and have the necessary permissions, you can type bors try in a comment on a PR to have integration test suite run on that PR, or bors r+ to try and merge the code. Bors ensures that all integration tests for a given PR always pass before merging into main. The integration tests currently run example cases in examples/. Any breaking changes will need to also update the examples/, else bors will fail.

+ # However, if you remove everything, the rebase will be aborted.

Then in the next screen that appears, we can just delete all messages that we do not want to show in the commit. After this is done and we are back to the console, we have to force push. We need to force push because we rewrote the local commit history.

$ git push -uf origin <name_of_local_branch>

You can find more information about squashing here.

Unit testing

Currently a number of checks are run per commit for a given PR.

Unit tests are run against every new commit for a given PR, the status of the unit-tests are not checked during the merge process but act as a sanity check for developers and reviewers. Depending on the content changed in the PR, some CI checks that are not necessary will be skipped. For example doc only changes do not require the unit tests to be run.

The merge process

We use bors to manage merging PR's in the the EnsembleKalmanProcesses repo. If you're a collaborator and have the necessary permissions, you can type bors try in a comment on a PR to have integration test suite run on that PR, or bors r+ to try and merge the code. Bors ensures that all integration tests for a given PR always pass before merging into main. The integration tests currently run example cases in examples/. Any breaking changes will need to also update the examples/, else bors will fail.

diff --git a/dev/ensemble_kalman_inversion/index.html b/dev/ensemble_kalman_inversion/index.html index aac283889..04c12b573 100644 --- a/dev/ensemble_kalman_inversion/index.html +++ b/dev/ensemble_kalman_inversion/index.html @@ -28,4 +28,4 @@ y, obs_noise_cov, Inversion(), - failure_handler_method = SampleSuccGauss())
Forward model requirements when using FailureHandlers

The user must determine if a model run has "failed", and replace the output $\mathcal{G}(\theta)$ with NaN. The FailureHandler takes care of the rest.

A description of the algorithmic modification is included below.

SampleSuccGauss()

The SampleSuccGauss() modification is based on updating all ensemble members with a distribution given by only the successful parameter ensemble. Let $\Theta_{s,n}=[ \theta^{(1)}_{s,n},\dots,\theta^{(J_s)}_{s,n}]$ be the successful ensemble, for which each evaluation $\mathcal{G}(\theta^{(j)}_{s,n})$ does not fail, and let $\theta_{f,n}^{(k)}$ be the ensemble members for which the evaluation $\mathcal{G}(\theta^{(k)}_{f,n})$ fails. The successful ensemble $\Theta_{s,n}$ is updated to $\Theta_{s,n+1}$ using expression (2), and each failed ensemble member as

\[ \theta_{f,n+1}^{(k)} \sim \mathcal{N} \left({m}_{s, {n+1}}, \Sigma_{s, n+1} \right),\]

where

\[ {m}_{s, {n+1}} = \dfrac{1}{J_s}\sum_{j=1}^{J_s} \theta_{s,n+1}^{(j)}, \qquad \Sigma_{s, n+1} = \mathrm{Cov}(\theta_{s, n+1}, \theta_{s, n+1}) + \kappa_*^{-1}\mu_{s,1}I_p.\]

Here, $\kappa_*$ is a limiting condition number, $\mu_{s,1}$ is the largest eigenvalue of the sample covariance $\mathrm{Cov}(\theta_{s, n+1}, \theta_{s, n+1})$ and $I_p$ is the identity matrix of size $p\times p$.

Warning

This modification is not a magic bullet. If large fractions of ensemble members fail during an iteration, this will degenerate the span of the ensemble.

Sparsity-Inducing Ensemble Kalman Inversion

We include Sparsity-inducing Ensemble Kalman Inversion (SEKI) to add approximate $L^0$ and $L^1$ penalization to the EKI (Schneider, Stuart, Wu, 2020).

Warning

The algorithm suffers from robustness issues, and therefore we urge caution in using the tool

+ failure_handler_method = SampleSuccGauss())
Forward model requirements when using FailureHandlers

The user must determine if a model run has "failed", and replace the output $\mathcal{G}(\theta)$ with NaN. The FailureHandler takes care of the rest.

A description of the algorithmic modification is included below.

SampleSuccGauss()

The SampleSuccGauss() modification is based on updating all ensemble members with a distribution given by only the successful parameter ensemble. Let $\Theta_{s,n}=[ \theta^{(1)}_{s,n},\dots,\theta^{(J_s)}_{s,n}]$ be the successful ensemble, for which each evaluation $\mathcal{G}(\theta^{(j)}_{s,n})$ does not fail, and let $\theta_{f,n}^{(k)}$ be the ensemble members for which the evaluation $\mathcal{G}(\theta^{(k)}_{f,n})$ fails. The successful ensemble $\Theta_{s,n}$ is updated to $\Theta_{s,n+1}$ using expression (2), and each failed ensemble member as

\[ \theta_{f,n+1}^{(k)} \sim \mathcal{N} \left({m}_{s, {n+1}}, \Sigma_{s, n+1} \right),\]

where

\[ {m}_{s, {n+1}} = \dfrac{1}{J_s}\sum_{j=1}^{J_s} \theta_{s,n+1}^{(j)}, \qquad \Sigma_{s, n+1} = \mathrm{Cov}(\theta_{s, n+1}, \theta_{s, n+1}) + \kappa_*^{-1}\mu_{s,1}I_p.\]

Here, $\kappa_*$ is a limiting condition number, $\mu_{s,1}$ is the largest eigenvalue of the sample covariance $\mathrm{Cov}(\theta_{s, n+1}, \theta_{s, n+1})$ and $I_p$ is the identity matrix of size $p\times p$.

Warning

This modification is not a magic bullet. If large fractions of ensemble members fail during an iteration, this will degenerate the span of the ensemble.

Sparsity-Inducing Ensemble Kalman Inversion

We include Sparsity-inducing Ensemble Kalman Inversion (SEKI) to add approximate $L^0$ and $L^1$ penalization to the EKI (Schneider, Stuart, Wu, 2020).

Warning

The algorithm suffers from robustness issues, and therefore we urge caution in using the tool

diff --git a/dev/ensemble_kalman_sampler/index.html b/dev/ensemble_kalman_sampler/index.html index 343f655a3..a8ef6e7f9 100644 --- a/dev/ensemble_kalman_sampler/index.html +++ b/dev/ensemble_kalman_sampler/index.html @@ -34,4 +34,4 @@ Γ_post = get_u_cov_final(eksobj)

To obtain samples of this approximate posterior in the constrained space, we first sample the distribution, then transform using the constraints contained within the prior

using Random, Distributions
 
 ten_post_samples = rand(MvNormal(θ_post,Γ_post), 10)
-ten_post_samples_phys = transform_unconstrained_to_constrained(prior, ten_post_samples) # the optimal physical parameter value
+ten_post_samples_phys = transform_unconstrained_to_constrained(prior, ten_post_samples) # the optimal physical parameter value diff --git a/dev/examples/ClimateMachine_example/index.html b/dev/examples/ClimateMachine_example/index.html index 7222c13e1..31c678982 100644 --- a/dev/examples/ClimateMachine_example/index.html +++ b/dev/examples/ClimateMachine_example/index.html @@ -6,4 +6,4 @@ θ = load("ekp_clima.jld")["ekp_u"] println(typeof(θ)) # Array{Array{Float64,2},1}, outer dimension is N_iter, inner Array{Float64,2} of size = (J, p)

The optimal parameter vector determined by the ensemble Kalman inversion is the ensemble mean of the particles after the last iteration. Following the previous script,

using Statistics
 
-θ_opt = mean(θ[end], dims=1)
+θ_opt = mean(θ[end], dims=1) diff --git a/dev/examples/Cloudy_example/index.html b/dev/examples/Cloudy_example/index.html index 8f4829f3f..98ce74bee 100644 --- a/dev/examples/Cloudy_example/index.html +++ b/dev/examples/Cloudy_example/index.html @@ -13,4 +13,4 @@ end truth = Observations.Observation(y_t, Γy, data_names)

Solution and Output

Playing Around

If you want to play around with the Cloudy examples, you can e.g. change the type or the parameters of the initial cloud droplet mass distribution (see Cloudy.ParticleDistributions for the available distributions), by modifying these lines:

ϕ_true = [N0_true, θ_true, k_true]
-dist_true = ParticleDistributions.GammaPrimitiveParticleDistribution(ϕ_true...)

(Don't forget to also change dist_type accordingly).

You can also experiment with different noise covariances (Γy), priors, vary the number of iterations (N_iter) or ensemble particles (N_ens), etc.

+dist_true = ParticleDistributions.GammaPrimitiveParticleDistribution(ϕ_true...)

(Don't forget to also change dist_type accordingly).

You can also experiment with different noise covariances (Γy), priors, vary the number of iterations (N_iter) or ensemble particles (N_ens), etc.

diff --git a/dev/examples/darcy/index.html b/dev/examples/darcy/index.html index 85262b76b..99b2df4a2 100644 --- a/dev/examples/darcy/index.html +++ b/dev/examples/darcy/index.html @@ -36,4 +36,4 @@ params_i = get_ϕ_final(prior, ekiobj) g_ens = run_G_ensemble(darcy, params_i) EKP.update_ensemble!(ekiobj, g_ens) -end

Inversion results

We plot first the prior ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean.

Darcy prior

Now we plot the final ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean.

Darcy final

We can compare this with the true permeability and pressure field:

Darcy truth

+end

Inversion results

We plot first the prior ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean.

Darcy prior

Now we plot the final ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean.

Darcy final

We can compare this with the true permeability and pressure field:

Darcy truth

diff --git a/dev/examples/lorenz_example/index.html b/dev/examples/lorenz_example/index.html index 64e8753d9..99c02e9d4 100644 --- a/dev/examples/lorenz_example/index.html +++ b/dev/examples/lorenz_example/index.html @@ -15,4 +15,4 @@ println("True parameters: ") println(params_true) println("\nEKI results:") -println(get_ϕ_mean_final(priors, ekiobj))

Saved output

The parameters and forward model outputs will be saved in parameter_storage.jld2 and data_storage.jld2, respectively. The data will be saved in the directory output.

Plots

A scatter plot animation of the ensemble convergence to the true parameters is saved in the directory output.

+println(get_ϕ_mean_final(priors, ekiobj))

Saved output

The parameters and forward model outputs will be saved in parameter_storage.jld2 and data_storage.jld2, respectively. The data will be saved in the directory output.

Plots

A scatter plot animation of the ensemble convergence to the true parameters is saved in the directory output.

diff --git a/dev/examples/sinusoid_example_toml/index.html b/dev/examples/sinusoid_example_toml/index.html index ba405351f..c2c7ff3cb 100644 --- a/dev/examples/sinusoid_example_toml/index.html +++ b/dev/examples/sinusoid_example_toml/index.html @@ -42,4 +42,4 @@ 6.51158 6.31867 6.68542 6.12809 6.44726 6.52448

while the initial ensemble is retrieved with:

julia> get_ϕ(prior, eki, 1)
 2×6 Matrix{Float64}:
   1.05344   1.67949    6.29847  0.951586  2.07678    1.62284
- -7.00616  -0.931872  -6.11603  0.984338  0.274007  -1.39082
Why is it so slow?

The example is slow because the forward map is written in Julia, and so 99.99% of computation for each call to julia --project is precompilation. Ensembles in Julia can be accelerated by using methods discussed here, or by compiling system images with PackageCompiler.jl, for example. This example is for instructional purposes only, and so is not optimized.

+ -7.00616 -0.931872 -6.11603 0.984338 0.274007 -1.39082
Why is it so slow?

The example is slow because the forward map is written in Julia, and so 99.99% of computation for each call to julia --project is precompilation. Ensembles in Julia can be accelerated by using methods discussed here, or by compiling system images with PackageCompiler.jl, for example. This example is for instructional purposes only, and so is not optimized.

diff --git a/dev/examples/template_example/index.html b/dev/examples/template_example/index.html index ca05053b4..2f9f796da 100644 --- a/dev/examples/template_example/index.html +++ b/dev/examples/template_example/index.html @@ -1,2 +1,2 @@ -Template · EnsembleKalmanProcesses.jl

Template example

We provide the following template for how the tools may be applied.

For small examples typically have 2 files.

  • DynamicalModel.jl Contains the dynamical model $\Psi$ and the observation map $\mathcal{H}$. The inputs should be the so-called free parameters (in the constrained/physical space that is the input domain of the dynamical model) we are interested in learning, and the output should be the measured data.
  • The example script which contains the inverse problem setup and solve

The structure of the example script

Create the data and the setting for the model

  1. Set up the forward model.
  2. Construct/load the truth data.

Set up the inverse problem

  1. Define the prior distributions, and generate an initial ensemble.
  2. Initialize the process tool you would like to use (we recommend you begin with Inversion()).
  3. initialize the EnsembleKalmanProcess object

Solve the inverse problem, in a loop

  1. Obtain the current parameter ensemble
  2. Transform them from the unbounded computational space to the physical space
  3. call the forward model on the ensemble of parameters, producing an ensemble of measured data
  4. call the update_ensemble! function to generate a new parameter ensemble based on the new data

Get the solution

  1. Obtain the final parameter ensemble, compute desired statistics here.
  2. Transform the final ensemble into the physical space for use in prediction studies with the forward model.
+Template · EnsembleKalmanProcesses.jl

Template example

We provide the following template for how the tools may be applied.

For small examples typically have 2 files.

  • DynamicalModel.jl Contains the dynamical model $\Psi$ and the observation map $\mathcal{H}$. The inputs should be the so-called free parameters (in the constrained/physical space that is the input domain of the dynamical model) we are interested in learning, and the output should be the measured data.
  • The example script which contains the inverse problem setup and solve

The structure of the example script

Create the data and the setting for the model

  1. Set up the forward model.
  2. Construct/load the truth data.

Set up the inverse problem

  1. Define the prior distributions, and generate an initial ensemble.
  2. Initialize the process tool you would like to use (we recommend you begin with Inversion()).
  3. initialize the EnsembleKalmanProcess object

Solve the inverse problem, in a loop

  1. Obtain the current parameter ensemble
  2. Transform them from the unbounded computational space to the physical space
  3. call the forward model on the ensemble of parameters, producing an ensemble of measured data
  4. call the update_ensemble! function to generate a new parameter ensemble based on the new data

Get the solution

  1. Obtain the final parameter ensemble, compute desired statistics here.
  2. Transform the final ensemble into the physical space for use in prediction studies with the forward model.
diff --git a/dev/glossary/index.html b/dev/glossary/index.html index e837350fb..ae629d33d 100644 --- a/dev/glossary/index.html +++ b/dev/glossary/index.html @@ -1,2 +1,2 @@ -Glossary · EnsembleKalmanProcesses.jl

Glossary

The following list includes the names and symbols of recurring concepts in EnsembleKalmanProcesses.jl. Some of these variables do not appear in the codebase, which relies on array programming for performance. Contributions to the codebase require following this notational convention. Similarly, if you find inconsistencies in the documentation or codebase, please report an issue on GitHub.

NameSymbol (Theory/Docs)Symbol (Code)
Parameter vector, Parameters (unconstrained space)$\theta$, $u$, $\mathcal{T}(\phi)$θ,u
Parameter vector, Parameters (physical / constrained space)$\phi$, $\mathcal{T}^{-1}(\theta)$ϕ
Parameter vector size, Number of parameters$p$N_par
Ensemble size$J$N_ens
Ensemble particles, members$\theta^{(j)}$
Number of iterations$N_{\rm it}$N_iter
Observation vector, Observations, Data vector$y$y
Observation vector size, Data vector size$d$N_obs
Observational noise$\eta$obs_noise
Observational noise covariance$\Gamma_y$obs_noise_cov
Hilbert space inner product$\langle \phi , \Gamma^{-1} \psi \rangle$
Forward map$\mathcal{G}$G
Dynamical model$\Psi$Ψ
Transform map (constrained to unconstrained)$\mathcal{T}$T
Observation map$\mathcal{H}$H
Prior covariance (unconstrained space)$\Gamma_{\theta}$prior_cov
Prior mean (unconstrained space)$m_\theta$prior_mean
+Glossary · EnsembleKalmanProcesses.jl

Glossary

The following list includes the names and symbols of recurring concepts in EnsembleKalmanProcesses.jl. Some of these variables do not appear in the codebase, which relies on array programming for performance. Contributions to the codebase require following this notational convention. Similarly, if you find inconsistencies in the documentation or codebase, please report an issue on GitHub.

NameSymbol (Theory/Docs)Symbol (Code)
Parameter vector, Parameters (unconstrained space)$\theta$, $u$, $\mathcal{T}(\phi)$θ,u
Parameter vector, Parameters (physical / constrained space)$\phi$, $\mathcal{T}^{-1}(\theta)$ϕ
Parameter vector size, Number of parameters$p$N_par
Ensemble size$J$N_ens
Ensemble particles, members$\theta^{(j)}$
Number of iterations$N_{\rm it}$N_iter
Observation vector, Observations, Data vector$y$y
Observation vector size, Data vector size$d$N_obs
Observational noise$\eta$obs_noise
Observational noise covariance$\Gamma_y$obs_noise_cov
Hilbert space inner product$\langle \phi , \Gamma^{-1} \psi \rangle$
Forward map$\mathcal{G}$G
Dynamical model$\Psi$Ψ
Transform map (constrained to unconstrained)$\mathcal{T}$T
Observation map$\mathcal{H}$H
Prior covariance (unconstrained space)$\Gamma_{\theta}$prior_cov
Prior mean (unconstrained space)$m_\theta$prior_mean
diff --git a/dev/index.html b/dev/index.html index 3e43ea896..d649f4bf1 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · EnsembleKalmanProcesses.jl

EnsembleKalmanProcesses

EnsembleKalmanProcesses.jl (EKP) is a library of derivative-free Bayesian optimization techniques based on ensemble Kalman Filters, a well known family of approximate filters used for data assimilation. The tools in this library enable fitting parameters found in expensive black-box computer codes without the need for adjoints or derivatives. This property makes them particularly useful when calibrating non-deterministic models, or when the training data are noisy.

Currently, the following methods are implemented in the library:

  • Ensemble Kalman Inversion (EKI) - The traditional optimization technique based on the Ensemble Kalman Filter EnKF (Iglesias, Law, Stuart, 2013),
  • Ensemble Kalman Sampler (EKS) - also obtains a Gaussian Approximation of the posterior distribution, through a Monte Carlo integration (Garbuno-Inigo, Hoffmann, Li, Stuart, 2020),
  • Unscented Kalman Inversion (UKI) - also obtains a Gaussian Approximation of the posterior distribution, through a quadrature based integration approach (Huang, Schneider, Stuart, 2022),
  • Sparsity-inducing Ensemble Kalman Inversion (SEKI) - Additionally adds approximate $L^0$ and $L^1$ penalization to the EKI (Schneider, Stuart, Wu, 2020).
ModulePurpose
EnsembleKalmanProcesses.jlCollection of all tools
EnsembleKalmanProcess.jlImplementations of EKI, EKS, UKI, and SEKI
Observations.jlStructure to hold observational data
ParameterDistributions.jlStructures to hold prior and posterior distributions
DataContainers.jlStructure to hold model parameters and outputs
Localizers.jlCovariance localization kernels

Learning the amplitude and vertical shift of a sine curve

Ensemble of parameter estimates by iteration

See full example for the code.

Authors

EnsembleKalmanProcesses.jl is being developed by the Climate Modeling Alliance. The main developers are Oliver R. A. Dunbar and Ignacio Lopez-Gomez.

+Home · EnsembleKalmanProcesses.jl

EnsembleKalmanProcesses

EnsembleKalmanProcesses.jl (EKP) is a library of derivative-free Bayesian optimization techniques based on ensemble Kalman Filters, a well known family of approximate filters used for data assimilation. The tools in this library enable fitting parameters found in expensive black-box computer codes without the need for adjoints or derivatives. This property makes them particularly useful when calibrating non-deterministic models, or when the training data are noisy.

Currently, the following methods are implemented in the library:

  • Ensemble Kalman Inversion (EKI) - The traditional optimization technique based on the Ensemble Kalman Filter EnKF (Iglesias, Law, Stuart, 2013),
  • Ensemble Kalman Sampler (EKS) - also obtains a Gaussian Approximation of the posterior distribution, through a Monte Carlo integration (Garbuno-Inigo, Hoffmann, Li, Stuart, 2020),
  • Unscented Kalman Inversion (UKI) - also obtains a Gaussian Approximation of the posterior distribution, through a quadrature based integration approach (Huang, Schneider, Stuart, 2022),
  • Sparsity-inducing Ensemble Kalman Inversion (SEKI) - Additionally adds approximate $L^0$ and $L^1$ penalization to the EKI (Schneider, Stuart, Wu, 2020).
ModulePurpose
EnsembleKalmanProcesses.jlCollection of all tools
EnsembleKalmanProcess.jlImplementations of EKI, EKS, UKI, and SEKI
Observations.jlStructure to hold observational data
ParameterDistributions.jlStructures to hold prior and posterior distributions
DataContainers.jlStructure to hold model parameters and outputs
Localizers.jlCovariance localization kernels

Learning the amplitude and vertical shift of a sine curve

Ensemble of parameter estimates by iteration

See full example for the code.

Authors

EnsembleKalmanProcesses.jl is being developed by the Climate Modeling Alliance. The main developers are Oliver R. A. Dunbar and Ignacio Lopez-Gomez.

diff --git a/dev/inflation/index.html b/dev/inflation/index.html index c1044667e..7be59f995 100644 --- a/dev/inflation/index.html +++ b/dev/inflation/index.html @@ -2,4 +2,4 @@ Inflation · EnsembleKalmanProcesses.jl

Inflation

Inflation is an approach that slows down collapse in ensemble Kalman methods. Two distinct forms of inflation are implemented in this package. Both involve perturbing the ensemble members following the standard update rule of the chosen Kalman process. Multiplicative inflation expands ensemble members away from their mean in a deterministic manner, whereas additive inflation hinges on the addition of stochastic noise to ensemble members.

For both implementations, a scaling factor $s$ is included to extend functionality to cases with mini-batching. The scaling factor $s$ multiplies the artificial time step $\Delta t$ in the inflation equations to account for sampling error. For mini-batching, the scaling factor should be:

\[ s = \frac{|B|}{|C|}\]

where $|B|$ is the mini-batch size and $|C|$ is the full dataset size.

Multiplicative Inflation

Multiplicative inflation effectively scales parameter vectors in parameter space, such that the perturbed ensemble remains in the linear span of the original ensemble. The implemented update equation follows Huang et al, 2022 eqn. 41:

\[\begin{aligned} m_{n+1} = m_{n} ; \qquad u^{j}_{n + 1} = m_{n+1} + \sqrt{\frac{1}{1 - s \Delta{t}}} \left(u^{j}_{n} - m_{n} \right) \qquad (1) \end{aligned}\]

where $m$ is the ensemble average. In this way, the parameter covariance is inflated by a factor of $\frac{1}{1 - s \Delta{t}}$, while the ensemble mean remains fixed.

\[ C_{n + 1} = \frac{1}{1 - s \Delta{t}} C_{n} \qquad (2)\]

Multiplicative inflation can be used by flagging the update_ensemble! method as follows:

    EKP.update_ensemble!(ekiobj, g_ens; multiplicative_inflation = true, s = 1.0)

Additive Inflation

Additive inflation is implemented by systematically adding stochastic perturbations to the parameter ensemble in the form of Gaussian noise. Additive inflation breaks the linear subspace property, meaning the parameter ensemble can evolve outside of the span of the initial ensemble. In additive inflation, the ensemble is perturbed in the following manner after the standard Kalman update:

\[ u_{n+1} = u_n + \zeta_{n} \qquad (3) \\ - \zeta_{n} \sim N(0, \frac{s \Delta{t} }{1 - s \Delta{t}} C_n) \qquad (4)\]

This inflates the parameter covariance by a factor of $\frac{1}{1 - s \Delta{t}}$ as in eqn. 2 , while the ensemble mean remains fixed.

Additive inflation can be used by flagging the update_ensemble! method as follows:

    EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, s = 1.0)

Alternatively, the prior covariance matrix may be used to generate additive noise, following:

\[ \zeta_{n} \sim N(0, \frac{s \Delta{t} }{1 - s \Delta{t}} C_{0}) \qquad (5)\]

This results in an additive increase in the parameter covariance by $\frac{s \Delta{t} }{1 - s \Delta{t}} * C_{0}$ , while the mean remains fixed.

\[ C_{n + 1} = C_{n} + \frac{s \Delta{t} }{1 - s \Delta{t}} C_{0} \qquad (6)\]

Additive inflation using the scaled prior covariance (parameter covariance of initial ensemble) can be used by flagging the update_ensemble! method as follows:

    EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, use_prior_cov = true, s = 1.0)
+ \zeta_{n} \sim N(0, \frac{s \Delta{t} }{1 - s \Delta{t}} C_n) \qquad (4)\]

This inflates the parameter covariance by a factor of $\frac{1}{1 - s \Delta{t}}$ as in eqn. 2 , while the ensemble mean remains fixed.

Additive inflation can be used by flagging the update_ensemble! method as follows:

    EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, s = 1.0)

Alternatively, the prior covariance matrix may be used to generate additive noise, following:

\[ \zeta_{n} \sim N(0, \frac{s \Delta{t} }{1 - s \Delta{t}} C_{0}) \qquad (5)\]

This results in an additive increase in the parameter covariance by $\frac{s \Delta{t} }{1 - s \Delta{t}} * C_{0}$ , while the mean remains fixed.

\[ C_{n + 1} = C_{n} + \frac{s \Delta{t} }{1 - s \Delta{t}} C_{0} \qquad (6)\]

Additive inflation using the scaled prior covariance (parameter covariance of initial ensemble) can be used by flagging the update_ensemble! method as follows:

    EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, use_prior_cov = true, s = 1.0)
diff --git a/dev/installation_instructions/index.html b/dev/installation_instructions/index.html index 6e7efd738..bef61ac78 100644 --- a/dev/installation_instructions/index.html +++ b/dev/installation_instructions/index.html @@ -15,4 +15,4 @@ > julia> ] > (example-name)> rm EnsembleKalmanProcesses.jl > (example-name)> dev ../.. -> (example-name)> instantiate

followed by

> julia --project example-file-name.jl
+> (example-name)> instantiate

followed by

> julia --project example-file-name.jl
diff --git a/dev/internal_data_representation/index.html b/dev/internal_data_representation/index.html index e22739fc4..3ad6806fe 100644 --- a/dev/internal_data_representation/index.html +++ b/dev/internal_data_representation/index.html @@ -2,4 +2,4 @@ Internal data representation · EnsembleKalmanProcesses.jl

Wrapping up data

To provide a consistent form for data (such as observations, parameter ensembles, model evaluations) across the package, we store the data in simple wrappers internally.

Data is always stored as columns of AbstractMatrix. That is, we obey the format

[ data dimension x number of data samples ]

The DataContainer

A DataContainer is constructed initially by copying and perhaps transposing matrix data

dc = DataContainer(abstract_matrix; data_are_columns = true)

The flag data_are_columns indicates whether the provided data is stored column- or row-wise. The data is retrieved with

get_data(dc)

The PairedDataContainer

A PairedDataContainer stores pairs of inputs and outputs in the form of DataContainers. It is constructed from two data matrices, or from two DataContainers.

pdc = PairedDataContainer(input_matrix, output_matrix; data_are_columns = true)
 pdc = PairedDataContainer(input_data_container, output_data_container)

Data is retrieved with

get_data(pdc) # returns both inputs and outputs
 get_inputs(pdc)
-get_outputs(pdc)
+get_outputs(pdc) diff --git a/dev/learning_rate_scheduler/index.html b/dev/learning_rate_scheduler/index.html index 268b857b5..5ae27fe52 100644 --- a/dev/learning_rate_scheduler/index.html +++ b/dev/learning_rate_scheduler/index.html @@ -15,4 +15,4 @@ if !isnothing(terminated) # if termination is flagged, break the loop break end -end

Timestep and termination time

Recall, for example for EKI, we perform updates of our ensemble of parameters $j=1,\dots,J$ at step $n = 1,\dots,N_\mathrm{it}$ using

$\theta_{n+1}^{(j)} = \theta_{n}^{(j)} - \dfrac{\Delta t_n}{J}\sum_{k=1}^J \left \langle \mathcal{G}(\theta_n^{(k)}) - \bar{\mathcal{G}}_n \, , \, \Gamma_y^{-1} \left ( \mathcal{G}(\theta_n^{(j)}) - y \right ) \right \rangle \theta_{n}^{(k)},$

where $\bar{\mathcal{G}}_n$ is the mean value of $\mathcal{G}(\theta_n)$ across ensemble members. We denote the current time $t_n = \sum_{i=1}^n\Delta t_i$, and the termination time as $T = t_{N_\mathrm{it}}$.

Note

Adaptive Schedulers typically try to make the biggest update that controls some measure of this update. For example, EKSStableScheduler() controls the frobenius norm of the update, while DataMisfitController() controls the Jeffrey divergence between the two steps. Largely they follow a pattern of scheduling very small initial timesteps, leading to much larger steps at later times.

There are two termination times that the theory indicates are useful

The experiment with EKI & UKI

We assess the schedulers by solving the inverse problem with EKI and UKI (we average results over 100 initial ensembles in the case of EKI). We will not draw comparisons between EKI and UKI here, rather we use them to observe consistent behavior in the schedulers. Shown below are the solution plots of one solve with each timestepper, for both methods.

Solution EKI Solution UKI

Top: EKI, Bottom: UKI. Left: The true model over $[0,2\pi]$ (black), and solution schedulers (colors). Right: The noisy observation (black) of mean and max of the model; the distribution it was sampled from (gray-ribbon), and the corresponding ensemble-mean approximation given from each scheduler (colors).

To assess the timestepping we show the convergence plot against the algorithm iteration we measure two quantities.

Error vs spread EKI Error vs spread UKI

Top: EKI. Bottom: UKI. Left: the error and spread of the different timesteppers at over iterations of the algorithm for a single run. Right: the error and spread of the different timesteppers at their final iterations, (for EKI, averaged from 100 initial conditions).

Finding the Posterior (terminating at $T=1$):

Optimizing the objective function (continuing $T \to \infty$):

DMC as a default in future?

This experiment motivates the possibility of making DMC (with/without) continuation a default timestepper in future releases, for EKI/SEKI/UKI. Currently we will retain constant timestepping as default while we investigate further.

Ensemble Kalman Sampler

We observe blow-up in EKS, when not using the EKSStableScheduler.

+end

Timestep and termination time

Recall, for example for EKI, we perform updates of our ensemble of parameters $j=1,\dots,J$ at step $n = 1,\dots,N_\mathrm{it}$ using

$\theta_{n+1}^{(j)} = \theta_{n}^{(j)} - \dfrac{\Delta t_n}{J}\sum_{k=1}^J \left \langle \mathcal{G}(\theta_n^{(k)}) - \bar{\mathcal{G}}_n \, , \, \Gamma_y^{-1} \left ( \mathcal{G}(\theta_n^{(j)}) - y \right ) \right \rangle \theta_{n}^{(k)},$

where $\bar{\mathcal{G}}_n$ is the mean value of $\mathcal{G}(\theta_n)$ across ensemble members. We denote the current time $t_n = \sum_{i=1}^n\Delta t_i$, and the termination time as $T = t_{N_\mathrm{it}}$.

Note

Adaptive Schedulers typically try to make the biggest update that controls some measure of this update. For example, EKSStableScheduler() controls the frobenius norm of the update, while DataMisfitController() controls the Jeffrey divergence between the two steps. Largely they follow a pattern of scheduling very small initial timesteps, leading to much larger steps at later times.

There are two termination times that the theory indicates are useful

The experiment with EKI & UKI

We assess the schedulers by solving the inverse problem with EKI and UKI (we average results over 100 initial ensembles in the case of EKI). We will not draw comparisons between EKI and UKI here, rather we use them to observe consistent behavior in the schedulers. Shown below are the solution plots of one solve with each timestepper, for both methods.

Solution EKI Solution UKI

Top: EKI, Bottom: UKI. Left: The true model over $[0,2\pi]$ (black), and solution schedulers (colors). Right: The noisy observation (black) of mean and max of the model; the distribution it was sampled from (gray-ribbon), and the corresponding ensemble-mean approximation given from each scheduler (colors).

To assess the timestepping we show the convergence plot against the algorithm iteration we measure two quantities.

Error vs spread EKI Error vs spread UKI

Top: EKI. Bottom: UKI. Left: the error and spread of the different timesteppers at over iterations of the algorithm for a single run. Right: the error and spread of the different timesteppers at their final iterations, (for EKI, averaged from 100 initial conditions).

Finding the Posterior (terminating at $T=1$):

Optimizing the objective function (continuing $T \to \infty$):

DMC as a default in future?

This experiment motivates the possibility of making DMC (with/without) continuation a default timestepper in future releases, for EKI/SEKI/UKI. Currently we will retain constant timestepping as default while we investigate further.

Ensemble Kalman Sampler

We observe blow-up in EKS, when not using the EKSStableScheduler.

diff --git a/dev/literated/aerosol_activation/index.html b/dev/literated/aerosol_activation/index.html index fefdd477e..2ff70fec0 100644 --- a/dev/literated/aerosol_activation/index.html +++ b/dev/literated/aerosol_activation/index.html @@ -141,4 +141,4 @@ println("Molar mass [kg/mol]: ", molar_mass_ekp, " vs ", molar_mass_true) println("Osmotic coefficient [-]: ", osmotic_coeff_ekp, " vs ", osmotic_coeff_true)
Molar mass [kg/mol]: 0.094398 vs 0.058443
-Osmotic coefficient [-]: 1.127754 vs 0.9

This page was generated using Literate.jl.

+Osmotic coefficient [-]: 1.127754 vs 0.9

This page was generated using Literate.jl.

diff --git a/dev/literated/loss_minimization/index.html b/dev/literated/loss_minimization/index.html index 1cd405b2f..7a4c84ffd 100644 --- a/dev/literated/loss_minimization/index.html +++ b/dev/literated/loss_minimization/index.html @@ -108,4 +108,4 @@ label = "particles", title = "EKI iteration = " * string(i), ) -end

Our bias in the prior shifts the initial ensemble into the negative $u_1$ direction, and thus increases the likelihood (over different instances of the random number generator) of finding the minimizer $u=w_*$.

Example block output

This page was generated using Literate.jl.

+end

Our bias in the prior shifts the initial ensemble into the negative $u_1$ direction, and thus increases the likelihood (over different instances of the random number generator) of finding the minimizer $u=w_*$.

Example block output

This page was generated using Literate.jl.

diff --git a/dev/literated/loss_minimization_sparse_eki/5b4a33d8.gif b/dev/literated/loss_minimization_sparse_eki/5b4a33d8.gif deleted file mode 100644 index 8332fe5e0..000000000 Binary files a/dev/literated/loss_minimization_sparse_eki/5b4a33d8.gif and /dev/null differ diff --git a/dev/literated/loss_minimization_sparse_eki/a91ceda5.gif b/dev/literated/loss_minimization_sparse_eki/a91ceda5.gif new file mode 100644 index 000000000..55113474c Binary files /dev/null and b/dev/literated/loss_minimization_sparse_eki/a91ceda5.gif differ diff --git a/dev/literated/loss_minimization_sparse_eki/index.html b/dev/literated/loss_minimization_sparse_eki/index.html index 8a04b16a1..7d9a4f349 100644 --- a/dev/literated/loss_minimization_sparse_eki/index.html +++ b/dev/literated/loss_minimization_sparse_eki/index.html @@ -53,4 +53,4 @@ label = "particles", title = "EKI iteration = " * string(i), ) -end

The results show that the minimizer of $G_1$ is $u=u_*$.

Example block output

This page was generated using Literate.jl.

+end

The results show that the minimizer of $G_1$ is $u=u_*$.

Example block output

This page was generated using Literate.jl.

diff --git a/dev/literated/molar_mass_average.pdf b/dev/literated/molar_mass_average.pdf index 4b4e74e86..feac5feba 100644 Binary files a/dev/literated/molar_mass_average.pdf and b/dev/literated/molar_mass_average.pdf differ diff --git a/dev/literated/molar_mass_scatter.pdf b/dev/literated/molar_mass_scatter.pdf index 8da8e78cd..1b3f80019 100644 Binary files a/dev/literated/molar_mass_scatter.pdf and b/dev/literated/molar_mass_scatter.pdf differ diff --git a/dev/literated/osmotic_coeff_average.pdf b/dev/literated/osmotic_coeff_average.pdf index 263eefd81..255c15f15 100644 Binary files a/dev/literated/osmotic_coeff_average.pdf and b/dev/literated/osmotic_coeff_average.pdf differ diff --git a/dev/literated/osmotic_coeff_scatter.pdf b/dev/literated/osmotic_coeff_scatter.pdf index 29f11cc38..7bb7fa1d1 100644 Binary files a/dev/literated/osmotic_coeff_scatter.pdf and b/dev/literated/osmotic_coeff_scatter.pdf differ diff --git a/dev/literated/sinusoid_example/0057c645.svg b/dev/literated/sinusoid_example/ea2277f3.svg similarity index 95% rename from dev/literated/sinusoid_example/0057c645.svg rename to dev/literated/sinusoid_example/ea2277f3.svg index 453797a7d..cb8495898 100644 --- a/dev/literated/sinusoid_example/0057c645.svg +++ b/dev/literated/sinusoid_example/ea2277f3.svg @@ -1,62 +1,62 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/literated/sinusoid_example/index.html b/dev/literated/sinusoid_example/index.html index 6a368d73c..474660152 100644 --- a/dev/literated/sinusoid_example/index.html +++ b/dev/literated/sinusoid_example/index.html @@ -49,4 +49,4 @@ ) plot!(trange, [model(final_ensemble[:, i]...) for i in 1:N_ensemble], c = :blue, label = ["Final ensemble" "" "" "" ""]) -xlabel!("Time")Example block output

We see that the final ensemble is much closer to the truth. Note that the random phase shift is of no consequence.


This page was generated using Literate.jl.

+xlabel!("Time")Example block output

We see that the final ensemble is much closer to the truth. Note that the random phase shift is of no consequence.


This page was generated using Literate.jl.

diff --git a/dev/literated/unique_minimum_sparse.gif b/dev/literated/unique_minimum_sparse.gif index 8332fe5e0..55113474c 100644 Binary files a/dev/literated/unique_minimum_sparse.gif and b/dev/literated/unique_minimum_sparse.gif differ diff --git a/dev/localization/index.html b/dev/localization/index.html index c703f1f27..0dedbadf4 100644 --- a/dev/localization/index.html +++ b/dev/localization/index.html @@ -30,4 +30,4 @@ locs = [Delta(), RBF(1.0), RBF(0.1), BernoulliDropout(0.1), SEC(10.0), SECFisher(), SEC(1.0, 0.1)] for loc in locs ekiobj = EKP.EnsembleKalmanProcess(initial_ensemble, y, Γ, Inversion(); localization_method = loc) -end +end diff --git a/dev/observations/index.html b/dev/observations/index.html index a48a4d912..d55db1687 100644 --- a/dev/observations/index.html +++ b/dev/observations/index.html @@ -5,4 +5,4 @@ yt = rand(MvNormal(μ, Γy), 100) # generate 100 samples name = "zero-mean mvnormal" -true_data = Observations.Observation(yt, Γy, name)

Currently, the data is retrieved by accessing the stored variables, e.g the fifth data sample is given by truth_data.samples[5], or the covariance matrix by truth_data.cov.

+true_data = Observations.Observation(yt, Γy, name)

Currently, the data is retrieved by accessing the stored variables, e.g the fifth data sample is given by truth_data.samples[5], or the covariance matrix by truth_data.cov.

diff --git a/dev/parallel_hpc/index.html b/dev/parallel_hpc/index.html index 84e541538..38ee8d27f 100644 --- a/dev/parallel_hpc/index.html +++ b/dev/parallel_hpc/index.html @@ -40,4 +40,4 @@ id_ens_array=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_ek_upd --array=1-$n ekp_single_cm_run.sbatch $it) fi id_ek_upd=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_ens_array --export=n=$n ekp_cont_calibration.sbatch $it) -done

Here a dependency tree is set up in SLURM, which iterates calls to the scripts ekp_single_cm_run.sbatch (which runs the forward model on HPC) and ekp_cont_calibration.sbatch (which performs an EKI update). We find this a smooth workflow that uses HPC resources well, and can likely be set up on other workload managers.

For more details see the code and docs for the HPC interfacing example: ClimateMachine.

+done

Here a dependency tree is set up in SLURM, which iterates calls to the scripts ekp_single_cm_run.sbatch (which runs the forward model on HPC) and ekp_cont_calibration.sbatch (which performs an EKI update). We find this a smooth workflow that uses HPC resources well, and can likely be set up on other workload managers.

For more details see the code and docs for the HPC interfacing example: ClimateMachine.

diff --git a/dev/parameter_distributions/e00eed92.svg b/dev/parameter_distributions/3f1495a1.svg similarity index 87% rename from dev/parameter_distributions/e00eed92.svg rename to dev/parameter_distributions/3f1495a1.svg index 0dbefe2a2..b294053e7 100644 --- a/dev/parameter_distributions/e00eed92.svg +++ b/dev/parameter_distributions/3f1495a1.svg @@ -1,46 +1,46 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/4728b2d3.svg b/dev/parameter_distributions/4728b2d3.svg deleted file mode 100644 index 1b2b254aa..000000000 --- a/dev/parameter_distributions/4728b2d3.svg +++ /dev/null @@ -1,456 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dev/parameter_distributions/0e395567.svg b/dev/parameter_distributions/5b0dff11.svg similarity index 76% rename from dev/parameter_distributions/0e395567.svg rename to dev/parameter_distributions/5b0dff11.svg index cb1af2254..8be0624a1 100644 --- a/dev/parameter_distributions/0e395567.svg +++ b/dev/parameter_distributions/5b0dff11.svg @@ -1,177 +1,177 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/21b59015.svg b/dev/parameter_distributions/5c4a7649.svg similarity index 86% rename from dev/parameter_distributions/21b59015.svg rename to dev/parameter_distributions/5c4a7649.svg index 02833a631..2e6c4fb5f 100644 --- a/dev/parameter_distributions/21b59015.svg +++ b/dev/parameter_distributions/5c4a7649.svg @@ -1,76 +1,76 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/88364d24.svg b/dev/parameter_distributions/6acae1f9.svg similarity index 74% rename from dev/parameter_distributions/88364d24.svg rename to dev/parameter_distributions/6acae1f9.svg index e51902470..a9782022c 100644 --- a/dev/parameter_distributions/88364d24.svg +++ b/dev/parameter_distributions/6acae1f9.svg @@ -1,587 +1,587 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/7d4dcd1a.svg b/dev/parameter_distributions/7d4dcd1a.svg new file mode 100644 index 000000000..16bc10caf --- /dev/null +++ b/dev/parameter_distributions/7d4dcd1a.svg @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/d06de111.svg b/dev/parameter_distributions/b0fb2a17.svg similarity index 75% rename from dev/parameter_distributions/d06de111.svg rename to dev/parameter_distributions/b0fb2a17.svg index a4d4d25b5..0de9576a9 100644 --- a/dev/parameter_distributions/d06de111.svg +++ b/dev/parameter_distributions/b0fb2a17.svg @@ -1,641 +1,641 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/cad080a0.svg b/dev/parameter_distributions/bb729ff2.svg similarity index 78% rename from dev/parameter_distributions/cad080a0.svg rename to dev/parameter_distributions/bb729ff2.svg index 0824a0c33..e97f4aa91 100644 --- a/dev/parameter_distributions/cad080a0.svg +++ b/dev/parameter_distributions/bb729ff2.svg @@ -1,996 +1,996 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/a44be935.svg b/dev/parameter_distributions/e6b23754.svg similarity index 77% rename from dev/parameter_distributions/a44be935.svg rename to dev/parameter_distributions/e6b23754.svg index 6708efa41..d007d394f 100644 --- a/dev/parameter_distributions/a44be935.svg +++ b/dev/parameter_distributions/e6b23754.svg @@ -1,140 +1,140 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/c1e755a6.svg b/dev/parameter_distributions/f5c81162.svg similarity index 77% rename from dev/parameter_distributions/c1e755a6.svg rename to dev/parameter_distributions/f5c81162.svg index c126be564..9be783235 100644 --- a/dev/parameter_distributions/c1e755a6.svg +++ b/dev/parameter_distributions/f5c81162.svg @@ -1,1203 +1,1203 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/parameter_distributions/index.html b/dev/parameter_distributions/index.html index e39792950..acf26f0d0 100644 --- a/dev/parameter_distributions/index.html +++ b/dev/parameter_distributions/index.html @@ -11,9 +11,9 @@ # μ_2 = 0.5, σ_2 = 0.25 using Plots -plot(prior)Example block output

One can also access the underlying Gaussian distributions in the unconstrained space with

using Plots
-plot(prior, constrained=false)
Example block output

Task: We wish to create a prior for a one-dimensional parameter. Our problem dictates that this parameter is bounded between 0 and 1; domain knowledge leads us to expect it should be around 0.7. The parameter is called point_seven.

We're told that the prior mean is 0.7; we choose a prior standard deviation of 0.15 to be sufficiently wide without putting too much mass at the upper bound. The constructor is then

using EnsembleKalmanProcesses.ParameterDistributions # for `constrained_gaussian`
-prior = constrained_gaussian("point_seven", 0.7, 0.15, 0.0, 1.0)

The pdf of the constructed prior distribution (in the physical, constrained space) looks like:

Example block output

In Simple example revisited below, we repeat this example "manually" with the general constructor.

What if I want to impose the same prior on many parameters?

The recommended constructor can be called as constrained_gaussian(...; repeats = n) to return a combined prior formed by n identical priors.

ParameterDistribution struct

This section provides more details on the components of a ParameterDistribution object.

ParameterDistributionType

The ParameterDistributionType struct wraps four types for specifying different types of prior distributions:

  • The Parameterized type is initialized using a Julia Distributions.jl object. Samples are drawn randomly from the distribution object.

  • The VectorOfParameterized type is initialized with a vector of distributions.

  • The Samples type is initialized using a two dimensional array. Samples are drawn randomly (with replacement) from the columns of the provided array.

  • The FunctionParameterDistributionType struct defines parameters specified as fields over a domain. More detail can be found here.

Warning

We recommend that the distributions be unbounded (see next section), as the filtering algorithms in EnsembleKalmanProcesses are not guaranteed to preserve constraints unless defined through the ConstraintType mechanism.

ConstraintType

The inference algorithms implemented in EnsembleKalmanProcesses assume unbounded parameter domains. To be able to handle constrained parameter values consistently, the ConstraintType defines a bijection between the physical, constrained parameter domain and an unphysical, unconstrained domain in which the filtering takes place. This bijection is specified by the functions transform_constrained_to_unconstrained and transform_unconstrained_to_constrained, which are built from either predefined constructors or user-defined constraint functions given as arguments to the ConstraintType constructor.

We provide the following predefined constructors which implement mappings that handle the most common constraints:

  • no_constraint(): The parameter is unconstrained and takes values in (-∞, ∞) (mapping is the identity).
  • bounded_below(lower_bound): The parameter takes values in [lower_bound, ∞).
  • bounded_above(upper_bound): The parameter takes values in (-∞, upper_bound].
  • bounded(lower_bound,upper_bound): The parameter takes values on the interval [lower_bound, upper_bound].

These are demonstrated in ConstraintType Examples.

Currently we only support multivariate constraints which are the Cartesian product of the one-dimensional ConstraintTypes. Every component of a multidimensional parameter must have an associated constraint, so, e.g. for a multivariate ParameterDistributionType of dimension p the user must provide a p-dimensional Array{ConstraintType}. A VectorOfParameterized distribution built with distributions of dimension p and q has dimension p+q.

Note

When a nontrivial ConstraintType is given, the general constructor assumes the ParameterDistributionType is specified in the unconstrained space; the actual prior pdf is then the composition of the ParameterDistributionType's pdf with the transform_unconstrained_to_constrained transformation. We provide constrained_gaussian to define priors directly in the physical, constrained space.

Warning

It is up to the user to ensure any custom mappings transform_constrained_to_unconstrained and transform_unconstrained_to_constrained are inverses of each other.

The name

This is simply a String used to identify different parameters in multi-parameter situations, as in the methods below.

FunctionParameterDistributionType

Learning a function distribution is useful when one wishes to obtain a parametric representation of a function that is (relatively) agnostic of the underlying grid discretization. Most practical implementations involve posing a restrictive class of functions by truncation of a spectral decomposition. The function is then represented as a set of coefficients of these modes (known as degrees of freedom), rather than directly through the values at evaluation points.

As a subtype of ParameterDistributionType, we currently support one option for specifying prior distributions over functions:

  • The GaussianRandomFieldInterface type is initialized with a Gaussian Random Field object and the GRF package. Currently we support objects from GaussianRandomFields.jl with package GRFJL(). Gaussian random fields allow the definition of scalar function distributions defined over a uniform mesh on interval, rectangular, and hyper-rectangular domains.

As with other ParameterDistributions, a function distribution, is built from a name, a FunctionPameterDistributionType struct and a constraint, here only one, placed on the scalar output space of the function using a Constraint().

constraints

The transformation transform_unconstrained_to_constrained, will map from (unconstrained) degrees of freedom, to (constrained) evaluations of the function on a numerical grid. In particular, the transform_constrained_to_unconstrained is no longer the inverse of this map, it now simply maps from constrained evaluations to unconstrained evaluations on the grid.

We provide an example construction here.

ParameterDistribution constructor

The Recommended constructor, constrained_gaussian(), is described above. For more general cases in which the prior needs to be specified in more detail, a ParameterDistribution may be constructed "manually" from its component objects:

using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`, `combine_distributions`
+plot(prior)
Example block output

One can also access the underlying Gaussian distributions in the unconstrained space with

using Plots
+plot(prior, constrained=false)
Example block output

Task: We wish to create a prior for a one-dimensional parameter. Our problem dictates that this parameter is bounded between 0 and 1; domain knowledge leads us to expect it should be around 0.7. The parameter is called point_seven.

We're told that the prior mean is 0.7; we choose a prior standard deviation of 0.15 to be sufficiently wide without putting too much mass at the upper bound. The constructor is then

using EnsembleKalmanProcesses.ParameterDistributions # for `constrained_gaussian`
+prior = constrained_gaussian("point_seven", 0.7, 0.15, 0.0, 1.0)

The pdf of the constructed prior distribution (in the physical, constrained space) looks like:

Example block output

In Simple example revisited below, we repeat this example "manually" with the general constructor.

What if I want to impose the same prior on many parameters?

The recommended constructor can be called as constrained_gaussian(...; repeats = n) to return a combined prior formed by n identical priors.

ParameterDistribution struct

This section provides more details on the components of a ParameterDistribution object.

ParameterDistributionType

The ParameterDistributionType struct wraps four types for specifying different types of prior distributions:

  • The Parameterized type is initialized using a Julia Distributions.jl object. Samples are drawn randomly from the distribution object.

  • The VectorOfParameterized type is initialized with a vector of distributions.

  • The Samples type is initialized using a two dimensional array. Samples are drawn randomly (with replacement) from the columns of the provided array.

  • The FunctionParameterDistributionType struct defines parameters specified as fields over a domain. More detail can be found here.

Warning

We recommend that the distributions be unbounded (see next section), as the filtering algorithms in EnsembleKalmanProcesses are not guaranteed to preserve constraints unless defined through the ConstraintType mechanism.

ConstraintType

The inference algorithms implemented in EnsembleKalmanProcesses assume unbounded parameter domains. To be able to handle constrained parameter values consistently, the ConstraintType defines a bijection between the physical, constrained parameter domain and an unphysical, unconstrained domain in which the filtering takes place. This bijection is specified by the functions transform_constrained_to_unconstrained and transform_unconstrained_to_constrained, which are built from either predefined constructors or user-defined constraint functions given as arguments to the ConstraintType constructor.

We provide the following predefined constructors which implement mappings that handle the most common constraints:

  • no_constraint(): The parameter is unconstrained and takes values in (-∞, ∞) (mapping is the identity).
  • bounded_below(lower_bound): The parameter takes values in [lower_bound, ∞).
  • bounded_above(upper_bound): The parameter takes values in (-∞, upper_bound].
  • bounded(lower_bound,upper_bound): The parameter takes values on the interval [lower_bound, upper_bound].

These are demonstrated in ConstraintType Examples.

Currently we only support multivariate constraints which are the Cartesian product of the one-dimensional ConstraintTypes. Every component of a multidimensional parameter must have an associated constraint, so, e.g. for a multivariate ParameterDistributionType of dimension p the user must provide a p-dimensional Array{ConstraintType}. A VectorOfParameterized distribution built with distributions of dimension p and q has dimension p+q.

Note

When a nontrivial ConstraintType is given, the general constructor assumes the ParameterDistributionType is specified in the unconstrained space; the actual prior pdf is then the composition of the ParameterDistributionType's pdf with the transform_unconstrained_to_constrained transformation. We provide constrained_gaussian to define priors directly in the physical, constrained space.

Warning

It is up to the user to ensure any custom mappings transform_constrained_to_unconstrained and transform_unconstrained_to_constrained are inverses of each other.

The name

This is simply a String used to identify different parameters in multi-parameter situations, as in the methods below.

FunctionParameterDistributionType

Learning a function distribution is useful when one wishes to obtain a parametric representation of a function that is (relatively) agnostic of the underlying grid discretization. Most practical implementations involve posing a restrictive class of functions by truncation of a spectral decomposition. The function is then represented as a set of coefficients of these modes (known as degrees of freedom), rather than directly through the values at evaluation points.

As a subtype of ParameterDistributionType, we currently support one option for specifying prior distributions over functions:

  • The GaussianRandomFieldInterface type is initialized with a Gaussian Random Field object and the GRF package. Currently we support objects from GaussianRandomFields.jl with package GRFJL(). Gaussian random fields allow the definition of scalar function distributions defined over a uniform mesh on interval, rectangular, and hyper-rectangular domains.

As with other ParameterDistributions, a function distribution, is built from a name, a FunctionPameterDistributionType struct and a constraint, here only one, placed on the scalar output space of the function using a Constraint().

constraints

The transformation transform_unconstrained_to_constrained, will map from (unconstrained) degrees of freedom, to (constrained) evaluations of the function on a numerical grid. In particular, the transform_constrained_to_unconstrained is no longer the inverse of this map, it now simply maps from constrained evaluations to unconstrained evaluations on the grid.

We provide an example construction here.

ParameterDistribution constructor

The Recommended constructor, constrained_gaussian(), is described above. For more general cases in which the prior needs to be specified in more detail, a ParameterDistribution may be constructed "manually" from its component objects:

using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`, `combine_distributions`
 prior_1 = ParameterDistribution(distribution_1, constraint_1, name_1)
 prior_2 = ParameterDistribution(distribution_2, constraint_2, name_2)
 prior = combine_distributions( [prior_1, prior_2])

Arguments may also be provided as a Dict:

using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`
@@ -21,11 +21,11 @@
 dict_2 = Dict("distribution" => distribution_2, "constraint" => constraint_2, "name" => name_2)
 prior = ParameterDistribution( [dict_1, dict_2] )

We provide Additional Examples below; see also examples in the package examples/ and unit tests found in test/ParameterDistributions/runtests.jl.

ParameterDistribution methods

These functions typically return a Dict with ParameterDistribution.name as a keys, or an Array if requested:

  • get_name: returns the name(s) of parameters in the ParameterDistribution.
  • get_distribution: returns the distributions (ParameterDistributionType objects) in the ParameterDistribution. Note that this is not the prior pdf used for inference if nontrivial constraints have been applied.
  • mean, var, cov, sample, logpdf: mean, variance, covariance, logpdf or samples the Julia Distribution if Parameterized, or draws from the list of samples if Samples. Extends the StatsBase definitions. Note that these do not correspond to the prior pdf used for inference if nontrivial constraints have been applied.
  • transform_unconstrained_to_constrained: Applies the constraint mappings.
  • transform_constrained_to_unconstrained: Applies the inverse constraint mappings.

Additional Examples

Simple example revisited

To illustrate what the constrained_gaussian constructor is doing, in this section we repeat the Recommended constructor - Simple example given above, using the "manual," general-purpose constructor. Let's bring in the packages we will require

using EnsembleKalmanProcesses.ParameterDistributions # for `bounded`, `Parameterized`, and `ParameterDistribution`
 using Distributions # for `Normal`

Then we initialize the constraint first,

constraint = bounded(0, 1)

This defines the following transformation to the constrained space (and also its inverse)

transform_unconstrained_to_constrained(x) = exp(x) / (exp(x) + 1)

The prior mean should be around 0.7 (in the constrained space), and one can find that the push-forward of a particular normal distribution, namely, transform_unconstrained_to_constrained(Normal(mean = 1, sd = 0.5)) gives a prior pdf with 95% of its mass between [0.5, 0.88].

This is the main difference from the use of the constrained_gaussian constructor: in that example, the constructor numerically solved for the parameters of the Normal() which would reproduce the requested μ, σ for the physical, constrained quantity (since no closed-form transformation for the moments exists.)

distribution = Parameterized(Normal(1, 0.5))

Finally we attach the name

name = "point_seven"

and the distribution is created by either:

prior = ParameterDistribution(distribution, constraint, name)

or

prior_dict = Dict("distribution" => distribution, "constraint" => constraint, "name" => name)
-prior = ParameterDistribution(prior_dict)

The pdf of the Normal distribution and its transform to the physical, constrained space are:

Example block output

Sample-based distribution

We repeat the work of Simple example revisited, but now assuming that to create our prior, we only have samples given by the histogram:

Example block output

Imagine we do not know this distribution is bounded. To create a ParameterDistribution one can take a matrix constrained_samples whose columns are this data:

using EnsembleKalmanProcesses.ParameterDistributions # for `Samples`, `no_constraint`, `ParameterDistribution`, `bounded`
+prior = ParameterDistribution(prior_dict)

The pdf of the Normal distribution and its transform to the physical, constrained space are:

Example block output

Sample-based distribution

We repeat the work of Simple example revisited, but now assuming that to create our prior, we only have samples given by the histogram:

Example block output

Imagine we do not know this distribution is bounded. To create a ParameterDistribution one can take a matrix constrained_samples whose columns are this data:

using EnsembleKalmanProcesses.ParameterDistributions # for `Samples`, `no_constraint`, `ParameterDistribution`, `bounded`
 distribution = Samples(constrained_samples)
 constraint = no_constraint()
 name = "point_seven"
-prior = ParameterDistribution(distribution, constraint, name)
Note

This naive implementation will not enforce any boundaries during the algorithm implementation.

Imagine that we know about the boundedness of this distribution, then, as in Simple example revisited, we define the constraint

constraint = bounded(0, 1)

which stores the transformation:

unconstrained_samples = constraint.constrained_to_unconstrained.(constrained_samples)

This maps the samples into an unbounded space, giving the following histogram:

Example block output

As before we define a Samples distribution from matrix whose columns are the (now unconstrained) samples, along with a name to create the ParameterDistribution.

distribution = Samples(unconstrained_samples)
+prior = ParameterDistribution(distribution, constraint, name)
Note

This naive implementation will not enforce any boundaries during the algorithm implementation.

Imagine that we know about the boundedness of this distribution, then, as in Simple example revisited, we define the constraint

constraint = bounded(0, 1)

which stores the transformation:

unconstrained_samples = constraint.constrained_to_unconstrained.(constrained_samples)

This maps the samples into an unbounded space, giving the following histogram:

Example block output

As before we define a Samples distribution from matrix whose columns are the (now unconstrained) samples, along with a name to create the ParameterDistribution.

distribution = Samples(unconstrained_samples)
 name = "point_seven"
 prior = ParameterDistribution(distribution, constraint, name)

Example combining several distributions

To show how to combine priors in a more complex setting (e.g. for an entire parametrized process), we create a 25-dimensional parameter distribution from three dictionaries.

Bring in the packages!

using EnsembleKalmanProcesses.ParameterDistributions
 # for `bounded_below`, `bounded`, `Constraint`, `no_constraint`,
@@ -54,8 +54,8 @@
 param_dict2 = Dict("distribution" => d2, "constraint" => c2, "name" => name2)
 param_dict3 = Dict("distribution" => d3, "constraint" => c3, "name" => name3)
 u = ParameterDistribution([param_dict1, param_dict2, param_dict3])

We can visualize the marginals of the constrained distributions,

using Plots
-plot(u)
Example block output

and the unconstrained distributions similarly,

using Plots
-plot(u, constrained = false)
Example block output

Function Distribution Example

Here, define a function parameter distribution on $[0,1] \times [1,2]$ , bounded by $[-5,-3]$ and with correlation lengthscales 0.05. First, we get the packages:

using EnsembleKalmanProcesses.ParameterDistributions # For `ParameterDistribution`
+plot(u)
Example block output

and the unconstrained distributions similarly,

using Plots
+plot(u, constrained = false)
Example block output

Function Distribution Example

Here, define a function parameter distribution on $[0,1] \times [1,2]$ , bounded by $[-5,-3]$ and with correlation lengthscales 0.05. First, we get the packages:

using EnsembleKalmanProcesses.ParameterDistributions # For `ParameterDistribution`
 using Random, Distributions # for `rand` and `Normal`
 using Plots
 # We must `import` the GRF package, rather than call a `using` statement here
@@ -79,7 +79,7 @@
 ) # The ParameterDistribution with constraint in the output space

We plot 4 samples of this distribution. Samples are taken over the (30-dimensional) degrees of freedom, and then we apply the transform_unconstrained_to_costrained map to (i) build the function distribution, (ii) evaluate it on the numerical grid, and (iii) constrain the output with our prescribed bounds.

shape = [length(pp) for pp in points]
 samples_constrained_flat = [transform_unconstrained_to_constrained(pd, rand(Normal(0,1), dofs)) for i = 1:4]
 plts = [contour(points..., reshape(samples_constrained_flat[i], shape...)', fill = true,) for i =1:4]
-plot(plts..., legend=false, size=(800,800))
Example block output

ConstraintType Examples

For each for the predefined ConstraintTypes, we present animations of the resulting constrained prior distribution for

distribution = Parameterized(Normal(μ, σ))

where we vary μ and σ respectively. As noted above, in the presence of a nontrivial constraint, μ and σ will no longer correspond to the mean and standard deviation of the prior distribution (which is taken in the physical, constrained space).

Without constraints: "constraint" => no_constraints()

The following specifies a prior based on an unconstrained Normal(0.5, 1) distribution:

using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `no_constraint`, `ParameterDistribution`
+plot(plts..., legend=false, size=(800,800))
Example block output

ConstraintType Examples

For each for the predefined ConstraintTypes, we present animations of the resulting constrained prior distribution for

distribution = Parameterized(Normal(μ, σ))

where we vary μ and σ respectively. As noted above, in the presence of a nontrivial constraint, μ and σ will no longer correspond to the mean and standard deviation of the prior distribution (which is taken in the physical, constrained space).

Without constraints: "constraint" => no_constraints()

The following specifies a prior based on an unconstrained Normal(0.5, 1) distribution:

using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `no_constraint`, `ParameterDistribution`
 using Distributions # for `Normal`
 
 param_dict = Dict(
@@ -114,4 +114,4 @@
 "name" => "bounded_parameter",
 )
 
-prior = ParameterDistribution(param_dict)

where bounded(-1, 5) automatically defines the constraint map

transform_unconstrained_to_constrained(x) = 10 - 5 / (exp(x) + 1)

The following plots show the effect of varying μ and σ in the physical, constrained space:

Example block output +prior = ParameterDistribution(param_dict)

where bounded(-1, 5) automatically defines the constraint map

transform_unconstrained_to_constrained(x) = 10 - 5 / (exp(x) + 1)

The following plots show the effect of varying μ and σ in the physical, constrained space:

Example block output diff --git a/dev/search_index.js b/dev/search_index.js index 6a125a78a..16edfa872 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"API/Sampler/#Ensemble-Kalman-Sampler","page":"Sampler","title":"Ensemble Kalman Sampler","text":"","category":"section"},{"location":"API/Sampler/","page":"Sampler","title":"Sampler","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/Sampler/","page":"Sampler","title":"Sampler","text":"Sampler\neks_update","category":"page"},{"location":"API/Sampler/#EnsembleKalmanProcesses.Sampler","page":"Sampler","title":"EnsembleKalmanProcesses.Sampler","text":"Sampler{FT<:AbstractFloat,IT<:Int} <: Process\n\nAn ensemble Kalman Sampler process.\n\nFields\n\nprior_mean::Vector{FT} where FT<:AbstractFloat\nMean of Gaussian parameter prior in unconstrained space\nprior_cov::Union{LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}} where FT<:AbstractFloat\nCovariance of Gaussian parameter prior in unconstrained space\n\nConstructors\n\nSampler(prior_mean, prior_cov)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:17.\n\nSampler(prior)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:23.\n\n\n\n\n\n","category":"type"},{"location":"API/Sampler/#EnsembleKalmanProcesses.eks_update","page":"Sampler","title":"EnsembleKalmanProcesses.eks_update","text":" eks_update(\n ekp::EnsembleKalmanProcess{FT, IT, Sampler{FT}},\n u::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n) where {FT <: Real, IT}\n\nReturns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the sampler algorithm.\n\nThe current implementation assumes that rows of u and g correspond to ensemble members, so it requires passing the transpose of the u and g arrays associated with ekp.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#Unscented-Kalman-Inversion","page":"Unscented","title":"Unscented Kalman Inversion","text":"","category":"section"},{"location":"API/Unscented/","page":"Unscented","title":"Unscented","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/Unscented/","page":"Unscented","title":"Unscented","text":"Unscented\nconstruct_sigma_ensemble\nconstruct_mean\nconstruct_cov\nupdate_ensemble_prediction!\nupdate_ensemble_analysis!","category":"page"},{"location":"API/Unscented/#EnsembleKalmanProcesses.Unscented","page":"Unscented","title":"EnsembleKalmanProcesses.Unscented","text":"Unscented{FT<:AbstractFloat, IT<:Int} <: Process\n\nAn unscented Kalman Inversion process.\n\nFields\n\nu_mean::Any\nan interable of arrays of size N_parameters containing the mean of the parameters (in each uki iteration a new array of mean is added)\nuu_cov::Any\nan iterable of arrays of size (N_parameters x N_parameters) containing the covariance of the parameters (in each uki iteration a new array of cov is added)\nobs_pred::Any\nan iterable of arrays of size N_y containing the predicted observation (in each uki iteration a new array of predicted observation is added)\nc_weights::AbstractVecOrMat{FT} where FT<:AbstractFloat\nweights in UKI\nmean_weights::AbstractVector{FT} where FT<:AbstractFloat\ncov_weights::AbstractVector{FT} where FT<:AbstractFloat\nN_ens::Int64\nnumber of particles 2N+1 or N+2\nΣ_ω::AbstractMatrix{FT} where FT<:AbstractFloat\ncovariance of the artificial evolution error\nΣ_ν_scale::AbstractFloat\ncovariance of the artificial observation error\nα_reg::AbstractFloat\nregularization parameter\nr::AbstractVector{FT} where FT<:AbstractFloat\nregularization vector\nupdate_freq::Int64\nupdate frequency\nimpose_prior::Bool\nusing augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation.\nprior_mean::Any\nprior mean - defaults to initial mean\nprior_cov::Any\nprior covariance - defaults to initial covariance\niter::Int64\ncurrent iteration number\n\nConstructors\n\nUnscented(\n u0_mean::AbstractVector{FT},\n uu0_cov::AbstractMatrix{FT};\n α_reg::FT = 1.0,\n update_freq::IT = 0,\n modified_unscented_transform::Bool = true,\n impose_prior::Bool = false,\n prior_mean::Any,\n prior_cov::Any,\n sigma_points::String = symmetric\n) where {FT <: AbstractFloat, IT <: Int}\n\nConstruct an Unscented Inversion Process.\n\nInputs:\n\nu0_mean: Mean at initialization.\nuu0_cov: Covariance at initialization.\nα_reg: Hyperparameter controlling regularization toward the prior mean (0 < α_reg ≤ 1),\n\ndefault should be 1, without regulariazion.\n\nupdate_freq: Set to 0 when the inverse problem is not identifiable, \n\nnamely the inverse problem has multiple solutions, the covariance matrix will represent only the sensitivity of the parameters, instead of posterior covariance information; set to 1 (or anything > 0) when the inverse problem is identifiable, and the covariance matrix will converge to a good approximation of the posterior covariance with an uninformative prior.\n\nmodified_unscented_transform: Modification of the UKI quadrature given in Huang et al (2021).\nimpose_prior: using augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation. If impose_prior == true, prior mean and prior cov must be provided. This is recommended to use, especially when the number of observations is smaller than the number of parameters (ill-posed inverse problems). When this is used, other regularizations are turned off automatically.\nprior_mean: Prior mean used for regularization.\nprior_cov: Prior cov used for regularization.\nsigma_points: String of sigma point type, it can be symmetric with 2N_par+1 ensemble members or simplex with N_par+2 ensemble members.\n\nUnscented(u_mean, uu_cov, obs_pred, c_weights, mean_weights, cov_weights, N_ens, Σ_ω, Σ_ν_scale, α_reg, r, update_freq, impose_prior, prior_mean, prior_cov, iter)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:57.\n\nUnscented(u0_mean, uu0_cov)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:91.\n\nUnscented(prior)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:212.\n\n\n\n\n\n","category":"type"},{"location":"API/Unscented/#EnsembleKalmanProcesses.construct_sigma_ensemble","page":"Unscented","title":"EnsembleKalmanProcesses.construct_sigma_ensemble","text":"construct_sigma_ensemble(\n process::Unscented,\n x_mean::Array{FT},\n x_cov::AbstractMatrix{FT},\n) where {FT <: AbstractFloat, IT <: Int}\n\nConstruct the sigma ensemble based on the mean x_mean and covariance x_cov.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.construct_mean","page":"Unscented","title":"EnsembleKalmanProcesses.construct_mean","text":"construct_mean(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n x::AbstractVecOrMat{FT};\n mean_weights = uki.process.mean_weights,\n) where {FT <: AbstractFloat, IT <: Int}\n\nconstructs mean x_mean from an ensemble x.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.construct_cov","page":"Unscented","title":"EnsembleKalmanProcesses.construct_cov","text":"construct_cov(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n x::AbstractVecOrMat{FT},\n x_mean::Union{FT, AbstractVector{FT}, Nothing} = nothing;\n cov_weights = uki.process.cov_weights,\n) where {FT <: AbstractFloat, IT <: Int}\n\nConstructs covariance xx_cov from ensemble x and mean x_mean.\n\n\n\n\n\nconstruct_cov(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n x::AbstractMatrix{FT},\n x_mean::AbstractVector{FT},\n obs_mean::AbstractMatrix{FT},\n y_mean::AbstractVector{FT};\n cov_weights = uki.process.cov_weights,\n) where {FT <: AbstractFloat, IT <: Int, P <: Process}\n\nConstructs covariance xy_cov from ensemble x and mean x_mean, ensemble obs_mean and mean y_mean.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.update_ensemble_prediction!","page":"Unscented","title":"EnsembleKalmanProcesses.update_ensemble_prediction!","text":"update_ensemble_prediction!(process::Unscented, Δt::FT) where {FT <: AbstractFloat}\n\nUKI prediction step : generate sigma points.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.update_ensemble_analysis!","page":"Unscented","title":"EnsembleKalmanProcesses.update_ensemble_analysis!","text":"update_ensemble_analysis!(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n u_p::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n) where {FT <: AbstractFloat, IT <: Int}\n\nUKI analysis step : g is the predicted observations Ny x N_ens matrix\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcess","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"","category":"section"},{"location":"API/EnsembleKalmanProcess/","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/EnsembleKalmanProcess/","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"EnsembleKalmanProcess\nFailureHandler\nSampleSuccGauss\nIgnoreFailures\nget_u\nget_g\nget_ϕ\nget_u_final\nget_g_final\nget_ϕ_final\nget_u_mean\nget_u_cov\nget_g_mean\nget_ϕ_mean\nget_u_mean_final\nget_u_cov_final\nget_g_mean_final\nget_ϕ_mean_final\ncompute_error!\nget_error\nget_N_iterations\nconstruct_initial_ensemble\nupdate_ensemble!\nsample_empirical_gaussian\nsplit_indices_by_success","category":"page"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.EnsembleKalmanProcess","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.EnsembleKalmanProcess","text":"EnsembleKalmanProcess{FT <: AbstractFloat, IT <: Int, P <: Process}\n\nStructure that is used in Ensemble Kalman processes.\n\nFields\n\nu::Array{EnsembleKalmanProcesses.DataContainers.DataContainer{FT}} where FT<:AbstractFloat\narray of stores for parameters (u), each of size [N_par × N_ens]\nobs_mean::Vector{FT} where FT<:AbstractFloat\nvector of the observed vector size [N_obs]\nobs_noise_cov::Union{LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}} where FT<:AbstractFloat\ncovariance matrix of the observational noise, of size [N_obs × N_obs]\nN_ens::Int64\nensemble size\ng::Array{EnsembleKalmanProcesses.DataContainers.DataContainer{FT}} where FT<:AbstractFloat\nArray of stores for forward model outputs, each of size [N_obs × N_ens]\nerr::Vector{FT} where FT<:AbstractFloat\nvector of errors\nscheduler::EnsembleKalmanProcesses.LearningRateScheduler\nScheduler to calculate the timestep size in each EK iteration\naccelerator::EnsembleKalmanProcesses.Accelerator\naccelerator object that informs EK update steps, stores additional state variables as needed\nΔt::Vector{FT} where FT<:AbstractFloat\nstored vector of timesteps used in each EK iteration\nprocess::EnsembleKalmanProcesses.Process\nthe particular EK process (Inversion or Sampler or Unscented or TransformInversion or SparseInversion)\nrng::Random.AbstractRNG\nRandom number generator object (algorithm + seed) used for sampling and noise, for reproducibility. Defaults to Random.GLOBAL_RNG.\nfailure_handler::FailureHandler\nstruct storing failsafe update directives, implemented for (Inversion, SparseInversion, Unscented, TransformInversion)\nlocalizer::EnsembleKalmanProcesses.Localizers.Localizer\nLocalization kernel, implemented for (Inversion, SparseInversion, Unscented)\nverbose::Bool\nWhether to print diagnostics for each EK iteration\n\nGeneric constructor\n\nEnsembleKalmanProcess(\n params::AbstractMatrix{FT},\n obs_mean,\n obs_noise_cov::Union{AbstractMatrix{FT}, UniformScaling{FT}},\n process::P;\n scheduler = DefaultScheduler(1),\n Δt = FT(1),\n rng::AbstractRNG = Random.GLOBAL_RNG,\n failure_handler_method::FM = IgnoreFailures(),\n localization_method::LM = NoLocalization(),\n verbose::Bool = false,\n) where {FT <: AbstractFloat, P <: Process, FM <: FailureHandlingMethod, LM <: LocalizationMethod}\n\nInputs:\n\nparams :: Initial parameter ensemble\nobs_mean :: Vector of observations\nobs_noise_cov :: Noise covariance associated with the observations obs_mean\nprocess :: Algorithm used to evolve the ensemble\nscheduler :: Adaptive timestep calculator \nΔt :: Initial time step or learning rate\nrng :: Random number generator\nfailure_handler_method :: Method used to handle particle failures\nlocalization_method :: Method used to localize sample covariances\nverbose :: Whether to print diagnostic information\n\nOther constructors:\n\nEnsembleKalmanProcess(u, obs_mean, obs_noise_cov, N_ens, g, err, scheduler, accelerator, Δt, process, rng, failure_handler, localizer, verbose)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:117.\n\nEnsembleKalmanProcess(params, obs_mean, obs_noise_cov, process)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:147.\n\nEnsembleKalmanProcess(obs_mean, obs_noise_cov, process)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:223.\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.FailureHandler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.FailureHandler","text":"FailureHandler{P <: Process, FM <: FailureHandlingMethod}\n\nStructure defining the failure handler method used in the EnsembleKalmanProcess.\n\nFields\n\nfailsafe_update::Function\nFailsafe algorithmic update equation\n\nConstructors\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:10.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:22.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:31.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:17.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:29.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:40.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:52.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:235.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:254.\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.SampleSuccGauss","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.SampleSuccGauss","text":"\" SampleSuccGauss <: FailureHandlingMethod\n\nFailure handling method that substitutes failed ensemble members by new samples from the empirical Gaussian distribution defined by the updated successful ensemble.\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.IgnoreFailures","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.IgnoreFailures","text":"Failure handling method that ignores forward model failures\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u","text":"get_u(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}\n\nReturns the unconstrained parameters at the given iteration. Returns a DataContainer object unless return_array is true.\n\n\n\n\n\nget_u(ekp::EnsembleKalmanProcess; return_array=true)\n\nReturns the unconstrained parameters from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g","text":"get_g(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}\n\nReturns the forward model evaluations at the given iteration. Returns a DataContainer object unless return_array is true.\n\n\n\n\n\nget_g(ekp::EnsembleKalmanProcess; return_array=true)\n\nReturns the forward model evaluations from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ","text":"get_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)\n\nReturns the constrained parameters at the given iteration.\n\n\n\n\n\nget_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)\n\nReturns the constrained parameters from all iterations. The outer dimension is given by the number of iterations.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_final","text":"get_u_final(ekp::EnsembleKalmanProcess, return_array=true)\n\nGet the unconstrained parameters at the last iteration, returning a DataContainer Object if return_array is false.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g_final","text":"get_g_final(ekp::EnsembleKalmanProcess, return_array=true)\n\nGet forward model outputs at the last iteration, returns a DataContainer Object if return_array is false.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ_final","text":"get_ϕ_final(ekp::EnsembleKalmanProcess)\n\nGet the constrained parameters at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_mean","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_mean","text":"get_u_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}\n\nReturns the mean unconstrained parameter at the given iteration.\n\n\n\n\n\nget_u_mean(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)\n\nReturns the mean unconstrained parameter at the requested iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_cov","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_cov","text":"get_u_cov(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}\n\nReturns the unconstrained parameter sample covariance at the given iteration.\n\n\n\n\n\nget_u_cov(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)\n\nReturns the unconstrained parameter covariance at the requested iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g_mean","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g_mean","text":"get_g_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}\n\nReturns the mean forward map evaluation at the given iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ_mean","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ_mean","text":"get_ϕ_mean(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)\n\nReturns the constrained transform of the mean unconstrained parameter at the given iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_mean_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_mean_final","text":"get_u_mean_final(ekp::EnsembleKalmanProcess)\n\nGet the mean unconstrained parameter at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_cov_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_cov_final","text":"get_u_cov_final(ekp::EnsembleKalmanProcess)\n\nGet the mean unconstrained parameter covariance at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g_mean_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g_mean_final","text":"get_g_mean_final(ekp::EnsembleKalmanProcess)\n\nGet the mean forward model evaluation at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ_mean_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ_mean_final","text":"get_ϕ_mean_final(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)\n\nGet the constrained transform of the mean unconstrained parameter at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.compute_error!","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.compute_error!","text":"compute_error!(ekp::EnsembleKalmanProcess)\n\nComputes the covariance-weighted error of the mean forward model output, (ḡ - y)'Γ_inv(ḡ - y). The error is stored within the EnsembleKalmanProcess.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_error","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_error","text":"get_error(ekp::EnsembleKalmanProcess)\n\nReturns the mean forward model output error as a function of algorithmic time.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_N_iterations","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_N_iterations","text":"get_N_iterations(ekp::EnsembleKalmanProcess)\n\nGet number of times update has been called (equals size(g), or size(u)-1).\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.construct_initial_ensemble","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.construct_initial_ensemble","text":"construct_initial_ensemble(\n rng::AbstractRNG,\n prior::ParameterDistribution,\n N_ens::IT\n) where {IT <: Int}\nconstruct_initial_ensemble(prior::ParameterDistribution, N_ens::IT) where {IT <: Int}\n\nConstruct the initial parameters, by sampling N_ens samples from specified prior distribution. Returned with parameters as columns.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.update_ensemble!","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.update_ensemble!","text":"update_ensemble!(\n ekp::EnsembleKalmanProcess,\n g::AbstractMatrix{FT};\n multiplicative_inflation::Bool = false,\n additive_inflation::Bool = false,\n use_prior_cov::Bool = false,\n s::FT = 0.0,\n ekp_kwargs...,\n) where {FT, IT}\n\nUpdates the ensemble according to an Inversion process. Inputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nmultiplicative_inflation :: Flag indicating whether to use multiplicative inflation.\nadditive_inflation :: Flag indicating whether to use additive inflation.\nusepriorcov :: Bool specifying whether to use prior covariance estimate for additive inflation. If false (default), parameter covariance from the current iteration is used.\ns :: Scaling factor for time step in inflation step.\nekpkwargs :: Keyword arguments to pass to standard ekp updateensemble!.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, Inversion},\n g::AbstractMatrix{FT},\n process::Inversion;\n deterministic_forward_map::Bool = true,\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to an Inversion process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\ndeterministicforwardmap :: Whether output g comes from a deterministic model.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, TransformInversion},\n g::AbstractMatrix{FT},\n process::TransformInversion;\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to a TransformInversion process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},\n g::AbstractMatrix{FT},\n process::SparseInversion{FT};\n deterministic_forward_map = true,\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to a SparseInversion process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\ndeterministic_forward_map :: Whether output g comes from a deterministic model.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, Sampler{FT}},\n g::AbstractMatrix{FT},\n process::Sampler{FT};\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to a Sampler process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n g_in::AbstractMatrix{FT},\n process::Unscented;\n failed_ens = nothing,\n) where {FT <: AbstractFloat, IT <: Int}\n\nUpdates the ensemble according to an Unscented process. \n\nInputs:\n\nuki :: The EnsembleKalmanProcess to update.\ng_in :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.sample_empirical_gaussian","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.sample_empirical_gaussian","text":"sample_empirical_gaussian(\n u::AbstractMatrix{FT},\n n::IT;\n inflation::Union{FT, Nothing} = nothing,\n) where {FT <: Real, IT <: Int}\n\nReturns n samples from an empirical Gaussian based on point estimates u, adding inflation if the covariance is singular.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.split_indices_by_success","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.split_indices_by_success","text":" split_indices_by_success(g::AbstractMatrix{FT}) where {FT <: Real}\n\nReturns the successful/failed particle indices given a matrix with output vectors stored as columns. Failures are defined for particles containing at least one NaN output element.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#scheduler_api","page":"EnsembleKalmanProcess","title":"Learning Rate Schedulers","text":"","category":"section"},{"location":"API/EnsembleKalmanProcess/","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"DefaultScheduler\nMutableScheduler\nEKSStableScheduler\nDataMisfitController\ncalculate_timestep!","category":"page"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.DefaultScheduler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.DefaultScheduler","text":"struct DefaultScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler containing a default constant step size, users can override this temporarily within update_ensemble!.\n\nΔt_default::Any\nstep size\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.MutableScheduler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.MutableScheduler","text":"struct MutableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler containing a mutable constant step size, users can override this permanently within update_ensemble!.\n\nΔt_mutable::Vector\nmutable step size\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.EKSStableScheduler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.EKSStableScheduler","text":"struct EKSStableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler known to be stable for EKS, In particular, Delta t = fracalphaU + varepsilon where U = (G(u) - barG(u))^TGamma^-1(G(u) - y). Cannot be overriden.\n\nnumerator::Any\nthe numerator alpha\nnugget::Any\nthe nugget term varepsilon\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.DataMisfitController","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.DataMisfitController","text":"struct DataMisfitController{FT, M, S} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler from Iglesias, Yang, 2021, Based on Bayesian Tempering. Terminates at T=1 by default, and at this time, ensemble spread provides a (more) meaningful approximation of posterior uncertainty In particular, for parameters theta_j at step n, to calculate the next timestep Delta t_n = minleft(maxleft(fracJ2Phi sqrtfracJ2langle Phi Phi rangleright) 1-sum^n-1_i t_iright) where Phi_j = Gamma^-frac12(G(theta_j) - y)^2. Cannot be overriden by user provided timesteps. By default termination returns true from update_ensemble! and \n\nif on_terminate == \"stop\", stops further iteration.\nif on_terminate == \"continue_fixed\", continues iteration with the final timestep fixed\nif on_terminate == \"continue\", continues the algorithm (though no longer compares to 1-sum^n-1_i t_i) \n\nThe user may also change the T with terminate_at keyword.\n\niteration::Vector{Int64}\nthe current iteration\ninv_sqrt_noise::Vector\nthe inverse square-root of the noise covariance is stored\nterminate_at::Any\nthe algorithm time for termination, default: 1.0\non_terminate::Any\nthe action on termination, default: \"stop\",\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.calculate_timestep!","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.calculate_timestep!","text":"calculate_timestep!(ekp::EnsembleKalmanProcess, g::AbstractMatrix, Δt_new::Union{Nothing, AbstractFloat}) -> Any\n\n\nCalculates next timestep by pushing to ekp.Δt, !isnothing(return_value) implies termination condition has been met\n\n\n\n\n\n","category":"function"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"EditURL = \"../../../examples/AerosolActivation/aerosol_activation.jl\"","category":"page"},{"location":"literated/aerosol_activation/#Aerosol-Activation-Example","page":"Aerosol activation","title":"Aerosol Activation Example","text":"","category":"section"},{"location":"literated/aerosol_activation/#Overview","page":"Aerosol activation","title":"Overview","text":"","category":"section"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"This example is based on AerosolActivation module which is a part of the CloudMicrophysics.jl package. The AerosolActivation module computes the total number and mass of aerosol particles that get activated and become cloud droplets, given the atmospheric conditions and the initial aerosol size distribution and properties. See the AerosolActivation module docs for derivation and description of all input parameters.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"In this example we use the ensemble Kalman methods to learn two parameters that describe the chemical composition of aerosol particles based on the observed total number and mass of activated particles. The AerosolActivation model is used here in a \"perfect model\" setting, meaning that the observations are generated by the same module we are calibrating.","category":"page"},{"location":"literated/aerosol_activation/#Prerequisites","page":"Aerosol activation","title":"Prerequisites","text":"","category":"section"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"The example depends on some standard Julia libraries, as well as the CliMA packages: EnsembleKalmanProcess.jl, CLIMAParameters.jl and CloudMicrophysics.jl. To ensure that all the dependencies are met start Julia using the Project.toml file provided in the example and run the Julia package manager to download all the dependecies.","category":"page"},{"location":"literated/aerosol_activation/#Example","page":"Aerosol activation","title":"Example","text":"","category":"section"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We begin by importing some standard Julia modules, the Ensemble Kalman Process modules, CLIMA Parameter modules and Aerosol Activation modules.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"using Plots\nusing Distributions\nusing LinearAlgebra\nusing Random\n\nrng_seed = 44\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses\n\nimport CLIMAParameters\nconst CP = CLIMAParameters\nstruct EarthParameterSet <: CP.AbstractEarthParameterSet end\nconst param_set = EarthParameterSet()\n\nimport CloudMicrophysics\nconst AM = CloudMicrophysics.AerosolModel\nconst AA = CloudMicrophysics.AerosolActivation\n\nimport Thermodynamics\nconst TD = Thermodynamics\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Next, we provide the information about the priors of the parameters we want to learn. We are calibrating two parameters decribing the aerosol properties - namely the aerosol molar mass and the osmotic coefficient.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"parameter_names = [\"molar_mass\", \"osmotic_coeff\"]\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"In this test we do know the parameter values. We use them to test the convergence of EKP for aerosol activation.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"molar_mass_true = 0.058443\nosmotic_coeff_true = 0.9\ndefault_params = [molar_mass_true, osmotic_coeff_true]\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We must define parameter priors. Both parameters have to be positive definite, therefore we define the constraints to be bounded below by zero. We don't have much other prior knowledge about the parameters. We simply constrain their scale to be loosely of size 1. For more details see constrained_gaussian","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"prior1 = constrained_gaussian(parameter_names[1], 1, 1, 0, Inf)\nprior2 = constrained_gaussian(parameter_names[2], 1, 1, 0, Inf)\npriors = combine_distributions([prior1, prior2])\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Next we define the atmospheric conditions for which the calibration will take place, (air temperature in K, air pressure in Pa vertical velocity in m/s and vapor specific humidity assuming its saturated in kg/kg) This can be changed later to include more than one (T p w) combination in the calibration process","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"T = 283.15\np = 1e5\nw = 5.0\np_vs = TD.saturation_vapor_pressure(param_set, T, TD.Liquid())\nq_vs = 1 / (1 - CP.Planet.molmass_ratio(param_set) * (p_vs - p) / p_vs)\nq = TD.PhasePartition(q_vs, 0.0, 0.0)\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We also define the aerosol size distribution (lognormal, 1 mode) with (mean radius in m, geometric stdev, number concentration 1/m³). These can also be changed later to include different initial size distributions.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"r_dry = 0.243e-6\nstdev = 1.4\nN = 100.0 * 1e6 # since 1/cm³ = 1e6 1/m³\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Finally, we define additional parameters that describe the aerosol properties. The chosen aerosol is sea salt.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"dissoc_seasalt = 2.0\nsoluble_mass_frac_seasalt = 1.0\nrho_seasalt = 2170.0;\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We define a wrapper function that runs the aerosol activation module with two input parameters that will be calibrated by EKP. The output observations are the number and mass of activated aerosol.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"function run_activation_model(molar_mass_calibrated, osmotic_coeff_calibrated)\n\n accum_mode_seasalt = AM.Mode_B(\n r_dry,\n stdev,\n N,\n (1.0,),\n (soluble_mass_frac_seasalt,),\n (osmotic_coeff_calibrated,),\n (molar_mass_calibrated,),\n (dissoc_seasalt,),\n (rho_seasalt,),\n 1,\n )\n\n aerosol_distr = AM.AerosolDistribution((accum_mode_seasalt,))\n N_act = AA.total_N_activated(param_set, aerosol_distr, T, p, w, q)\n M_act = AA.total_M_activated(param_set, aerosol_distr, T, p, w, q)\n return [N_act, M_act]\nend\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"This example is run in a \"perfect model setting\", meaning the model that we calibrate is also used to generate observations. We use the total number and mass of activated aerosol particles as our observational data.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"observation_data_names = [\"N_act\", \"M_act\"];\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We generate artificial truth samples based on the default values of parameters we are calibrating.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"n_samples = 10\nG_t = run_activation_model(molar_mass_true, osmotic_coeff_true)\ny_t = zeros(length(G_t), n_samples)\n\nΓy = convert(Array, LinearAlgebra.Diagonal([0.01 * G_t[1], 0.01 * G_t[2]]))\nμ = zeros(length(G_t));\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"And add noise to the generated truth sample.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"for i in 1:n_samples\n y_t[:, i] = G_t .+ rand(Distributions.MvNormal(μ, Γy))\nend\n\ntruth_array = EKP.Observations.Observation(y_t, Γy, observation_data_names)\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"One could try for the truth to be a mean of the generated array. Or do the calibration for all individual truth samples and then compute the mean of calibrated parameters. For now we are just taking one truth array member.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"truth_sample = truth_array.samples[1];\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We use 50 ensemble members and do 10 iterations.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"N_ens = 50\nN_iter = 10\n\ninitial_par = EKP.construct_initial_ensemble(rng, priors, N_ens)\nekiobj = EKP.EnsembleKalmanProcess(initial_par, truth_sample, truth_array.obs_noise_cov, EKP.Inversion())\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Finally, we can run the Ensemble Kalman Process calibration.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"ϕ_n_values = []\nfor n in 1:N_iter\n ϕ_n = EKP.get_ϕ_final(priors, ekiobj)\n G_n = [run_activation_model(ϕ_n[:, i]...) for i in 1:N_ens]\n G_ens = hcat(G_n...)\n EKP.update_ensemble!(ekiobj, G_ens)\n\n global ϕ_n_values = vcat(ϕ_n_values, [ϕ_n])\nend\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We define some simple functions for plotting the data.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"function plot_ensemble_scatter(id)\n\n ensemble_member = 1:N_ens\n\n if id == 1\n ylabel = \"Molar mass [kg/mol]\"\n filename = \"molar_mass_scatter.pdf\"\n elseif id == 2\n ylabel = \"Osmotic coefficient [-]\"\n filename = \"osmotic_coeff_scatter.pdf\"\n end\n\n plot(\n ensemble_member,\n ϕ_n_values[1][id, 1:N_ens],\n seriestype = :scatter,\n xlabel = \"Ensemble Number\",\n ylabel = ylabel,\n legend = false,\n )\n\n for it in 2:N_iter\n plot!(ensemble_member .+ ((it - 1) * 50), ϕ_n_values[it][id, 1:N_ens], seriestype = :scatter, legend = false)\n end\n\n current()\n savefig(filename)\nend\n\nfunction plot_ensemble_means(id)\n\n number_of_iters = 1:N_iter\n means = zeros(N_iter)\n\n for it in 1:N_iter\n means[it] = mean(ϕ_n_values[it][id, 1:N_ens])\n end\n\n if id == 1\n ylabel = \"Molar mass [kg/mol]\"\n filename = \"molar_mass_average.pdf\"\n end\n if id == 2\n ylabel = \"Osmotic coefficient [-]\"\n filename = \"osmotic_coeff_average.pdf\"\n end\n\n plot(\n number_of_iters,\n means,\n markershape = :star5,\n xticks = number_of_iters,\n xlabel = \"Iteration Number\",\n ylabel = ylabel,\n label = \"Ensemble Mean\",\n )\n hline!([default_params[id]], label = \"true value\")\n\n savefig(filename)\nend\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We plot the ensemble members and the ensemble mean for the molar mass and osmotic coefficient.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"plot_ensemble_scatter(1)\nplot_ensemble_means(1)\nplot_ensemble_scatter(2)\nplot_ensemble_means(2)","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"(Image: ) (Image: ) (Image: ) (Image: )","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Finally, we test that the parameter values obtained via EnsembleKalmanProcesses.jl are close to the known true parameter values.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"molar_mass_ekp = round(mean(ϕ_n_values[N_iter][1, 1:N_ens]), digits = 6)\nosmotic_coeff_ekp = round(mean(ϕ_n_values[N_iter][2, 1:N_ens]), digits = 6)\n\nprintln(\"Molar mass [kg/mol]: \", molar_mass_ekp, \" vs \", molar_mass_true)\nprintln(\"Osmotic coefficient [-]: \", osmotic_coeff_ekp, \" vs \", osmotic_coeff_true)","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"This page was generated using Literate.jl.","category":"page"},{"location":"contributing/#Contributing","page":"Contributing","title":"Contributing","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Thank you for considering contributing to EnsembleKalmanProcesses! We encourage opening issues and pull requests (PRs).","category":"page"},{"location":"contributing/#What-to-contribute?","page":"Contributing","title":"What to contribute?","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"The easiest way to contribute is by using EnsembleKalmanProcesses, identifying problems and opening issues;\nYou can try to tackle an existing issue. It is best to outline your proposed solution in the issue thread before implementing it in a PR;\nWrite an example or tutorial. It is likely that other users may find your use of EnsembleKalmanProcesses insightful;\nImprove documentation or comments if you found something hard to use;\nImplement a new feature if you need it. We strongly encourage opening an issue to make sure the administrators are on board before opening a PR with an unsolicited feature addition.","category":"page"},{"location":"contributing/#Using-git","page":"Contributing","title":"Using git","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"If you are unfamiliar with git and version control, the following guides will be helpful:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Atlassian (bitbucket) git tutorials. A set of tips and tricks for getting started with git.\nGitHub's git tutorials. A set of resources from GitHub to learn git.","category":"page"},{"location":"contributing/#Forks-and-branches","page":"Contributing","title":"Forks and branches","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Create your own fork of EnsembleKalmanProcesses on GitHub and check out your copy:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git clone https://github.com//EnsembleKalmanProcesses.jl.git\n$ cd EnsembleKalmanProcesses.jl","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Now you have access to your fork of EnsembleKalmanProcesses through origin. Create a branch for your feature; this will hold your contribution:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git checkout -b ","category":"page"},{"location":"contributing/#Some-useful-tips","page":"Contributing","title":"Some useful tips","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"When you start working on a new feature branch, make sure you start from main by running: git checkout main and git pull.\nCreate a new branch from main by using git checkout -b .","category":"page"},{"location":"contributing/#Develop-your-feature","page":"Contributing","title":"Develop your feature","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Make sure you add tests for your code in test/ and appropriate documentation in the code and/or in docs/. Before committing your changes, you can verify their behavior by running the tests, the examples, and building the documentation locally. In addition, make sure your feature follows the formatting guidelines by running","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"julia --project=.dev .dev/climaformat.jl .","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"from the EnsembleKalmanProcesses.jl directory.","category":"page"},{"location":"contributing/#Squash-and-rebase","page":"Contributing","title":"Squash and rebase","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"When your PR is ready for review, clean up your commit history by squashing and make sure your code is current with EnsembleKalmanProcesses.jl main by rebasing. The general rule is that a PR should contain a single commit with a descriptive message.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"To make sure you are up to date with main, you can use the following workflow:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git checkout main\n$ git pull\n$ git checkout \n$ git rebase main","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"This may create conflicts with the local branch. The conflicted files will be outlined by git. To resolve conflicts, we have to manually edit the files (e.g. with vim). The conflicts will appear between >>>>, ===== and <<<<<. We need to delete these lines and pick what version we want to keep.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"To squash your commits, you can use the following command:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git rebase -i HEAD~n","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"where n is the number of commits you need to squash into one. Then, follow the instructions in the terminal. For example, to squash 4 commits:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git rebase -i HEAD~4","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"will open the following file in (typically) vim:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":" pick 01d1124 \n pick 6340aaa \n pick ebfd367 \n pick 30e0ccb \n\n # Rebase 60709da..30e0ccb onto 60709da\n #\n # Commands:\n # p, pick = use commit\n # e, edit = use commit, but stop for amending\n # s, squash = use commit, but meld into previous commit\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\n##","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We want to keep the first commit and squash the last 3. We do so by changing the last three commits to squash and then do :wq on vim.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":" pick 01d1124 \n squash 6340aaa \n squash ebfd367 \n squash 30e0ccb \n\n # Rebase 60709da..30e0ccb onto 60709da\n #\n # Commands:\n # p, pick = use commit\n # e, edit = use commit, but stop for amending\n # s, squash = use commit, but meld into previous commit\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Then in the next screen that appears, we can just delete all messages that we do not want to show in the commit. After this is done and we are back to the console, we have to force push. We need to force push because we rewrote the local commit history.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git push -uf origin ","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"You can find more information about squashing here.","category":"page"},{"location":"contributing/#Unit-testing","page":"Contributing","title":"Unit testing","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Currently a number of checks are run per commit for a given PR.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"JuliaFormatter checks if the PR is formatted with .dev/climaformat.jl.\nDocumentation rebuilds the documentation for the PR and checks if the docs are consistent and generate valid output.\nUnit Tests run subsets of the unit tests defined in tests/, using Pkg.test(). The tests are run in parallel to ensure that they finish in a reasonable time. The tests only run the latest commit for a PR, branch and will kill any stale jobs on push. These tests are only run on linux (Ubuntu LTS).","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Unit tests are run against every new commit for a given PR, the status of the unit-tests are not checked during the merge process but act as a sanity check for developers and reviewers. Depending on the content changed in the PR, some CI checks that are not necessary will be skipped. For example doc only changes do not require the unit tests to be run.","category":"page"},{"location":"contributing/#The-merge-process","page":"Contributing","title":"The merge process","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We use bors to manage merging PR's in the the EnsembleKalmanProcesses repo. If you're a collaborator and have the necessary permissions, you can type bors try in a comment on a PR to have integration test suite run on that PR, or bors r+ to try and merge the code. Bors ensures that all integration tests for a given PR always pass before merging into main. The integration tests currently run example cases in examples/. Any breaking changes will need to also update the examples/, else bors will fail.","category":"page"},{"location":"observations/#Observations","page":"Observations","title":"Observations","text":"","category":"section"},{"location":"observations/","page":"Observations","title":"Observations","text":"The Observations object is used to store the truth for convenience of the user. The ingredients are","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"Samples of the data Vector{Vector{Float}} or Array{Float, 2}. If provided as a 2D array, the samples must be provided as columns. They are stored internally as Vector{Vector{Float}}\nAn optional covariance matrix can be provided.\nThe names of the data in this object as a String or Vector{String}","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"The empirical mean is calculated automatically. If a covariance matrix is not provided, then the empirical covariance is also calculated automatically.","category":"page"},{"location":"observations/#A-simple-example:","page":"Observations","title":"A simple example:","text":"","category":"section"},{"location":"observations/","page":"Observations","title":"Observations","text":"Here is a typical construction of the object:","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"μ = zeros(5)\nΓy = rand(5, 5)\nΓy = Γy' * Γy\nyt = rand(MvNormal(μ, Γy), 100) # generate 100 samples\nname = \"zero-mean mvnormal\"\n\ntrue_data = Observations.Observation(yt, Γy, name)","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"Currently, the data is retrieved by accessing the stored variables, e.g the fifth data sample is given by truth_data.samples[5], or the covariance matrix by truth_data.cov.","category":"page"},{"location":"ensemble_kalman_sampler/#Ensemble-Kalman-Sampling","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampling","text":"","category":"section"},{"location":"ensemble_kalman_sampler/#What-Is-It-and-What-Does-It-Do?","page":"Ensemble Kalman Sampler","title":"What Is It and What Does It Do?","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The Ensemble Kalman Sampler (EKS) (Garbuno-Inigo et al, 2020, Cleary et al, 2020, Garbuno-Inigo et al, 2020) is a derivative-free tool for approximate Bayesian inference. It does so by approximately sampling from the posterior distribution. That is, EKS provides both point estimation (through the mean of the final ensemble) and uncertainty quantification (through the covariance of the final ensemble), this is in contrast to EKI, which only provides point estimation.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The EKS is an interacting particle system in stochastic differential equation form, and it is based on a dynamic which transforms an arbitrary initial probability distribution into an approximation of the desired posterior distribution over an infinite time horizon – see Garbuno-Inigo et al, 2020, for a comprehensive description of the method. While there are noisy variants of the standard EKI, EKS differs from them in its noise structure (as its noise is added in parameter space, not in data space), and its update rule explicitly accounts for the prior (rather than having it enter through initialization). The EKS algorithm can be understood as well as an affine invariant system of interacting particles (Garbuno-Inigo et al, 2020) for which a finite-sample correction is introduced to overcome its computational finite-sample implementation. This finite-sample corrected version of EKS is also known as the affine invariant Langevin dynamics (ALDI).","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"Perhaps as expected, the approximate posterior characterization through EKS needs more iterations, and thus more forward model evaluations, than EKI to converge to a suitable solution. This is because of the discrete-time implementation of the EKS diffusion process and the need to maintain a stable interacting particle system. However, the posterior approximation through EKS is obtained with far less computational effort than a typical Markov Chain Monte Carlo (MCMC) like Metropolis-Hastings.","category":"page"},{"location":"ensemble_kalman_sampler/#Problem-Formulation","page":"Ensemble Kalman Sampler","title":"Problem Formulation","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The data y and parameter vector theta are assumed to be related according to:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":" y = mathcalG(theta) + eta ","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where mathcalG mathbbR^p rightarrow mathbbR^d denotes the forward map, y in mathbbR^d is the vector of observations, and eta is the observational noise, which is assumed to be drawn from a d-dimensional Gaussian with distribution mathcalN(0 Gamma_y). The objective of the inverse problem is to compute the unknown parameters theta given the observations y, the known forward map mathcalG, and noise characteristics eta of the process.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"note: Note\nTo obtain Bayesian characterization for the posterior from EKS, the user must specify a Gaussian prior distribution. See Prior distributions to see how one can apply flexible constraints while maintaining Gaussian priors. ","category":"page"},{"location":"ensemble_kalman_sampler/#Ensemble-Kalman-Sampling-Algorithm","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampling Algorithm","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The EKS is based on the following update equation for the parameter vector theta^(j)_n of ensemble member j at the n-iteration:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"beginaligned\ntheta_n+1^(* j) = theta_n^(j) - dfracDelta t_nJsum_k=1^Jlangle mathcalG(theta_n^(k)) - barmathcalG_n Gamma_y^-1(mathcalG(theta_n^(j)) - y) rangle theta_n^(k) + fracd+1J left(theta_n^(j) - bar theta_n right) - Delta t_n mathsfC(Theta_n) Gamma_theta^-1 theta_n + 1^(* j) \ntheta_n + 1^j = theta_n+1^(* j) + sqrt2 Delta t_n mathsfC(Theta_n) xi_n^j \nendaligned","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where the subscript n=1 dots N_textit indicates the iteration, J is the ensemble size (i.e., the number of particles in the ensemble), Delta t_n is an internal adaptive time step (thus no need for the user to specify), Gamma_theta is the prior covariance, and xi_n^(j) sim mathcalN(0 mathrmI_p). barmathcalG_n is the ensemble mean of the forward map mathcalG(theta),","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"barmathcalG_n = dfrac1Jsum_k=1^JmathcalG(theta_n^(k))","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The p times p matrix mathsfC(Theta_n), where Theta_n = lefttheta^(j)_nright_j=1^J is the set of all ensemble particles in the n-th iteration, denotes the empirical covariance between particles","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"mathsfC(Theta_n) = frac1J sum_k=1^J (theta^(k)_n - bartheta_n) otimes (theta^(k)_n - bartheta_n)","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where bartheta_n is the ensemble mean of the particles,","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"bartheta_n = dfrac1Jsum_k=1^Jtheta^(k)_n ","category":"page"},{"location":"ensemble_kalman_sampler/#Constructing-the-Forward-Map","page":"Ensemble Kalman Sampler","title":"Constructing the Forward Map","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"At the core of the forward map mathcalG is the dynamical model PsimathbbR^p rightarrow mathbbR^o (running Psi is usually where the computational heavy-lifting is done), but the map mathcalG may include additional components such as a transformation of the (unbounded) parameters theta to a constrained domain the dynamical model can work with, or some post-processing of the output of Psi to generate the observations. For example, mathcalG may take the following form:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"mathcalG = mathcalH circ Psi circ mathcalT^-1","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where mathcalHmathbbR^o rightarrow mathbbR^d is the observation map and mathcalT is the transformation from the constrained to the unconstrained parameter space, such that mathcalT(phi)=theta. A family of standard transformations and their inverses are available in the ParameterDistributions module.","category":"page"},{"location":"ensemble_kalman_sampler/#How-to-Construct-an-Ensemble-Kalman-Sampler","page":"Ensemble Kalman Sampler","title":"How to Construct an Ensemble Kalman Sampler","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"An EKS object can be created using the EnsembleKalmanProcess constructor by specifying the Sampler type. The constructor takes two arguments, the prior mean prior_mean and the prior covariance prior_cov.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"Creating an EKS object requires as arguments:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"An initial parameter ensemble – an array of size p × N_ens, where N_ens is the ensemble size;\nThe mean value of the observed data – a vector of length d;\nThe covariance matrix of the observational noise – an array of size d × d;\nThe Sampler(prior_mean, prior_cov) process type, with the mean (a vector of length p) and the covariance (an array of size p x p) of the parameter's prior distribution.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The following example shows how an EKS object is instantiated. An observation (y) and the covariance of the observational noise (obs_cov) are assumed to be defined previously in the code.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions # required to create the prior\n\n# Construct prior (see `ParameterDistributions.jl` docs)\nprior = ParameterDistribution(...)\nprior_mean = mean(prior)\nprior_cov = cov(prior)\n\n# Construct initial ensemble\nN_ens = 50 # ensemble size\ninitial_ensemble = construct_initial_ensemble(prior, N_ens)\n\n# Construct ensemble Kalman process\neks_process = Sampler(prior_mean, prior_cov)\neksobj = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, eks_process)","category":"page"},{"location":"ensemble_kalman_sampler/#Updating-the-ensemble","page":"Ensemble Kalman Sampler","title":"Updating the ensemble","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"Once the EKS object eksobj has been initialized, the initial ensemble of particles is iteratively updated by the update_ensemble! function, which takes as arguments the eksobj and the evaluations of the forward model at each member of the current ensemble. In the following example, the forward map G maps a parameter to the corresponding data – this is done for each parameter in the ensemble, such that the resulting g_ens is of size d x N_ens. The update_ensemble! function then stores the updated ensemble as well as the evaluations of the forward map in eksobj.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"A typical use of the update_ensemble! function given the EKS object eksobj, the dynamical model Ψ, and the observation map H (the latter two are assumed to be defined elsewhere, e.g. in a separate module) may look as follows:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"# Given:\n# Ψ (some black box simulator)\n# H (some observation of the simulator output)\n# prior (prior distribution and parameter constraints)\n\nN_iter = 100 # Number of iterations\n\nfor n in 1:N_iter\n ϕ_n = get_ϕ_final(prior, eksobj) # Get current ensemble in constrained \"ϕ\"-space\n G_n = [H(Ψ(ϕ_n[:, i])) for i in 1:J] # Evaluate forward map\n g_ens = hcat(G_n...) # Reformat into `d x N_ens` matrix\n update_ensemble!(eksobj, g_ens) # Update ensemble\nend","category":"page"},{"location":"ensemble_kalman_sampler/#Solution","page":"Ensemble Kalman Sampler","title":"Solution","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The solution of the EKS algorithm is an approximate Gaussian distribution whose mean (θ_post) and covariance (Γ_post) can be extracted from the ''final ensemble'' (i.e., after the last iteration). The sample mean of the last ensemble is also the \"optimal\" parameter (θ_optim) for the given calibration problem. These statistics can be accessed as follows:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"# mean of the Gaussian distribution, the optimal parameter in computational θ-space\nθ_post = get_u_mean_final(eksobj)\n# (empirical) covariance of the Gaussian distribution in computational θ-space\nΓ_post = get_u_cov_final(eksobj)","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"To obtain samples of this approximate posterior in the constrained space, we first sample the distribution, then transform using the constraints contained within the prior ","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"using Random, Distributions\n\nten_post_samples = rand(MvNormal(θ_post,Γ_post), 10)\nten_post_samples_phys = transform_unconstrained_to_constrained(prior, ten_post_samples) # the optimal physical parameter value","category":"page"},{"location":"examples/sinusoid_example_toml/#TOML-interface-for-fitting-parameters-of-a-sinusoid","page":"TOML interface","title":"TOML interface for fitting parameters of a sinusoid","text":"","category":"section"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Here we revisit the simple sinusoid example, with the purpose of demonstrating how the EKP tools can interact with models in a non-intrusive fashion. In particular, this example will be useful for users whose model is written in another language, requires HPC management, or requires additional data processing stages.","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"We can generally orchestrate the different stages of the calibration process using a script file. Here we employ a Linux bash script:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"> bash calibrate_script","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Which executes the following sequence of processes (in this case, calls to julia --project)","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"# generate data\njulia --project generate_data.jl \n\n# create initial ensemble and build EKI\njulia --project initialize_EKP.jl \n\n# the EKI loop\nfor i in $(seq 1 $N_iterations); do\n\n # run the model at each ensemble member\n for j in $(seq 1 $N_ensemble); do\n julia --project run_computer_model.jl $i $j\n done\n\n # update the ensemble with EKI\n julia --project update_EKP.jl $i\n \ndone","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"The interaction between the calibration tools and the forward map are only through simple readable files stored in a nested file structure: for iteration i, ensemble member j","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Parameter values are stored (with their priors) in output/iteration_i/member_j/parameters.toml\nComputer model outputs are stored in output/iteration_i/member_j/model_output.jld2","category":"page"},{"location":"examples/sinusoid_example_toml/#Inputs-and-Outputs","page":"TOML interface","title":"Inputs and Outputs","text":"","category":"section"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"The prior distributions are provided in priors.toml in TOML format.","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"[amplitude]\nprior = \"Parameterized(Normal(0.5815754049028404, 0.47238072707743883))\"\nconstraint = \"bounded_below(0.0)\"\ndescription = \"\"\"\nThe amplitude of the sine curve.\nThis yields a physical prior that is log-normal with approximate (mean,sd) = (2,1)\n\"\"\"\n\n[vert_shift]\nprior = \"Parameterized(Normal(0,5))\"\nconstraint = \"no_constraint()\"\ndescription = \"\"\"\nThe vertical shift of the sine curve.\nThis yields a physical prior that is Normal with (mean,sd) = (0,5)\n\"\"\"","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"More information on the priors and constraints are given here. More examples defining priors in TOML format may be found in test/TOMLInterface/toml/.","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"After running the example, (it takes several minutes to run), results are stored in output/eki.jld2. To view the results, one can interact with the stored objects by loading julia --project and proceeding as follows:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"julia> using EnsembleKalmanProcesses, JLD2\n\njulia> @load \"output/eki.jld2\"\n3-element Vector{Symbol}:\n :eki\n :param_dict\n :prior","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Then, for example, the final 6-member parameter ensemble is retrieved with:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"julia> get_ϕ_final(prior,eki)\n2×6 Matrix{Float64}:\n 1.38462 1.36124 1.32444 1.26686 1.33462 1.3636\n 6.51158 6.31867 6.68542 6.12809 6.44726 6.52448","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"while the initial ensemble is retrieved with:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"julia> get_ϕ(prior, eki, 1)\n2×6 Matrix{Float64}:\n 1.05344 1.67949 6.29847 0.951586 2.07678 1.62284\n -7.00616 -0.931872 -6.11603 0.984338 0.274007 -1.39082","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"note: Why is it so slow?\nThe example is slow because the forward map is written in Julia, and so 99.99% of computation for each call to julia --project is precompilation. Ensembles in Julia can be accelerated by using methods discussed here, or by compiling system images with PackageCompiler.jl, for example. This example is for instructional purposes only, and so is not optimized.","category":"page"},{"location":"inflation/#Inflation","page":"Inflation","title":"Inflation","text":"","category":"section"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Inflation is an approach that slows down collapse in ensemble Kalman methods. Two distinct forms of inflation are implemented in this package. Both involve perturbing the ensemble members following the standard update rule of the chosen Kalman process. Multiplicative inflation expands ensemble members away from their mean in a deterministic manner, whereas additive inflation hinges on the addition of stochastic noise to ensemble members.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"For both implementations, a scaling factor s is included to extend functionality to cases with mini-batching. The scaling factor s multiplies the artificial time step Delta t in the inflation equations to account for sampling error. For mini-batching, the scaling factor should be:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" s = fracBC","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"where B is the mini-batch size and C is the full dataset size.","category":"page"},{"location":"inflation/#Multiplicative-Inflation","page":"Inflation","title":"Multiplicative Inflation","text":"","category":"section"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Multiplicative inflation effectively scales parameter vectors in parameter space, such that the perturbed ensemble remains in the linear span of the original ensemble. The implemented update equation follows Huang et al, 2022 eqn. 41:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"beginaligned\n m_n+1 = m_n qquad u^j_n + 1 = m_n+1 + sqrtfrac11 - s Deltat left(u^j_n - m_n right) qquad (1)\nendaligned","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"where m is the ensemble average. In this way, the parameter covariance is inflated by a factor of frac11 - s Deltat, while the ensemble mean remains fixed.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" C_n + 1 = frac11 - s Deltat C_n qquad (2)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Multiplicative inflation can be used by flagging the update_ensemble! method as follows:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" EKP.update_ensemble!(ekiobj, g_ens; multiplicative_inflation = true, s = 1.0)","category":"page"},{"location":"inflation/#Additive-Inflation","page":"Inflation","title":"Additive Inflation","text":"","category":"section"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Additive inflation is implemented by systematically adding stochastic perturbations to the parameter ensemble in the form of Gaussian noise. Additive inflation breaks the linear subspace property, meaning the parameter ensemble can evolve outside of the span of the initial ensemble. In additive inflation, the ensemble is perturbed in the following manner after the standard Kalman update:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" u_n+1 = u_n + zeta_n qquad (3) \n zeta_n sim N(0 fracs Deltat 1 - s Deltat C_n) qquad (4)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"This inflates the parameter covariance by a factor of frac11 - s Deltat as in eqn. 2 , while the ensemble mean remains fixed.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Additive inflation can be used by flagging the update_ensemble! method as follows:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, s = 1.0)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Alternatively, the prior covariance matrix may be used to generate additive noise, following:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" zeta_n sim N(0 fracs Deltat 1 - s Deltat C_0) qquad (5)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"This results in an additive increase in the parameter covariance by fracs Deltat 1 - s Deltat * C_0 , while the mean remains fixed.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" C_n + 1 = C_n + fracs Deltat 1 - s Deltat C_0 qquad (6)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Additive inflation using the scaled prior covariance (parameter covariance of initial ensemble) can be used by flagging the update_ensemble! method as follows:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, use_prior_cov = true, s = 1.0)","category":"page"},{"location":"API/Observations/#Observations","page":"Observations","title":"Observations","text":"","category":"section"},{"location":"API/Observations/","page":"Observations","title":"Observations","text":"CurrentModule = EnsembleKalmanProcesses.Observations","category":"page"},{"location":"API/Observations/","page":"Observations","title":"Observations","text":"Observation","category":"page"},{"location":"API/Observations/#EnsembleKalmanProcesses.Observations.Observation","page":"Observations","title":"EnsembleKalmanProcesses.Observations.Observation","text":"Observation{FT <: AbstractFloat}\n\nStructure that contains the observations\n\nFields\n\nsamples::Array{Vector{FT}, 1} where FT<:AbstractFloat\nvector of observational samples, each of length sample_dim\nobs_noise_cov::Union{Nothing, LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}, FT} where FT<:AbstractFloat\ncovariance of the observational noise (assumed to be normally distributed); sample_dim x sample_dim (where sample_dim is the number of elements in each sample), or a scalar if the sample dim is 1. If not supplied, obs_noise_cov is set to a diagonal matrix whose non-zero elements are the variances of the samples, or to a scalar variance in the case of 1d samples. obs_noise_cov is set to nothing if only a single sample is provided.\nmean::Union{AbstractVector{FT}, FT} where FT<:AbstractFloat\nsample mean\ndata_names::Union{String, AbstractVector{String}}\nnames of the data\n\n\n\n\n\n","category":"type"},{"location":"installation_instructions/#Installation","page":"Installation instructions","title":"Installation","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"EnsembleKalmanProcesses.jl is a registered Julia package. You can install the latest version of EnsembleKalmanProcesses.jl through the built-in package manager. Press ] in the Julia REPL command prompt and","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"julia> ]\n(v1.7) pkg> add EnsembleKalmanProcesses\n(v1.7) pkg> instantiate","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"This will install the latest tagged release of the package.","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"info: But I wanna be on the bleeding edge...\nIf you want the most recent developer's version of the package thenjulia> ]\n(v1.7) pkg> add EnsembleKalmanProcesses#main\n(v1.7) pkg> instantiate","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"You can run the tests via the package manager by:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"julia> ]\n(v1.7) pkg> test EnsembleKalmanProcesses","category":"page"},{"location":"installation_instructions/#Cloning-the-repository","page":"Installation instructions","title":"Cloning the repository","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"If you are interested in getting your hands dirty and modifying the code then, you can also clone the repository and then instantiate, e.g.,","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> cd EnsembleKalmanProcesses.jl\n> julia --project -e 'using Pkg; Pkg.instantiate()'","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"info: Do I need to clone the repository?\nMost times, cloning the repository in not necessary. If you only want to use the package's functionality, adding the packages as a dependency on your project is enough.","category":"page"},{"location":"installation_instructions/#Running-the-test-suite","page":"Installation instructions","title":"Running the test suite","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"You can run the package's tests:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project -e 'using Pkg; Pkg.test()'","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"Alternatively, you can do this from within the repository:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project\njulia> ]\n(EnsembleKalmanProcesses) pkg> test","category":"page"},{"location":"installation_instructions/#Building-the-documentation-locally","page":"Installation instructions","title":"Building the documentation locally","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"Once the project is built, you can build the project documentation under the docs/ sub-project:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'\n> julia --project=docs/ docs/make.jl","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"The locally rendered HTML documentation can be viewed at docs/build/index.html","category":"page"},{"location":"installation_instructions/#Running-repository-examples","page":"Installation instructions","title":"Running repository examples","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"We have a selection of examples, found within the examples/ directory to demonstrate different use of our toolbox. Each example directory contains a Project.toml","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"To build with the latest EnsembleKalmanProcesses.jl release:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> cd examples/example-name/\n> julia --project -e 'using Pkg; Pkg.instantiate()'\n> julia --project example-file-name.jl","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"If you wish to run a local modified version of EnsembleKalmanProcesses.jl then try the following (starting from the EnsembleKalmanProcesses.jl package root)","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> cd examples/example-name/\n> julia --project \n> julia> ]\n> (example-name)> rm EnsembleKalmanProcesses.jl\n> (example-name)> dev ../..\n> (example-name)> instantiate","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"followed by","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project example-file-name.jl","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"EditURL = \"../../../examples/LossMinimization/loss_minimization.jl\"","category":"page"},{"location":"literated/loss_minimization/#Minimization-of-simple-loss-functions","page":"Minimization Loss","title":"Minimization of simple loss functions","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"First we load the required packages.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"using Distributions, LinearAlgebra, Random, Plots\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\nconst EKP = EnsembleKalmanProcesses","category":"page"},{"location":"literated/loss_minimization/#Loss-function-with-single-minimum","page":"Minimization Loss","title":"Loss function with single minimum","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Here, we minimize the loss function","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G₁(u) = u - u_* ","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"where u is a 2-vector of parameters and u_* is given; here u_* = (-1 1).","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"u★ = [1, -1]\nG₁(u) = [sqrt((u[1] - u★[1])^2 + (u[2] - u★[2])^2)]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We set the seed for pseudo-random number generator for reproducibility.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"rng_seed = 41\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We set a stabilization level, which can aid the algorithm convergence","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"dim_output = 1\nstabilization_level = 1e-3\nΓ_stabilization = stabilization_level * Matrix(I, dim_output, dim_output)","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The functional is positive so to minimize it we may set the target to be 0,","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G_target = [0]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/#Prior-distributions","page":"Minimization Loss","title":"Prior distributions","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"As we work with a Bayesian method, we define a prior. This will behave like an \"initial guess\" for the likely region of parameter space we expect the solution to live in. Here we define Normal(01) distributions with no constraints","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"prior_u1 = constrained_gaussian(\"u1\", 0, 1, -Inf, Inf)\nprior_u2 = constrained_gaussian(\"u1\", 0, 1, -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"note: Note\nIn this example there are no constraints, therefore no parameter transformations.","category":"page"},{"location":"literated/loss_minimization/#Calibration","page":"Minimization Loss","title":"Calibration","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We choose the number of ensemble members and the number of iterations of the algorithm","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"N_ensemble = 20\nN_iterations = 10\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The initial ensemble is constructed by sampling the prior","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"initial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We then initialize the Ensemble Kalman Process algorithm, with the initial ensemble, the target, the stabilization and the process type (for EKI this is Inversion, initialized with Inversion()).","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"ensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, G_target, Γ_stabilization, Inversion())\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Then we calibrate by (i) obtaining the parameters, (ii) calculate the loss function on the parameters (and concatenate), and last (iii) generate a new set of parameters using the model outputs:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"for i in 1:N_iterations\n params_i = get_u_final(ensemble_kalman_process)\n\n g_ens = hcat([G₁(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, g_ens)\nend","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"and visualize the results:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"u_init = get_u_prior(ensemble_kalman_process)\n\nanim_unique_minimum = @animate for i in 1:N_iterations\n u_i = get_u(ensemble_kalman_process, i)\n\n plot(\n [u★[1]],\n [u★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :red,\n label = \"optimum u⋆\",\n )\n\n plot!(\n u_i[1, :],\n u_i[2, :],\n seriestype = :scatter,\n xlims = extrema(u_init[1, :]),\n ylims = extrema(u_init[2, :]),\n xlabel = \"u₁\",\n ylabel = \"u₂\",\n markersize = 5,\n markeralpha = 0.6,\n markercolor = :blue,\n label = \"particles\",\n title = \"EKI iteration = \" * string(i),\n )\nend\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The results show that the minimizer of G_1 is u=u_*.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"gif(anim_unique_minimum, \"unique_minimum.gif\", fps = 1) # hide","category":"page"},{"location":"literated/loss_minimization/#Loss-function-with-two-minima","page":"Minimization Loss","title":"Loss function with two minima","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Now let's do an example in which the loss function has two minima. We minimize the loss function","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G₂(u) = u - v_* u - w_* ","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"where again u is a 2-vector, and v_* and w_* are given 2-vectors. Here, we take v_* = (1 -1) and w_* = (-1 -1).","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"v★ = [1, -1]\nw★ = [-1, -1]\nG₂(u) = [sqrt(((u[1] - v★[1])^2 + (u[2] - v★[2])^2) * ((u[1] - w★[1])^2 + (u[2] - w★[2])^2))]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The procedure is same as the single-minimum example above.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We set the seed for pseudo-random number generator for reproducibility,","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"rng_seed = 10\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"A positive function can be minimized with a target of 0,","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G_target = [0]","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We choose the stabilization as in the single-minimum example","category":"page"},{"location":"literated/loss_minimization/#Prior-distributions-2","page":"Minimization Loss","title":"Prior distributions","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We define the prior. We can place prior information on e.g., u₁, demonstrating a belief that u₁ is more likely to be negative. This can be implemented by setting a bias in the mean of its prior distribution to e.g., -05:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"prior_u1 = constrained_gaussian(\"u1\", -0.5, sqrt(2), -Inf, Inf)\nprior_u2 = constrained_gaussian(\"u1\", 0, sqrt(2), -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"note: Note\nIn this example there are no constraints, therefore no parameter transformations.","category":"page"},{"location":"literated/loss_minimization/#Calibration-2","page":"Minimization Loss","title":"Calibration","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We choose the number of ensemble members, the number of EKI iterations, construct our initial ensemble and the EKI with the Inversion() constructor (exactly as in the single-minimum example):","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"N_ensemble = 20\nN_iterations = 20\n\ninitial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)\n\nensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, G_target, Γ_stabilization, Inversion())","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We calibrate by (i) obtaining the parameters, (ii) calculating the loss function on the parameters (and concatenate), and last (iii) generate a new set of parameters using the model outputs:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"for i in 1:N_iterations\n params_i = get_u_final(ensemble_kalman_process)\n\n g_ens = hcat([G₂(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, g_ens)\nend","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"and visualize the results:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"u_init = get_u_prior(ensemble_kalman_process)\n\nanim_two_minima = @animate for i in 1:N_iterations\n u_i = get_u(ensemble_kalman_process, i)\n\n plot(\n [v★[1]],\n [v★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :red,\n label = \"optimum v⋆\",\n )\n\n plot!(\n [w★[1]],\n [w★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :green,\n label = \"optimum w⋆\",\n )\n\n plot!(\n u_i[1, :],\n u_i[2, :],\n seriestype = :scatter,\n xlims = extrema(u_init[1, :]),\n ylims = extrema(u_init[2, :]),\n xlabel = \"u₁\",\n ylabel = \"u₂\",\n markersize = 5,\n markeralpha = 0.6,\n markercolor = :blue,\n label = \"particles\",\n title = \"EKI iteration = \" * string(i),\n )\nend\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Our bias in the prior shifts the initial ensemble into the negative u_1 direction, and thus increases the likelihood (over different instances of the random number generator) of finding the minimizer u=w_*.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"gif(anim_two_minima, \"two_minima.gif\", fps = 1) # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"This page was generated using Literate.jl.","category":"page"},{"location":"parameter_distributions/#parameter-distributions","page":"Prior distributions","title":"Defining prior distributions","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Bayesian inference begins with an explicit prior distribution. This page describes the interface EnsembleKalmanProcesses provides for specifying priors on parameters, via the ParameterDistributions module (src/ParameterDistributions.jl).","category":"page"},{"location":"parameter_distributions/#Summary","page":"Prior distributions","title":"Summary","text":"","category":"section"},{"location":"parameter_distributions/#ParameterDistribution-objects","page":"Prior distributions","title":"ParameterDistribution objects","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"A prior is specified by a ParameterDistribution object, which has three components:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The distribution itself, given as a ParameterDistributionType object. This includes standard Julia Distributions, GaussianRandomFields as well as empirical/sample-based distributions, and thus can be univariate, multivariate or functional. To clarify, despite our use of the term \"Kalman processes,\" the prior distribution is not required to be Gaussian.\nA constraint (or array of constraints) on the domain of the distribution, given as a ConstraintType or Array{ConstraintType} object (the latter case builds a multivariate constraint as the Cartesian product of one-dimensional Constraints). This is used to enforce physical parameter values during inference: the model is never evaluated at parameter values outside the constrained region, and the posterior distribution will only be supported there.\nThe parameter name, given as a String.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"In multiparameter settings, one should define one ParameterDistribution per parameter, and then concatenate these either in the constructor or with combine_distributions. This is illustrated below and in the Example combining several distributions.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: What's up with the notation u, ϕ, and θ?\nParameters in unconstrained spaces are often denoted u or theta in the literature. In the code, method names featuring _u imply the return of a computational, unconstrained parameter.Parameters in physical/constrained spaces are often denoted mathcalT^-1(u), mathcalT^-1(theta), or phi in the literature (for some bijection mathcalT mapping to the unbounded space). In the code, method names featuring _ϕ imply the return of a physical, constrained parameter, and will always require a prior as input to perform the transformations internally.For more notations see our Glossary.","category":"page"},{"location":"parameter_distributions/#constrained-gaussian","page":"Prior distributions","title":"Recommended constructor","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"constrained_gaussian() is a streamlined constructor for ParameterDistributions which addresses the most common use case; more general forms of the constructor are documented below, but we highly recommend that users begin here when it comes to specifying priors, only using the general constructor when necessary.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Usage:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"lower_bound = 0.0\nupper_bound = 1.0\nμ_1 = 0.5\nμ_2 = 0.5\nσ_1 = 0.25\nσ_2 = 0.25","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `constrained_gaussian`, `combine_distributions`\nprior_1 = constrained_gaussian(\"param_1\", μ_1, σ_1, lower_bound, upper_bound)\nprior_2 = constrained_gaussian(\"param_2\", μ_2, σ_2, 0.0, Inf, repeats=3)\nprior = combine_distributions([prior_1, prior_2])","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior_1 is a ParameterDistribution describing a prior distribution for a parameter named \"param_1\" taking values on the interval [lower_bound, upper_bound]; the prior distribution has approximate mean μ_1 and standard deviation σ_1.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior_2 is a ParameterDistribution describing a 3-dimensional prior distribution for a parameter named \"param_2\" with each dimensions taking independent values on the half-open interval [0.0, Inf); the marginals of this prior distribution have approximate mean μ_2 and standard deviation σ_2.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The use case constrained_gaussian() addresses is when prior information is qualitative, and exact distributions of the priors are unknown: i.e., the user is only able to specify the physical and likely ranges of prior parameter values at a rough, qualitative level. constrained_gaussian() does this by constructing a ParameterDistribution corresponding to a Gaussian \"squashed\" to fit in the given constraint interval, such that the \"squashed\" distribution has the specified mean and standard deviation (e.g. prior_2 above is a log-normal for each dimension).","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The parameters of the Gaussian are chosen automatically (depending on the constraint) to reproduce the desired μ and σ — per the use case, other details of the form of the prior distribution shouldn't be important for downstream inference! ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: Slow/Failed construction?\nThe most common case of slow or failed construction is when requested parameters place too much mass at the hard boundary. A typical case is when the requested variance satisfies sigma approx mathrmdist(mumathrmboundary) Such priors can be defined, but not with our convenience constructor. If this is not the case but you still get failures please let us know!","category":"page"},{"location":"parameter_distributions/#Plotting","page":"Prior distributions","title":"Plotting","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"For quick visualization we have a plot recipe for ParameterDistribution types. This will plot marginal histograms for all dimensions of the parameter distribution. For example, ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# with values:\n# e.g. lower_bound = 0.0, upper_bound = 1.0\n# μ_1 = 0.5, σ_1 = 0.25\n# μ_2 = 0.5, σ_2 = 0.25\n\nusing Plots\nplot(prior) ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"One can also access the underlying Gaussian distributions in the unconstrained space with","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Plots\nplot(prior, constrained=false) ","category":"page"},{"location":"parameter_distributions/#Recommended-constructor-Simple-example","page":"Prior distributions","title":"Recommended constructor - Simple example","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Task: We wish to create a prior for a one-dimensional parameter. Our problem dictates that this parameter is bounded between 0 and 1; domain knowledge leads us to expect it should be around 0.7. The parameter is called point_seven.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We're told that the prior mean is 0.7; we choose a prior standard deviation of 0.15 to be sufficiently wide without putting too much mass at the upper bound. The constructor is then","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `constrained_gaussian`\nprior = constrained_gaussian(\"point_seven\", 0.7, 0.15, 0.0, 1.0)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# instead of importing ParameterDistributions & dependencies to call constructor,\n# which would make docs build longer and more fragile, simply hard-code Normal()\n# parameters found by constrained_gaussian constructor\n\nusing Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:6/400:5)\n\n#bounded in [0.0, 1.0]\ntransform_unconstrained_to_constrained(x) = 1.0 - 1.0 / (exp(x) + 1)\ndist= pdf.(Normal(0.957711, 0.78507), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np2 = plot(constrained_x_eval, dist) \nvline!([0.7]) \ntitle!(\"Prior pdf\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The pdf of the constructed prior distribution (in the physical, constrained space) looks like:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p2, legend=false, size = (450, 450)) #hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"In Simple example revisited below, we repeat this example \"manually\" with the general constructor.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: What if I want to impose the same prior on many parameters?\nThe recommended constructor can be called as constrained_gaussian(...; repeats = n) to return a combined prior formed by n identical priors.","category":"page"},{"location":"parameter_distributions/#ParameterDistribution-struct","page":"Prior distributions","title":"ParameterDistribution struct","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This section provides more details on the components of a ParameterDistribution object.","category":"page"},{"location":"parameter_distributions/#ParameterDistributionType","page":"Prior distributions","title":"ParameterDistributionType","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The ParameterDistributionType struct wraps four types for specifying different types of prior distributions:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The Parameterized type is initialized using a Julia Distributions.jl object. Samples are drawn randomly from the distribution object.\nThe VectorOfParameterized type is initialized with a vector of distributions.\nThe Samples type is initialized using a two dimensional array. Samples are drawn randomly (with replacement) from the columns of the provided array.\nThe FunctionParameterDistributionType struct defines parameters specified as fields over a domain. More detail can be found here.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"warning: Warning\nWe recommend that the distributions be unbounded (see next section), as the filtering algorithms in EnsembleKalmanProcesses are not guaranteed to preserve constraints unless defined through the ConstraintType mechanism.","category":"page"},{"location":"parameter_distributions/#ConstraintType","page":"Prior distributions","title":"ConstraintType","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The inference algorithms implemented in EnsembleKalmanProcesses assume unbounded parameter domains. To be able to handle constrained parameter values consistently, the ConstraintType defines a bijection between the physical, constrained parameter domain and an unphysical, unconstrained domain in which the filtering takes place. This bijection is specified by the functions transform_constrained_to_unconstrained and transform_unconstrained_to_constrained, which are built from either predefined constructors or user-defined constraint functions given as arguments to the ConstraintType constructor. ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We provide the following predefined constructors which implement mappings that handle the most common constraints:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"no_constraint(): The parameter is unconstrained and takes values in (-∞, ∞) (mapping is the identity).\nbounded_below(lower_bound): The parameter takes values in [lower_bound, ∞).\nbounded_above(upper_bound): The parameter takes values in (-∞, upper_bound].\nbounded(lower_bound,upper_bound): The parameter takes values on the interval [lower_bound, upper_bound].","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"These are demonstrated in ConstraintType Examples.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Currently we only support multivariate constraints which are the Cartesian product of the one-dimensional ConstraintTypes. Every component of a multidimensional parameter must have an associated constraint, so, e.g. for a multivariate ParameterDistributionType of dimension p the user must provide a p-dimensional Array{ConstraintType}. A VectorOfParameterized distribution built with distributions of dimension p and q has dimension p+q.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: Note\nWhen a nontrivial ConstraintType is given, the general constructor assumes the ParameterDistributionType is specified in the unconstrained space; the actual prior pdf is then the composition of the ParameterDistributionType's pdf with the transform_unconstrained_to_constrained transformation. We provide constrained_gaussian to define priors directly in the physical, constrained space.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"warning: Warning\nIt is up to the user to ensure any custom mappings transform_constrained_to_unconstrained and transform_unconstrained_to_constrained are inverses of each other.","category":"page"},{"location":"parameter_distributions/#The-name","page":"Prior distributions","title":"The name","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This is simply a String used to identify different parameters in multi-parameter situations, as in the methods below.","category":"page"},{"location":"parameter_distributions/#function-parameter-type","page":"Prior distributions","title":"FunctionParameterDistributionType","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Learning a function distribution is useful when one wishes to obtain a parametric representation of a function that is (relatively) agnostic of the underlying grid discretization. Most practical implementations involve posing a restrictive class of functions by truncation of a spectral decomposition. The function is then represented as a set of coefficients of these modes (known as degrees of freedom), rather than directly through the values at evaluation points.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"As a subtype of ParameterDistributionType, we currently support one option for specifying prior distributions over functions:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The GaussianRandomFieldInterface type is initialized with a Gaussian Random Field object and the GRF package. Currently we support objects from GaussianRandomFields.jl with package GRFJL(). Gaussian random fields allow the definition of scalar function distributions defined over a uniform mesh on interval, rectangular, and hyper-rectangular domains.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"As with other ParameterDistributions, a function distribution, is built from a name, a FunctionPameterDistributionType struct and a constraint, here only one, placed on the scalar output space of the function using a Constraint().","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: constraints\nThe transformation transform_unconstrained_to_constrained, will map from (unconstrained) degrees of freedom, to (constrained) evaluations of the function on a numerical grid. In particular, the transform_constrained_to_unconstrained is no longer the inverse of this map, it now simply maps from constrained evaluations to unconstrained evaluations on the grid.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We provide an example construction here.","category":"page"},{"location":"parameter_distributions/#ParameterDistribution-constructor","page":"Prior distributions","title":"ParameterDistribution constructor","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The Recommended constructor, constrained_gaussian(), is described above. For more general cases in which the prior needs to be specified in more detail, a ParameterDistribution may be constructed \"manually\" from its component objects:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`, `combine_distributions`\nusing Distributions\ndistribution_1 = Parameterized(Normal(0,1))\ndistribution_2 = Parameterized(Normal(0,1))\nconstraint_1 = no_constraint()\nconstraint_2 = no_constraint()\nname_1 = \"m\"\nname_2 = \"mm\"","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`, `combine_distributions`\nprior_1 = ParameterDistribution(distribution_1, constraint_1, name_1)\nprior_2 = ParameterDistribution(distribution_2, constraint_2, name_2)\nprior = combine_distributions( [prior_1, prior_2])\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Arguments may also be provided as a Dict:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`\ndict_1 = Dict(\"distribution\" => distribution_1, \"constraint\" => constraint_1, \"name\" => name_1)\ndict_2 = Dict(\"distribution\" => distribution_2, \"constraint\" => constraint_2, \"name\" => name_2)\nprior = ParameterDistribution( [dict_1, dict_2] )\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We provide Additional Examples below; see also examples in the package examples/ and unit tests found in test/ParameterDistributions/runtests.jl.","category":"page"},{"location":"parameter_distributions/#ParameterDistribution-methods","page":"Prior distributions","title":"ParameterDistribution methods","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"These functions typically return a Dict with ParameterDistribution.name as a keys, or an Array if requested:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"get_name: returns the name(s) of parameters in the ParameterDistribution.\nget_distribution: returns the distributions (ParameterDistributionType objects) in the ParameterDistribution. Note that this is not the prior pdf used for inference if nontrivial constraints have been applied.\nmean, var, cov, sample, logpdf: mean, variance, covariance, logpdf or samples the Julia Distribution if Parameterized, or draws from the list of samples if Samples. Extends the StatsBase definitions. Note that these do not correspond to the prior pdf used for inference if nontrivial constraints have been applied.\ntransform_unconstrained_to_constrained: Applies the constraint mappings.\ntransform_constrained_to_unconstrained: Applies the inverse constraint mappings.","category":"page"},{"location":"parameter_distributions/#Additional-Examples","page":"Prior distributions","title":"Additional Examples","text":"","category":"section"},{"location":"parameter_distributions/#Simple-example-revisited","page":"Prior distributions","title":"Simple example revisited","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"To illustrate what the constrained_gaussian constructor is doing, in this section we repeat the Recommended constructor - Simple example given above, using the \"manual,\" general-purpose constructor. Let's bring in the packages we will require","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `bounded`, `Parameterized`, and `ParameterDistribution` \nusing Distributions # for `Normal`\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Then we initialize the constraint first,","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"constraint = bounded(0, 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This defines the following transformation to the constrained space (and also its inverse)","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = exp(x) / (exp(x) + 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The prior mean should be around 0.7 (in the constrained space), and one can find that the push-forward of a particular normal distribution, namely, transform_unconstrained_to_constrained(Normal(mean = 1, sd = 0.5)) gives a prior pdf with 95% of its mass between [0.5, 0.88]. ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This is the main difference from the use of the constrained_gaussian constructor: in that example, the constructor numerically solved for the parameters of the Normal() which would reproduce the requested μ, σ for the physical, constrained quantity (since no closed-form transformation for the moments exists.)","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"distribution = Parameterized(Normal(1, 0.5))\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Finally we attach the name","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"name = \"point_seven\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"and the distribution is created by either:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior = ParameterDistribution(distribution, constraint, name)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"or","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior_dict = Dict(\"distribution\" => distribution, \"constraint\" => constraint, \"name\" => name)\nprior = ParameterDistribution(prior_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-3:6/400:3)\n\n#bounded in [0.0, 1.0]\ntransform_unconstrained_to_constrained(x) = exp(x) / (exp(x) + 1)\ndist= pdf.(Normal(1, 0.5), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(x_eval, dist,) \nvline!([1.0]) \ntitle!(\"Normal(1, 0.5)\")\n\np2 = plot(constrained_x_eval, dist) \nvline!([transform_unconstrained_to_constrained(1.0)]) \ntitle!(\"Constrained Normal(1, 0.5)\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The pdf of the Normal distribution and its transform to the physical, constrained space are:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p1, p2, legend=false, size = (900, 450)) #hide","category":"page"},{"location":"parameter_distributions/#samples-example","page":"Prior distributions","title":"Sample-based distribution","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We repeat the work of Simple example revisited, but now assuming that to create our prior, we only have samples given by the histogram:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# instead of importing ParameterDistributions & dependencies to call constructor,\n# which would make docs build longer and more fragile, simply hard-code Normal()\n# parameters found by constrained_gaussian constructor\n\nusing Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 5000\n\n#bounded in [0.0, 1.0]\ntransform_unconstrained_to_constrained(x) = 1.0 - 1.0 / (exp(x) + 1)\nsamples = rand(Normal(0.957711, 0.78507), N)\nconstrained_samples = transform_unconstrained_to_constrained.(samples)\n\np3 = histogram(constrained_samples, bins=50) \nvline!([0.7]) \ntitle!(\"Prior of samples\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p3, legend=false, size = (450, 450)) #hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Imagine we do not know this distribution is bounded. To create a ParameterDistribution one can take a matrix constrained_samples whose columns are this data:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Samples`, `no_constraint`, `ParameterDistribution`, `bounded`\nconstrained_samples = [0.1 0.2 0.3 0.4] # hide\ndistribution = Samples(constrained_samples)\nconstraint = no_constraint()\nname = \"point_seven\"\nprior = ParameterDistribution(distribution, constraint, name)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: Note\nThis naive implementation will not enforce any boundaries during the algorithm implementation.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Imagine that we know about the boundedness of this distribution, then, as in Simple example revisited, we define the constraint","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"constraint = bounded(0, 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"which stores the transformation:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"unconstrained_samples = constraint.constrained_to_unconstrained.(constrained_samples)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This maps the samples into an unbounded space, giving the following histogram:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# instead of importing ParameterDistributions & dependencies to call constructor,\n# which would make docs build longer and more fragile, simply hard-code Normal()\n# parameters found by constrained_gaussian constructor\n\nusing Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 5000\n\n# bounded in [0.0, 1.0]\n# transform_unconstrained_to_constrained(x) = 1.0 - 1.0 / (exp(x) + 1.0)\n transform_constrained_to_unconstrained(x) = log(1.0 / (1.0 - x) - 1.0)\nunconstrained_samples = rand(Normal(0.957711, 0.78507), N)\n\np3 = histogram(unconstrained_samples, bins=50) \nvline!([transform_constrained_to_unconstrained(0.7)]) \ntitle!(\"Prior of samples\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p3, legend=false, size = (450, 450)) #hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"As before we define a Samples distribution from matrix whose columns are the (now unconstrained) samples, along with a name to create the ParameterDistribution.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"distribution = Samples(unconstrained_samples)\nname = \"point_seven\"\nprior = ParameterDistribution(distribution, constraint, name)\nnothing # hide","category":"page"},{"location":"parameter_distributions/#Example-combining-several-distributions","page":"Prior distributions","title":"Example combining several distributions","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"To show how to combine priors in a more complex setting (e.g. for an entire parametrized process), we create a 25-dimensional parameter distribution from three dictionaries.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Bring in the packages!","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions\n# for `bounded_below`, `bounded`, `Constraint`, `no_constraint`,\n# `Parameterized`, `Samples`,`VectorOfParameterized`,\n# `ParameterDistribution`, `combine_distributions`\nusing LinearAlgebra # for `SymTridiagonal`, `Matrix`\nusing Distributions # for `MvNormal`, `Beta`\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The first parameter is a 3-dimensional distribution, with the following bound constraints on parameters in physical space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"c1 = repeat([bounded_below(0)], 3)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We know that a multivariate normal represents its distribution in the transformed (unbounded) space. Here we take a tridiagonal covariance matrix.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"diagonal_val = 0.5 * ones(3)\nudiag_val = 0.25 * ones(2)\nmean = ones(3)\ncovariance = Matrix(SymTridiagonal(diagonal_val, udiag_val))\nd1 = Parameterized(MvNormal(mean, covariance)) # 3D multivariate normal\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We also provide a name","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"name1 = \"constrained_mvnormal\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The second parameter is a 2-dimensional one. It is only given by 4 samples in the transformed space - (where one will typically generate samples). It is bounded in the first dimension by the constraint shown, there is a user provided transform for the second dimension - using the default constructor.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"d2 = Samples([1.0 5.0 9.0 13.0; 3.0 7.0 11.0 15.0]) # 4 samples of 2D parameter space\n\ntransform = (x -> 3 * x + 14)\njac_transform = (x -> 3)\ninverse_transform = (x -> (x - 14) / 3)\nabstract type Affine <: ConstraintType end\n\nc2 = [bounded(10, 15),\n Constraint{Affine}(transform, jac_transform, inverse_transform, nothing)]\nname2 = \"constrained_sampled\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The final parameter is 4-dimensional, defined as a list of i.i.d univariate distributions we make use of the VectorOfParameterized type","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"d3 = VectorOfParameterized(repeat([Beta(2,2)],4))\nc3 = repeat([no_constraint()],4)\nname3 = \"Beta\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The full prior distribution for this setting is created either through building simple distributions and combining","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"u1 = ParameterDistribution(d1, c1, name1)\nu2 = ParameterDistribution(d2, c2, name2)\nu3 = ParameterDistribution(d3, c3, name3)\nu = combine_distributions( [u1, u2, u3])\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"or an array of the parameter specifications as dictionaries.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"param_dict1 = Dict(\"distribution\" => d1, \"constraint\" => c1, \"name\" => name1)\nparam_dict2 = Dict(\"distribution\" => d2, \"constraint\" => c2, \"name\" => name2)\nparam_dict3 = Dict(\"distribution\" => d3, \"constraint\" => c3, \"name\" => name3)\nu = ParameterDistribution([param_dict1, param_dict2, param_dict3])\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We can visualize the marginals of the constrained distributions,","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Plots\nplot(u)","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"and the unconstrained distributions similarly,","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Plots\nplot(u, constrained = false)","category":"page"},{"location":"parameter_distributions/#function-example","page":"Prior distributions","title":"Function Distribution Example","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Here, define a function parameter distribution on 01 times 12 , bounded by -5-3 and with correlation lengthscales 0.05. First, we get the packages:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # For `ParameterDistribution`\nusing Random, Distributions # for `rand` and `Normal`\nusing Plots\n# We must `import` the GRF package, rather than call a `using` statement here\nimport GaussianRandomFields # for `GaussianRandomFields`","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"then, we use the GaussianRandomFields.jl package to define the distribution of choice. This distribution is unbounded. Here we take a Matern kernel, and define our evaluation grid on the domain. We choose 30 degrees of freedom (dofs), so this function distribution is specified through the value of 30 learnable coefficients. ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"const GRF = GaussianRandomFields\n# Define a `GaussianRandomFields` object\ninput_dim = 2 # Define a 2D -> 1D function\ndofs = 30 # the number of modes defining the distribution\npoints = [collect(0:0.01:1), collect(1:0.02:2)] # the 2D domain grid (uniform in each dimension)\n\ngrfjl_obj = GRF.GaussianRandomField(\n GRF.CovarianceFunction(input_dim, GRF.Matern(0.05, 2)),\n GRF.KarhunenLoeve(dofs),\n points...,\n) # the Gaussian Random Field object from the package\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We define our parameter distribution wrapper, where GRFJL() indicates the GRF package used. We also impose bounds into an interval -5-3 (here applied to the output space).","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"grf = GaussianRandomFieldInterface(grfjl_obj, GRFJL()) # our wrapper\npd = ParameterDistribution(\n Dict(\n \"distribution\" => grf,\n \"constraint\" => bounded(-5, -3), \n \"name\" => \"func_in_min5_min3\",\n )\n) # The ParameterDistribution with constraint in the output space\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We plot 4 samples of this distribution. Samples are taken over the (30-dimensional) degrees of freedom, and then we apply the transform_unconstrained_to_costrained map to (i) build the function distribution, (ii) evaluate it on the numerical grid, and (iii) constrain the output with our prescribed bounds.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"shape = [length(pp) for pp in points]\nsamples_constrained_flat = [transform_unconstrained_to_constrained(pd, rand(Normal(0,1), dofs)) for i = 1:4] \nplts = [contour(points..., reshape(samples_constrained_flat[i], shape...)', fill = true,) for i =1:4]\nplot(plts..., legend=false, size=(800,800)) ","category":"page"},{"location":"parameter_distributions/#ConstraintType-Examples","page":"Prior distributions","title":"ConstraintType Examples","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"For each for the predefined ConstraintTypes, we present animations of the resulting constrained prior distribution for","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions, Distributions # hide\nμ = 0 # hide\nσ = 1 # hide\ndistribution = Parameterized(Normal(μ, σ))\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where we vary μ and σ respectively. As noted above, in the presence of a nontrivial constraint, μ and σ will no longer correspond to the mean and standard deviation of the prior distribution (which is taken in the physical, constrained space).","category":"page"},{"location":"parameter_distributions/#Without-constraints:-\"constraint\"-no_constraints()","page":"Prior distributions","title":"Without constraints: \"constraint\" => no_constraints()","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior based on an unconstrained Normal(0.5, 1) distribution:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `no_constraint`, `ParameterDistribution`\nusing Distributions # for `Normal`\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => no_constraint(),\n\"name\" => \"unbounded_parameter\",\n)\n\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where no_constraint() automatically defines the identity constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = x\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the constrained space (which is trivial here):","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:10/200:5)\nmean_varying = collect(-3:6/(N+1):3)\nsd_varying = collect(0.1:2.9/(N+1):3)\n\n# no constraint\ntransform_unconstrained_to_constrained(x) = x\n\nmean0norm(n) = pdf.(Normal(0, sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1, p2, layout=(1, 2), size = (900, 450), legend = false)\n \nanim_unbounded = @animate for n = 1:length(mean_varying)\n #set new y data \n p[1][1][:y] = mean0norm(n) \n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\" \n p[2][1][:y] = sd1norm(n) \n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_unbounded, \"anim_unbounded.gif\", fps = 5) # hide","category":"page"},{"location":"parameter_distributions/#Bounded-below-by-0:-\"constraint\"-bounded_below(0)","page":"Prior distributions","title":"Bounded below by 0: \"constraint\" => bounded_below(0)","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior for a parameter which is bounded below by 0 (i.e. its only physical values are positive), and which has a Normal(0.5, 1) distribution in the unconstrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `bounded_below`, `ParameterDistribution`\nusing Distributions # for `Normal`\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => bounded_below(0),\n\"name\" => \"bounded_below_parameter\",\n)\n\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where bounded_below(0) automatically defines the constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = exp(x)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the physical, constrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:10/400:5)\nmean_varying = collect(-1:5/(N+1):4)\nsd_varying = collect(0.1:3.9/(N+1):4)\n\n#bounded below by 0\ntransform_unconstrained_to_constrained(x) = exp(x)\n\nmean0norm(n) = pdf.(Normal(0,sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1,p2, layout=(1,2), size = (900,450), legend=false)\n \nanim_bounded_below = @animate for n = 1:length(mean_varying) \n #set new y data \n p[1][1][:y] = mean0norm(n) \n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\"\n p[2][1][:y] = sd1norm(n) \n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_bounded_below, \"anim_bounded_below.gif\", fps = 5) # hide","category":"page"},{"location":"parameter_distributions/#Bounded-above-by-10.0:-\"constraint\"-bounded_above(10)","page":"Prior distributions","title":"Bounded above by 10.0: \"constraint\" => bounded_above(10)","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior for a parameter which is bounded above by ten, and which has a Normal(0.5, 1) distribution in the unconstrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `bounded_above`, `ParameterDistribution`\nusing Distributions\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => bounded_above(10),\n\"name\" => \"bounded_above_parameter\",\n)\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where bounded_above(10) automatically defines the constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = 10 - exp(-x)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the physical, constrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:4/400:5)\nmean_varying = collect(-1:5/(N+1):4)\nsd_varying = collect(0.1:3.9/(N+1):4)\n\n#bounded above by 10.0\ntransform_unconstrained_to_constrained(x) = 10 - exp(-x)\n\nmean0norm(n) = pdf.(Normal(0, sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1, p2, layout=(1, 2), size = (900, 450), legend=false)\n \nanim_bounded_above = @animate for n = 1:length(mean_varying)[1]\n #set new y data\n p[1][1][:y] = mean0norm(n)\n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\"\n p[2][1][:y] = sd1norm(n)\n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_bounded_above, \"anim_bounded_above.gif\", fps = 5) # hide","category":"page"},{"location":"parameter_distributions/#Bounded-between-5-and-10:-\"constraint\"-bounded(5,-10)","page":"Prior distributions","title":"Bounded between 5 and 10: \"constraint\" => bounded(5, 10)","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior for a parameter whose physical values lie in the range between 5 and 10, and which has a Normal(0.5, 1) distribution in the unconstrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions# for `Parameterized`, `bounded`, `ParameterDistribution`\nusing Distributions # for `Normal`\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => bounded(5, 10),\n\"name\" => \"bounded_parameter\",\n)\n\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where bounded(-1, 5) automatically defines the constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = 10 - 5 / (exp(x) + 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the physical, constrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-10:20/400:10)\nmean_varying = collect(-3:2/(N+1):3)\nsd_varying = collect(0.1:0.9/(N+1):10)\n\n#bounded in [5.0, 10.0]\ntransform_unconstrained_to_constrained(x) = 10 - 5 / (exp(x) + 1)\n\nmean0norm(n) = pdf.(Normal(0, sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1, p2, layout=(1, 2), size = (900, 450), legend=false)\n \nanim_bounded = @animate for n = 1:length(mean_varying)\n #set new y data\n p[1][1][:y] = mean0norm(n)\n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\"\n p[2][1][:y] = sd1norm(n)\n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_bounded, \"anim_bounded.gif\", fps = 10) # hide","category":"page"},{"location":"internal_data_representation/#Wrapping-up-data","page":"Internal data representation","title":"Wrapping up data","text":"","category":"section"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"To provide a consistent form for data (such as observations, parameter ensembles, model evaluations) across the package, we store the data in simple wrappers internally.","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"Data is always stored as columns of AbstractMatrix. That is, we obey the format","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"[ data dimension x number of data samples ]","category":"page"},{"location":"internal_data_representation/#The-DataContainer","page":"Internal data representation","title":"The DataContainer","text":"","category":"section"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"A DataContainer is constructed initially by copying and perhaps transposing matrix data","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"dc = DataContainer(abstract_matrix; data_are_columns = true)","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"The flag data_are_columns indicates whether the provided data is stored column- or row-wise. The data is retrieved with","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"get_data(dc)","category":"page"},{"location":"internal_data_representation/#The-PairedDataContainer","page":"Internal data representation","title":"The PairedDataContainer","text":"","category":"section"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"A PairedDataContainer stores pairs of inputs and outputs in the form of DataContainers. It is constructed from two data matrices, or from two DataContainers.","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"pdc = PairedDataContainer(input_matrix, output_matrix; data_are_columns = true)\npdc = PairedDataContainer(input_data_container, output_data_container)","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"Data is retrieved with","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"get_data(pdc) # returns both inputs and outputs\nget_inputs(pdc)\nget_outputs(pdc)","category":"page"},{"location":"learning_rate_scheduler/#learning-rate-schedulers","page":"Learning rate schedulers","title":"Learning Rate Schedulers (a.k.a) Timestepping","text":"","category":"section"},{"location":"learning_rate_scheduler/#Overview","page":"Learning rate schedulers","title":"Overview","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"We demonstrate the behaviour of different learning rate schedulers through solution of a nonlinear inverse problem.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"In this example we have a model that produces the exponential of a sinusoid f(A v) = exp(A sin(t) + v) forall t in 02pi. Given an initial guess of the parameters as A^* sim mathcalN(21) and v^* sim mathcalN(025), the inverse problem is to estimate the parameters from a noisy observation of only the maximum and mean value of the true model output.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"We shall compare the following configurations of implemented schedulers. ","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Fixed, \"long\" timestep DefaultScheduler(0.5) - orange\nFixed, \"short\" timestep DefaultScheduler(0.02) - green\nAdaptive timestep (designed originally to ensure EKS remains stable) EKSStableScheduler() Kovachki & Stuart 2018 - red\nMisfit controlling timestep (Terminating) DataMisfitController() Iglesias & Yang 2021 - purple\nMisfit controlling timestep (Continuing beyond Terminate condition) DataMisfitController(on_terminate=\"continue\") - brown","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"One can define the schedulers as","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"scheduler = DefaultScheduler(0.5) # fixed stepsize, default values: 1","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Then when constructing an EnsembleKalmanProcess, one uses the keyword argument","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"ekpobj = EKP.EnsembleKalmanProcess(args...; scheduler = scheduler, kwargs...)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"A variety of other schedulers can be defined similarly:","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"scheduler = MutableScheduler(2) # modifiable stepsize\nscheduler = EKSStableScheduler(numerator=10.0, nugget = 0.01) # Stable for EKS\nscheduler = DataMisfitController(on_terminate = \"continue\") # non-terminating","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Please see the learning rate schedulers API for defaults and other details","category":"page"},{"location":"learning_rate_scheduler/#Early-termination","page":"Learning rate schedulers","title":"Early termination","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Early termination can be implemented in the calibration loop as ","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"using EnsembleKalmanProcesses # for get_ϕ_final, update_ensemble!\n# given\n# * the number of iterations `N_iter`\n# * a prior `prior`\n# * a forward map `G`\n# * the EKP object `ekpobj`\n\nfor i in 1:N_iter\n params_i = get_ϕ_final(prior, ekpobj)\n g_ens = G(params_i)\n terminated = update_ensemble!(ekpobj, g_ens) # check for termination\n if !isnothing(terminated) # if termination is flagged, break the loop\n break\n end\nend ","category":"page"},{"location":"learning_rate_scheduler/#Timestep-and-termination-time","page":"Learning rate schedulers","title":"Timestep and termination time","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Recall, for example for EKI, we perform updates of our ensemble of parameters j=1dotsJ at step n = 1dotsN_mathrmit using","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"theta_n+1^(j) = theta_n^(j) - dfracDelta t_nJsum_k=1^J left langle mathcalG(theta_n^(k)) - barmathcalG_n Gamma_y^-1 left ( mathcalG(theta_n^(j)) - y right ) right rangle theta_n^(k)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"where barmathcalG_n is the mean value of mathcalG(theta_n) across ensemble members. We denote the current time t_n = sum_i=1^nDelta t_i, and the termination time as T = t_N_mathrmit.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"note: Note\nAdaptive Schedulers typically try to make the biggest update that controls some measure of this update. For example, EKSStableScheduler() controls the frobenius norm of the update, while DataMisfitController() controls the Jeffrey divergence between the two steps. Largely they follow a pattern of scheduling very small initial timesteps, leading to much larger steps at later times.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"There are two termination times that the theory indicates are useful","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"T=1: In the linear Gaussian case, the theta_N_mathrmit will represent the posterior distribution. In nonlinear case it should still provide an approximation to the posterior distribution. Note that as the posterior does not necessarily optimize the data-misfit we find bartheta_N_mathrmit (the ensemble mean) provides a conservative estimate of the true parameters, while retaining spread. It is noted in Iglesias & Yang 2021 that with small enough (or well chosen) step-sizes this estimate at T=1 satisfies a discrepancy principle with respect to the observational noise.\nTto infty: Though theoretical concerns have been made with respect to continuation beyond T=1 for inversion methods such as EKI, in practice we commonly see better optimization of the data-misfit, and thus better representation bartheta_N_mathrmit to the true parameters. As expected this procedure leads to ensemble collapse, and so no meaningful information can be taken from the posterior spread, and the optimizer is not likely to be the posterior mode.","category":"page"},{"location":"learning_rate_scheduler/#The-experiment-with-EKI-and-UKI","page":"Learning rate schedulers","title":"The experiment with EKI & UKI","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"We assess the schedulers by solving the inverse problem with EKI and UKI (we average results over 100 initial ensembles in the case of EKI). We will not draw comparisons between EKI and UKI here, rather we use them to observe consistent behavior in the schedulers. Shown below are the solution plots of one solve with each timestepper, for both methods. ","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"(Image: Solution EKI) (Image: Solution UKI)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Top: EKI, Bottom: UKI. Left: The true model over 02pi (black), and solution schedulers (colors). Right: The noisy observation (black) of mean and max of the model; the distribution it was sampled from (gray-ribbon), and the corresponding ensemble-mean approximation given from each scheduler (colors).","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"To assess the timestepping we show the convergence plot against the algorithm iteration we measure two quantities.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"error (solid) is defined by frac1N_enssum^N_ens_i=1 theta_i - theta^* ^2 where theta_i are ensemble members and theta^* is the true value used to create the observed data.\nspread (dashed) is defined by frac1N_enssum^N_ens_i=1 theta_i - bartheta ^2 where theta_i are ensemble members and bartheta is the mean over these members.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"(Image: Error vs spread EKI) (Image: Error vs spread UKI)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Top: EKI. Bottom: UKI. Left: the error and spread of the different timesteppers at over iterations of the algorithm for a single run. Right: the error and spread of the different timesteppers at their final iterations, (for EKI, averaged from 100 initial conditions).","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Finding the Posterior (terminating at T=1):","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"DMC with termination (purple), closely mimics a small-fixed timestep (green) that finishes stepping at T=1. Both retain more spread than other approaches, and DMC is far more efficient, typically terminating after around 10-20 steps, where fixed-stepping takes 50. We see that (for this experiment) this is a conservative estimate, as continuing to solve (e.g. brown) until later times often leads to a better error while still retaining similar \"error vs spread\" curves (before inevitable collapse). This is consistent with the concept of approximating the posterior, over seeking an optimizer.\nThe behavior observed in UKI is similar to EKI","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Optimizing the objective function (continuing T to infty):","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Large fixed step (orange). This is very efficient, but can get stuck when drawn too large, (perhaps unintuitive from a gradient-descent perspective). It typically also collapses the ensemble. On average it gives lower error to the true parameters than DMC. \nBoth EKSStable and DMC with continuation schedulers, perform very similarly. Both retain good ensemble spread during convergence, and collapse after finding a local optimum. This optimum on average has the best error to the true parameters in this experiment. They appear to consistently find the same optimum as Ttoinfty but DMC finds this in fewer iterations.\nThe UKI behavior is largely similar to EKI here, except that ensemble spread is retained in the Ttoinfty limit in all cases, from inflation of the parameter covariance (Sigma_omega) within our implementation. ","category":"page"},{"location":"learning_rate_scheduler/#DMC-as-a-default-in-future?","page":"Learning rate schedulers","title":"DMC as a default in future?","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"This experiment motivates the possibility of making DMC (with/without) continuation a default timestepper in future releases, for EKI/SEKI/UKI. Currently we will retain constant timestepping as default while we investigate further.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"warning: Ensemble Kalman Sampler\nWe observe blow-up in EKS, when not using the EKSStableScheduler.","category":"page"},{"location":"examples/darcy/#Learning-the-permiability-field-in-a-Darcy-flow","page":"Darcy flow","title":"Learning the permiability field in a Darcy flow","text":"","category":"section"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"In this example, we illustrate a simple function learning problem. We are presented with an unknown field that is discretized with a finite-dimensional approximation (e.g. spatial discretization). When learning this field, if one represents each pointwise value at a gridpoint as a parameter, increasing the spatial resolution leads to increasingly high dimensional learning problems, thus giving poor computational scaling and increasingly ill-posed inverse problems from fixed data. If instead, we treat the approximation as a discretized function living in a function space, then one can learn coefficients of a basis of this function space. Since it is commonly the case that functions have relatively low effective dimension in this space, the dependence on the spatial discretization only arises in discretization error, which vanishes as resolution is increased.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We will solve for an unknown permeability field kappa governing the pressure field of a Darcy flow on a square 2D domain. To learn about the permeability we shall take few pointwise measurements of the solved pressure field within the domain. The forward solver is a simple finite difference scheme taken and modified from code here.","category":"page"},{"location":"examples/darcy/#Walkthrough-of-the-code","page":"Darcy flow","title":"Walkthrough of the code","text":"","category":"section"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"First we load standard packages,","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"using LinearAlgebra\nusing Distributions\nusing Random\nusing JLD2","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"the package to define the function distributions,","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"import GaussianRandomFields # we wrap this so we don't want to use \"using\"\nconst GRF = GaussianRandomFields","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"and finally the EKP packages.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We include the forward solver here.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"include(\"GModel.jl\")","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We define the spatial domain and discretization,","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"rng = Random.MersenneTwister(seed)\ndim = 2\nN, L = 80, 1.0\npts_per_dim = LinRange(0, L, N)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"To provide a simple test case, we assume that the true function parameter is a particular sample from the function space we set up to define our prior. We choose a value of the truth that doesnt have a vanishingly small probability under the prior defined by a probability distribution over functions; taken to be a family of Gaussian Random Fields (GRF). This function distribution is characterized by a covariance function (Matern) and an appropriate representation (Karhunen-Loeve expansion). The representation is truncated to a finite number of coefficients, the degrees of freedom (dofs), which define the effective dimension of the learning problem that is decoupled from the spatial discretization. Larger dofs may be required to represent multiscale functions, but come at an increased dimension of the parameter space and therefore a typical increase in cost and difficulty of the learning problem. For more details see GaussianRandomFields.jl","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"smoothness = 2.0\ncorr_length = 0.5\ndofs = 50\n\ngrf = GRF.GaussianRandomField(\n GRF.CovarianceFunction(dim, GRF.Matern(smoothness, corr_length)),\n GRF.KarhunenLoeve(dofs),\n pts_per_dim,\n pts_per_dim,\n)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We define a wrapper around the GRF, and as the permeability field must be positive we introduce a domain constraint into the function distribution. ","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"pkg = GRFJL()\ndistribution = GaussianRandomFieldInterface(grf, pkg) # our wrapper from EKP\ndomain_constraint = bounded_below(0) # make κ positive\npd = ParameterDistribution(\n Dict(\"distribution\" => distribution, \"name\" => \"kappa\", \"constraint\" => domain_constraint),\n) # the fully constrained parameter distribution","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"Henceforth, the GRF is interfaced in the same manner as any other parameter distribution with regards to interface. We choose the true value by setting all degrees of freedom u_mathrmtrue = -15; this choice is arbitrary, upto not having a vanishingly small mass under the prior. We then use the EKP transform function to build the corresponding instance of the kappa_mathrmtrue.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"u_true = -1.5 * ones(dofs,1) # the truth parameter\nκ_true = transform_unconstrained_to_constrained(pd, u_true) # builds and constrains the function.\nκ_true = reshape(κ_true, N, N)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We generate the data sample for the truth in a perfect model setting by evaluating the the model here, and observing the pressure field at a few subsampled points in each dimension (here obs_ΔN, samples every 10 points in each dimension, leading to a 7 times 7 observation grid), and we assume 5% additive observational noise on the measurements.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"obs_ΔN = 10 \ndarcy = Setup_Param(pts_per_dim, obs_ΔN, κ_true) \nh_2d = solve_Darcy_2D(darcy, κ_true)\ny_noiseless = compute_obs(darcy, h_2d)\nobs_noise_cov = 0.05^2 * I(length(y_noiseless)) * (maximum(y_noiseless) - minimum(y_noiseless))\ntruth_sample = vec(y_noiseless + rand(rng, MvNormal(zeros(length(y_noiseless)), obs_noise_cov)))","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"Now we set up the Bayesian inversion algorithm. The prior we have already defined to construct our truth","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"prior = pd","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We define some algorithm parameters, here we take ensemble members larger than the dimension of the parameter space to ensure a full rank ensemble covariance.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"N_ens = dofs + 2 # number of ensemble members\nN_iter = 20 # number of EKI iterations","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We sample the initial ensemble from the prior, and create the EKP object as an EKI algorithm using the Inversion() keyword, we also use the DataMisfitController() learning rate scheduler","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"initial_params = construct_initial_ensemble(rng, prior, N_ens) \nekiobj = EKP.EnsembleKalmanProcess(initial_params, truth_sample, obs_noise_cov, Inversion(), scheduler=DataMisfitController())","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We perform the inversion loop. Remember that within calls to get_ϕ_final the EKP transformations are applied, thus the ensemble that is returned will be the positively-bounded permeability field evaluated at all the discretization points. Each ensemble member is stored as a column and therefore for uses such as plotting one needs to reshape to the desired dimension.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"err = zeros(N_iter)\nfor i in 1:N_iter\n params_i = get_ϕ_final(prior, ekiobj)\n g_ens = run_G_ensemble(darcy, params_i)\n EKP.update_ensemble!(ekiobj, g_ens)\nend","category":"page"},{"location":"examples/darcy/#Inversion-results","page":"Darcy flow","title":"Inversion results","text":"","category":"section"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We plot first the prior ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean. ","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"(Image: Darcy prior)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"Now we plot the final ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"(Image: Darcy final)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We can compare this with the true permeability and pressure field:","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"(Image: Darcy truth)","category":"page"},{"location":"glossary/#Glossary","page":"Glossary","title":"Glossary","text":"","category":"section"},{"location":"glossary/","page":"Glossary","title":"Glossary","text":"The following list includes the names and symbols of recurring concepts in EnsembleKalmanProcesses.jl. Some of these variables do not appear in the codebase, which relies on array programming for performance. Contributions to the codebase require following this notational convention. Similarly, if you find inconsistencies in the documentation or codebase, please report an issue on GitHub.","category":"page"},{"location":"glossary/","page":"Glossary","title":"Glossary","text":"Name Symbol (Theory/Docs) Symbol (Code)\nParameter vector, Parameters (unconstrained space) theta, u, mathcalT(phi) θ,u\nParameter vector, Parameters (physical / constrained space) phi, mathcalT^-1(theta) ϕ\nParameter vector size, Number of parameters p N_par\nEnsemble size J N_ens\nEnsemble particles, members theta^(j) \nNumber of iterations N_rm it N_iter\nObservation vector, Observations, Data vector y y\nObservation vector size, Data vector size d N_obs\nObservational noise eta obs_noise\nObservational noise covariance Gamma_y obs_noise_cov\nHilbert space inner product langle phi Gamma^-1 psi rangle \nForward map mathcalG G\nDynamical model Psi Ψ\nTransform map (constrained to unconstrained) mathcalT T\nObservation map mathcalH H\nPrior covariance (unconstrained space) Gamma_theta prior_cov\nPrior mean (unconstrained space) m_theta prior_mean","category":"page"},{"location":"API/Inversion/#Ensemble-Kalman-Inversion","page":"Inversion","title":"Ensemble Kalman Inversion","text":"","category":"section"},{"location":"API/Inversion/","page":"Inversion","title":"Inversion","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/Inversion/","page":"Inversion","title":"Inversion","text":"Inversion\neki_update","category":"page"},{"location":"API/Inversion/#EnsembleKalmanProcesses.Inversion","page":"Inversion","title":"EnsembleKalmanProcesses.Inversion","text":"Inversion <: Process\n\nAn ensemble Kalman Inversion process\n\n\n\n\n\n","category":"type"},{"location":"API/Inversion/#EnsembleKalmanProcesses.eki_update","page":"Inversion","title":"EnsembleKalmanProcesses.eki_update","text":" eki_update(\n ekp::EnsembleKalmanProcess{FT, IT, Inversion},\n u::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n y::AbstractMatrix{FT},\n obs_noise_cov::Union{AbstractMatrix{CT}, UniformScaling{CT}},\n) where {FT <: Real, IT, CT <: Real}\n\nReturns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (4) and (5) of Schillings and Stuart (2017).\n\nLocalization is implemented following the ekp.localizer.\n\n\n\n\n\n","category":"function"},{"location":"examples/lorenz_example/#Lorenz-example","page":"Lorenz","title":"Lorenz 96 example","text":"","category":"section"},{"location":"examples/lorenz_example/#Overview","page":"Lorenz","title":"Overview","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The Lorenz 96 (hereafter L96) example is a toy-problem for the application of the EnsembleKalmanProcesses.jl optimization and approximate uncertainty quantification methodologies. Here is L96 with additional periodic-in-time forcing, we try to determine parameters (sinusoidal amplitude and stationary component of the forcing) from some output statistics. The standard L96 equations are implemented with an additional forcing term with time dependence. The output statistics which are used for learning are the finite time-averaged variances.","category":"page"},{"location":"examples/lorenz_example/#Lorenz-96-equations","page":"Lorenz","title":"Lorenz 96 equations","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The standard single-scale L96 equations are implemented. The Lorenz 96 system (Lorenz, 1996) is given by ","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"fracd x_id t = (x_i+1 - x_i-2) x_i-1 - x_i + F","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"with i indicating the index of the given longitude. The number of longitudes is given by N. The boundary conditions are given by","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"x_-1 = x_N-1 x_0 = x_N x_N+1 = x_1","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The time scaling is such that the characteristic time is 5 days (Lorenz, 1996). For very small values of F, the solutions x_i decay to F after the initial transient feature. For moderate values of F, the solutions are periodic, and for larger values of F, the system is chaotic. The solution variance is a function of the forcing magnitude. Variations in the base state as a function of time can be imposed through a time-dependent forcing term F(t).","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"A temporal forcing term is defined","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"F = F_s + A sin(omega t)","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"with steady-state forcing F_s, transient forcing amplitude A, and transient forcing frequency omega. The total forcing F must be within the chaotic regime of L96 for all time given the prescribed N.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The L96 dynamics are solved with RK4 integration.","category":"page"},{"location":"examples/lorenz_example/#Structure","page":"Lorenz","title":"Structure","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The main code is located in Lorenz_example.jl which provides the functionality to run the L96 dynamical system, extract time-averaged statistics from the L96 states, and use the time-average statistics for optimization and uncertainty quantification.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The L96 system is solved in GModel.jl according to the time integration settings specified in LSettings and the L96 parameters specified in LParams. The types of statistics to be collected are detailed in GModel.jl.","category":"page"},{"location":"examples/lorenz_example/#Lorenz-dynamics-inputs","page":"Lorenz","title":"Lorenz dynamics inputs","text":"","category":"section"},{"location":"examples/lorenz_example/#Dynamics-settings","page":"Lorenz","title":"Dynamics settings","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The use of the transient forcing term is with the flag, dynamics. Stationary forcing is dynamics=1 (A=0) and transient forcing is used with dynamics=2 (Aneq0). The default parameters are specified in Lorenz_example.jl and can be modified as necessary. The system is solved over time horizon 0 to tend at fixed time step dt.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"N = 36\ndt = 1/64\nt_start = 800","category":"page"},{"location":"examples/lorenz_example/#Inverse-problem-settings","page":"Lorenz","title":"Inverse problem settings","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The states are integrated over time Ts_days to construct the time averaged statistics for use by the optimization. The specification of the statistics to be gathered from the states are provided by stats_type. The Ensemble Kalman Process (EKP) settings are","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"N_ens = 20 # number of ensemble members\nN_iter = 5 # number of EKI iterations","category":"page"},{"location":"examples/lorenz_example/#Setting-up-the-Inverse-Problem","page":"Lorenz","title":"Setting up the Inverse Problem","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The goal is to learn F_s and A based on the time averaged statistics in a perfect model setting. The true parameters are","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"F_true = 8. # Mean F\nA_true = 2.5 # Transient F amplitude\nω_true = 2. * π / (360. / τc) # Frequency of the transient F\nparams_true = [F_true, A_true]\nparam_names = [\"F\", \"A\"]","category":"page"},{"location":"examples/lorenz_example/#Priors","page":"Lorenz","title":"Priors","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"We implement (biased) priors as follows","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"prior_means = [F_true + 1.0, A_true + 0.5]\nprior_stds = [2.0, 0.5 * A_true]\n# constrained_gaussian(\"name\", desired_mean, desired_std, lower_bd, upper_bd)\nprior_F = constrained_gaussian(param_names[1], prior_means[1], prior_stds[1], 0, Inf)\nprior_A = constrained_gaussian(param_names[2], prior_means[2], prior_stds[2], 0, Inf)\npriors = combine_distributions([prior_F, prior_A])","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"We use the recommended constrained_gaussian to add the desired scale and bounds to the prior distribution, in particular we place lower bounds to preserve positivity. ","category":"page"},{"location":"examples/lorenz_example/#Observational-Noise","page":"Lorenz","title":"Observational Noise","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The observational noise can be generated using the L96 system or prescribed, as specified by var_prescribe. ","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"var_prescribe==false The observational noise is constructed by generating independent instantiations of the L96 statistics of interest at the true parameters for different initial conditions. The empirical covariance matrix is constructed.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"var_prescribe==true The observational noise is prescribed as a Gaussian distribution with prescribed mean and variance.","category":"page"},{"location":"examples/lorenz_example/#Running-the-Example","page":"Lorenz","title":"Running the Example","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The L96 parameter estimation can be run using julia --project Lorenz_example.jl","category":"page"},{"location":"examples/lorenz_example/#Solution-and-Output","page":"Lorenz","title":"Solution and Output","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The output will provide the estimated parameters in the constrained ϕ-space. The priors are required in the get-method to apply these constraints.","category":"page"},{"location":"examples/lorenz_example/#Printed-output","page":"Lorenz","title":"Printed output","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"# EKI results: Has the ensemble collapsed toward the truth?\nprintln(\"True parameters: \")\nprintln(params_true)\nprintln(\"\\nEKI results:\")\nprintln(get_ϕ_mean_final(priors, ekiobj))","category":"page"},{"location":"examples/lorenz_example/#Saved-output","page":"Lorenz","title":"Saved output","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The parameters and forward model outputs will be saved in parameter_storage.jld2 and data_storage.jld2, respectively. The data will be saved in the directory output.","category":"page"},{"location":"examples/lorenz_example/#Plots","page":"Lorenz","title":"Plots","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"A scatter plot animation of the ensemble convergence to the true parameters is saved in the directory output.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"EditURL = \"../../../examples/Sinusoid/sinusoid_example.jl\"","category":"page"},{"location":"literated/sinusoid_example/#sinusoid-example","page":"Simple example","title":"Fitting parameters of a sinusoid","text":"","category":"section"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"In this example we have a model that produces a sinusoid f(A v) = A sin(phi + t) + v forall t in 02pi, with a random phase phi. Given an initial guess of the parameters as A^* sim mathcalN(21) and v^* sim mathcalN(025), our goal is to estimate the parameters from a noisy observation of the maximum, minimum, and mean of the true model output.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"First, we load the packages we need:","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"using LinearAlgebra, Random\n\nusing Distributions, Plots\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses\nnothing # hide\n\n# Setting up the model and data for our inverse problem","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Now, we define a model which generates a sinusoid given parameters theta: an amplitude and a vertical shift. We will estimate these parameters from data. The model adds a random phase shift upon evaluation.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"dt = 0.01\ntrange = 0:dt:(2 * pi + dt)\nfunction model(amplitude, vert_shift)\n phi = 2 * pi * rand(rng)\n return amplitude * sin.(trange .+ phi) .+ vert_shift\nend\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Seed for pseudo-random number generator.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"rng_seed = 41\nrng = Random.MersenneTwister(rng_seed)\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We then define G(theta), which returns the observables of the sinusoid given a parameter vector. These observables should be defined such that they are informative about the parameters we wish to estimate. Here, the two observables are the y range of the curve (which is informative about its amplitude), as well as its mean (which is informative about its vertical shift).","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"function G(u)\n theta, vert_shift = u\n sincurve = model(theta, vert_shift)\n return [maximum(sincurve) - minimum(sincurve), mean(sincurve)]\nend\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Suppose we have a noisy observation of the true system. Here, we create a pseudo-observation y by running our model with the correct parameters and adding Gaussian noise to the output.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"dim_output = 2\n\nΓ = 0.1 * I\nnoise_dist = MvNormal(zeros(dim_output), Γ)\n\ntheta_true = [1.0, 7.0]\ny = G(theta_true) .+ rand(noise_dist)\nnothing # hide\n\n# Solving the inverse problem","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We now define prior distributions on the two parameters. For the amplitude, we define a prior with mean 2 and standard deviation 1. It is additionally constrained to be nonnegative. For the vertical shift we define a Gaussian prior with mean 0 and standard deviation 5.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"prior_u1 = constrained_gaussian(\"amplitude\", 2, 1, 0, Inf)\nprior_u2 = constrained_gaussian(\"vert_shift\", 0, 5, -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We now generate the initial ensemble and set up the ensemble Kalman inversion.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"N_ensemble = 5\nN_iterations = 5\n\ninitial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)\n\nensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, y, Γ, Inversion(); rng = rng)\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We are now ready to carry out the inversion. At each iteration, we get the ensemble from the last iteration, apply G(theta) to each ensemble member, and apply the Kalman update to the ensemble.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"for i in 1:N_iterations\n params_i = get_ϕ_final(prior, ensemble_kalman_process)\n\n G_ens = hcat([G(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, G_ens)\nend\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Finally, we get the ensemble after the last iteration. This provides our estimate of the parameters.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"final_ensemble = get_ϕ_final(prior, ensemble_kalman_process)","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"To visualize the success of the inversion, we plot model with the true parameters, the initial ensemble, and the final ensemble.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"plot(trange, model(theta_true...), c = :black, label = \"Truth\", legend = :bottomright, linewidth = 2)\nplot!(\n trange,\n [model(get_ϕ(prior, ensemble_kalman_process, 1)[:, i]...) for i in 1:N_ensemble],\n c = :red,\n label = [\"Initial ensemble\" \"\" \"\" \"\" \"\"],\n)\nplot!(trange, [model(final_ensemble[:, i]...) for i in 1:N_ensemble], c = :blue, label = [\"Final ensemble\" \"\" \"\" \"\" \"\"])\n\nxlabel!(\"Time\")","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We see that the final ensemble is much closer to the truth. Note that the random phase shift is of no consequence.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/template_example/#Template-example","page":"Template","title":"Template example","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"We provide the following template for how the tools may be applied.","category":"page"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"For small examples typically have 2 files.","category":"page"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"DynamicalModel.jl Contains the dynamical model Psi and the observation map mathcalH. The inputs should be the so-called free parameters (in the constrained/physical space that is the input domain of the dynamical model) we are interested in learning, and the output should be the measured data.\nThe example script which contains the inverse problem setup and solve","category":"page"},{"location":"examples/template_example/#The-structure-of-the-example-script","page":"Template","title":"The structure of the example script","text":"","category":"section"},{"location":"examples/template_example/#Create-the-data-and-the-setting-for-the-model","page":"Template","title":"Create the data and the setting for the model","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Set up the forward model.\nConstruct/load the truth data. ","category":"page"},{"location":"examples/template_example/#Set-up-the-inverse-problem","page":"Template","title":"Set up the inverse problem","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Define the prior distributions, and generate an initial ensemble.\nInitialize the process tool you would like to use (we recommend you begin with Inversion()). \ninitialize the EnsembleKalmanProcess object","category":"page"},{"location":"examples/template_example/#Solve-the-inverse-problem,-in-a-loop","page":"Template","title":"Solve the inverse problem, in a loop","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Obtain the current parameter ensemble\nTransform them from the unbounded computational space to the physical space\ncall the forward model on the ensemble of parameters, producing an ensemble of measured data\ncall the update_ensemble! function to generate a new parameter ensemble based on the new data","category":"page"},{"location":"examples/template_example/#Get-the-solution","page":"Template","title":"Get the solution","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Obtain the final parameter ensemble, compute desired statistics here.\nTransform the final ensemble into the physical space for use in prediction studies with the forward model.","category":"page"},{"location":"localization/#Localization-and-Sampling-Error-Correction-(SEC)","page":"Localization and SEC","title":"Localization and Sampling Error Correction (SEC)","text":"","category":"section"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"Ensemble Kalman inversion (EKI) seeks to find an optimal parameter vector theta in mathbbR^p by minimizing the mismatch between some data y in mathbbR^d and the forward model output mathcalG(theta) in mathbbR^d. Instead of relying on derivatives of the map mathcalG with respect to theta to find the optimum, EKI leverages sample covariances mathrmCov(theta mathcalG) and mathrmCov(mathcalG mathcalG) diagnosed from an ensemble of J particles,","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":" tag1\n beginaligned\n mathrmCov(theta mathcalG) = dfrac1Jsum_j=1^J\n (theta^(j) - m)(mathcalG(theta^(j)) - barmathcalG)^T \n\n mathrmCov(mathcalG mathcalG) = dfrac1Jsum_j=1^J\n (mathcalG(theta^(j)) - barmathcalG)(mathcalG(theta^(j)) - barmathcalG)^T \n endaligned","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"where m and barmathcalG are the ensemble averages of theta and mathcalG(theta), respectively.","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"For models with just a few (p) parameters, we can typically afford to use J p ensemble members, such that the sample covariance mathrmCov(theta mathcalG) is full rank. Using more ensemble members than the number of model parameters, EKI can in theory probe all dimensions of parameter space to find the optimum parameter vector.","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"For models with a lot of parameters (e.g., a deep neural network), computational constraints limit the size of the ensemble to J p or even J ll p members. Due to the characteristics of the EKI update equation, this means that the method can only find the minimum in the (J-1)-dimensional space spanned by the initial ensemble, leaving p-J+1 dimensions unexplored. This is known as the subspace property of EKI. As the dimensional gap p-J increases, we can expect the solution of the algorithm to deteriorate.","category":"page"},{"location":"localization/#Enter-Localization","page":"Localization and SEC","title":"Enter Localization","text":"","category":"section"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"In algebraic terms, the extent to which we can explore the dimensions of parameter space is roughly given by the rank of the matrices in equation (1). In the case J p, the rank of mathrmCov(theta mathcalG) is limited to mathrmmin(d J-1). It has been shown that the performance of ensemble Kalman methods with J p can be greatly improved by boosting this rank through an elementwise product with a suitable localization kernel Lambda,","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"tag2 mathrmrank(mathrmCov(theta mathcalG) odot Lambda) geq mathrmrank(mathrmCov(theta mathcalG))","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"Substituting the covariance mathrmCov(theta mathcalG) by the boosted version defined in the left-hand side of equation (2), EKI is able to break the subspace property and explore additional dimensions in parameter space. Localization is an empirical way of correcting for the sampling error due to a small ensemble size, and so it can also be interpreted as a sampling error correction (SEC) method.","category":"page"},{"location":"localization/#Localization-in-EnsembleKalmanProcesses","page":"Localization and SEC","title":"Localization in EnsembleKalmanProcesses","text":"","category":"section"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"A wide variety of localization kernels are available in EnsembleKalmanProcesses.jl under the module Localizers. The optimal localization kernel will depend on the structure of the problem at hand, so the user is encouraged to try different kernels and review their references in the literature.","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"In practice, the localization method is chosen at EnsembleKalmanProcess construction time,","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"using Distributions\nusing LinearAlgebra\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nusing EnsembleKalmanProcesses.Localizers\nconst EKP = EnsembleKalmanProcesses\n\np = 10; d = 20; J = 6\n\n# Construct initial ensemble\npriors = ParameterDistribution[]\nfor i in 1:p\n push!(priors, ParameterDistribution(Parameterized(Normal(0.0, 0.5)), no_constraint(), string(\"u\", i)))\nend\nprior = combine_distributions(priors)\ninitial_ensemble = EKP.construct_initial_ensemble(prior, J)\n\ny = 10.0 * rand(d)\nΓ = 1.0 * I\n\n# Construct EKP object with localization. Some examples of localization methods:\nlocs = [Delta(), RBF(1.0), RBF(0.1), BernoulliDropout(0.1), SEC(10.0), SECFisher(), SEC(1.0, 0.1)]\nfor loc in locs\n ekiobj = EKP.EnsembleKalmanProcess(initial_ensemble, y, Γ, Inversion(); localization_method = loc)\nend","category":"page"},{"location":"ensemble_kalman_inversion/#Ensemble-Kalman-Inversion","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"One of the ensemble Kalman processes implemented in EnsembleKalmanProcesses.jl is the ensemble Kalman inversion (Iglesias et al, 2013). The ensemble Kalman inversion (EKI) is a derivative-free ensemble optimization method that seeks to find the optimal parameters theta in mathbbR^p in the inverse problem defined by the data-model relation","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"tag1 y = mathcalG(theta) + eta ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where mathcalG denotes the forward map, y in mathbbR^d is the vector of observations and eta in mathbbR^d is additive noise. Note that p is the size of the parameter vector theta and d the size of the observation vector y. Here, we take eta sim mathcalN(0 Gamma_y) from a d-dimensional Gaussian with zero mean and covariance matrix Gamma_y. This noise structure aims to represent the correlations between observations.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The optimal parameters theta^* in mathbbR^p given relation (1) minimize the loss","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"mathcalL(theta y) = langle mathcalG(theta) - y Gamma_y^-1 left ( mathcalG(theta) - y right ) rangle","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"which can be interpreted as the negative log-likelihood given a Gaussian likelihood.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Denoting the parameter vector of the j-th ensemble member at the n-th iteration as theta^(j)_n, its update equation from n to n+1 under EKI is","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"tag2 theta_n+1^(j) = theta_n^(j) - dfracDelta t_nJsum_k=1^J left langle mathcalG(theta_n^(k)) - barmathcalG_n Gamma_y^-1 left ( mathcalG(theta_n^(j)) - y right ) right rangle theta_n^(k) ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where the subscript n=1 dots N_rm it indicates the iteration, J is the number of members in the ensemble, barmathcalG_n is the mean value of mathcalG(theta_n) across ensemble members,","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"barmathcalG_n = dfrac1Jsum_k=1^JmathcalG(theta_n^(k)) ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"and angle brackets denote the Euclidean inner product. By multiplying with Gamma_y^-1 we render the inner product non-dimensional.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The EKI algorithm is considered converged when the ensemble achieves sufficient consensus/collapse in parameter space. The final estimate bartheta_N_rm it is taken to be the ensemble mean at the final iteration,","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"bartheta_N_rm it = dfrac1Jsum_k=1^Jtheta_N_rm it^(k)","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"For typical applications, a near-optimal solution theta can be found after as few as 10 iterations of the algorithm, or 10cdot J evaluations of the forward model mathcalG. The basic algorithm requires J geq p, and better performance is often seen with larger ensembles; a good rule of thumb is to start with J=10p. The algorithm also extends to J p , using localizers to maintain performance in these situations (see the Localizers.jl module).","category":"page"},{"location":"ensemble_kalman_inversion/#Constructing-the-Forward-Map","page":"Ensemble Kalman Inversion","title":"Constructing the Forward Map","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The forward map mathcalG maps the space of unconstrained parameters theta in mathbbR^p to the space of outputs y in mathbbR^d. In practice, the user may not have access to such a map directly. Consider a situation where the goal is to learn a set of parameters phi of a dynamical model Psi mathbbR^p rightarrow mathbbR^o, given observations y in mathbbR^d and a set of constraints on the value of phi. Then, the forward map may be constructed as","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"mathcalG = mathcalH circ Psi circ mathcalT^-1","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where mathcalH mathbbR^o rightarrow mathbbR^d is the observation map and mathcalT is the transformation map from constrained to unconstrained parameter spaces, such that mathcalT(phi) = theta. A family of standard transformation maps and their inverse are available in the ParameterDistributions module.","category":"page"},{"location":"ensemble_kalman_inversion/#Creating-the-EKI-Object","page":"Ensemble Kalman Inversion","title":"Creating the EKI Object","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"An ensemble Kalman inversion object can be created using the EnsembleKalmanProcess constructor by specifying the Inversion() process type.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Creating an ensemble Kalman inversion object requires as arguments:","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"An initial parameter ensemble, Array{Float, 2} of size [p × J];\nThe mean value of the observed outputs, a vector of size [d];\nThe covariance of the observational noise, a matrix of size [d × d];\nThe Inversion() process type.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A typical initialization of the Inversion() process takes a user-defined prior, a summary of the observation statistics given by the mean y and covariance obs_noise_cov, and a desired number of members in the ensemble,","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\nJ = 50 # number of ensemble members\ninitial_ensemble = construct_initial_ensemble(prior, J) # Initialize ensemble from prior\n\nekiobj = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, Inversion())","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"See the Prior distributions section to learn about the construction of priors in EnsembleKalmanProcesses.jl. The prior is assumed to be over the unconstrained parameter space where theta is defined. For applications where enforcing parameter bounds is necessary, the ParameterDistributions module provides functions to map from constrained to unconstrained space and vice versa. ","category":"page"},{"location":"ensemble_kalman_inversion/#Updating-the-Ensemble","page":"Ensemble Kalman Inversion","title":"Updating the Ensemble","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Once the ensemble Kalman inversion object ekiobj has been initialized, any number of updates can be performed using the inversion algorithm.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A call to the inversion algorithm can be performed with the update_ensemble! function. This function takes as arguments the ekiobj and the evaluations of the forward map at each member of the current ensemble. The update_ensemble! function then stores the new updated ensemble and the inputted forward map evaluations in ekiobj. ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A typical use of the update_ensemble! function given the ensemble Kalman inversion object ekiobj, the dynamical model Ψ and the observation map H is","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"# Given:\n# Ψ (some black box simulator)\n# H (some observation of the simulator output)\n# prior (prior distribution and parameter constraints)\n\nN_iter = 20 # Number of steps of the algorithm\n\nfor n in 1:N_iter\n ϕ_n = get_ϕ_final(prior, ekiobj) # Get current ensemble in constrained \"ϕ\"-space\n G_n = [H(Ψ(ϕ_n[:, i])) for i in 1:J]\n g_ens = hcat(G_n...) # Evaluate forward map \n update_ensemble!(ekiobj, g_ens) # Update ensemble\nend","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"In the previous update, note that the parameters stored in ekiobj are given in the unconstrained Gaussian space where the EKI algorithm is performed. The map mathcalT^-1 between this unconstrained space and the (possibly constrained) physical space of parameters is encoded in the prior object. The dynamical model Ψ accepts as inputs the parameters in (possibly constrained) physical space, so it is necessary to use the getter get_ϕ_final which applies transform_unconstrained_to_constrained to the ensemble. See the Prior distributions section for more details on parameter transformations. ","category":"page"},{"location":"ensemble_kalman_inversion/#Solution","page":"Ensemble Kalman Inversion","title":"Solution","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The EKI algorithm drives the initial ensemble, sampled from the prior, towards the support region of the posterior distribution. The algorithm also drives the ensemble members towards consensus. The optimal parameter θ_optim found by the algorithm is given by the mean of the last ensemble (i.e., the ensemble after the last iteration),","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"θ_optim = get_u_mean_final(ekiobj) # optimal parameter","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"To obtain the optimal value in the constrained space, we use the getter with the constrained prior as input","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"ϕ_optim = get_ϕ_mean_final(prior, ekiobj) # the optimal physical parameter value","category":"page"},{"location":"ensemble_kalman_inversion/#Handling-forward-model-failures","page":"Ensemble Kalman Inversion","title":"Handling forward model failures","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"In situations where the forward model mathcalG represents a diagnostic of a complex computational model, there might be cases where for some parameter combinations theta, attempting to evaluate mathcalG(theta) may result in model failure (defined as returning a NaN from the point of view of this package). In such cases, the EKI update equation (2) must be modified to handle model failures.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"EnsembleKalmanProcesses.jl implements such modifications through the FailureHandler structure, an input to the EnsembleKalmanProcess constructor. Currently, the only failsafe modification available is SampleSuccGauss(), described in Lopez-Gomez et al (2022).","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"To employ this modification, construct the EKI object as","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\nJ = 50 # number of ensemble members\ninitial_ensemble = construct_initial_ensemble(prior, J) # Initialize ensemble from prior\n\nekiobj = EnsembleKalmanProcess(\n initial_ensemble,\n y,\n obs_noise_cov,\n Inversion(),\n failure_handler_method = SampleSuccGauss())","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"info: Forward model requirements when using FailureHandlers\nThe user must determine if a model run has \"failed\", and replace the output mathcalG(theta) with NaN. The FailureHandler takes care of the rest.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A description of the algorithmic modification is included below.","category":"page"},{"location":"ensemble_kalman_inversion/#SampleSuccGauss()","page":"Ensemble Kalman Inversion","title":"SampleSuccGauss()","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The SampleSuccGauss() modification is based on updating all ensemble members with a distribution given by only the successful parameter ensemble. Let Theta_sn= theta^(1)_sndotstheta^(J_s)_sn be the successful ensemble, for which each evaluation mathcalG(theta^(j)_sn) does not fail, and let theta_fn^(k) be the ensemble members for which the evaluation mathcalG(theta^(k)_fn) fails. The successful ensemble Theta_sn is updated to Theta_sn+1 using expression (2), and each failed ensemble member as","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":" theta_fn+1^(k) sim mathcalN left(m_s n+1 Sigma_s n+1 right)","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":" m_s n+1 = dfrac1J_ssum_j=1^J_s theta_sn+1^(j) qquad Sigma_s n+1 = mathrmCov(theta_s n+1 theta_s n+1) + kappa_*^-1mu_s1I_p","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Here, kappa_* is a limiting condition number, mu_s1 is the largest eigenvalue of the sample covariance mathrmCov(theta_s n+1 theta_s n+1) and I_p is the identity matrix of size ptimes p.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"warning: Warning\nThis modification is not a magic bullet. If large fractions of ensemble members fail during an iteration, this will degenerate the span of the ensemble.","category":"page"},{"location":"ensemble_kalman_inversion/#Sparsity-Inducing-Ensemble-Kalman-Inversion","page":"Ensemble Kalman Inversion","title":"Sparsity-Inducing Ensemble Kalman Inversion","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"We include Sparsity-inducing Ensemble Kalman Inversion (SEKI) to add approximate L^0 and L^1 penalization to the EKI (Schneider, Stuart, Wu, 2020).","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"warning: Warning\nThe algorithm suffers from robustness issues, and therefore we urge caution in using the tool","category":"page"},{"location":"API/Localizers/#Localizers","page":"Localizers","title":"Localizers","text":"","category":"section"},{"location":"API/Localizers/","page":"Localizers","title":"Localizers","text":"CurrentModule = EnsembleKalmanProcesses.Localizers","category":"page"},{"location":"API/Localizers/","page":"Localizers","title":"Localizers","text":"Localizer\nRBF\nBernoulliDropout\nSEC\nSECFisher\nDelta\nNoLocalization","category":"page"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.Localizer","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.Localizer","text":"Localizer{LM <: LocalizationMethod, T}\n\nStructure that defines a localize function, based on a localization method.\n\nFields\n\nlocalize::Function\nLocalizing function of the form: cov -> kernel .* cov\n\nConstructors\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:122.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:128.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:134.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:179.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:199.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:238.\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.RBF","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.RBF","text":"RBF{FT <: Real} <: LocalizationMethod\n\nRadial basis function localization method. Covariance terms C_ij are damped through multiplication with a centered Gaussian with standardized deviation d(ij)= vert i-j vert l.\n\nFields\n\nlengthscale::Real\nLength scale defining the RBF kernel\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.BernoulliDropout","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.BernoulliDropout","text":"BernoulliDropout{FT <: Real} <: LocalizationMethod\n\nLocalization method that drops cross-covariance terms with probability 1-p, retaining a Hermitian structure.\n\nFields\n\nprob::Real\nProbability of keeping a given cross-covariance term\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.SEC","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.SEC","text":"SEC{FT <: Real} <: LocalizationMethod\n\nSampling error correction that shrinks correlations by a factor of vert r vert ^alpha, as per Lee (2021). Sparsity of the resulting correlations can be imposed through the parameter r_0.\n\nLee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341\n\nFields\n\nα::Real\nControls degree of sampling error correction\nr_0::Real\nCutoff correlation\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.SECFisher","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.SECFisher","text":"SECFisher <: LocalizationMethod\n\nSampling error correction for EKI, as per Lee (2021), but using the method from Flowerdew (2015) based on the Fisher transformation. Correlations are shrinked by a factor determined by the sample correlation and the ensemble size. \n\nFlowerdew, J. (2015). Towards a theory of optimal localisation. Tellus A: Dynamic Meteorology and Oceanography, 67(1), 25257. https://doi.org/10.3402/tellusa.v67.25257\n\nLee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.Delta","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.Delta","text":"Dirac delta localization method, with an identity matrix as the kernel.\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.NoLocalization","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.NoLocalization","text":"Idempotent localization method.\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#ParameterDistributions","page":"ParameterDistributions","title":"ParameterDistributions","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"CurrentModule = EnsembleKalmanProcesses.ParameterDistributions","category":"page"},{"location":"API/ParameterDistributions/#ParameterDistributionTypes","page":"ParameterDistributions","title":"ParameterDistributionTypes","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"Parameterized\nSamples\nVectorOfParameterized","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.Parameterized","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.Parameterized","text":"Parameterized <: ParameterDistributionType\n\nA distribution constructed from a parameterized formula (e.g Julia Distributions.jl)\n\nFields\n\ndistribution::Distributions.Distribution\nA parameterized distribution\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.Samples","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.Samples","text":"Samples{FT <: Real} <: ParameterDistributionType\n\nA distribution comprised of only samples, stored as columns of parameters.\n\nFields\n\ndistribution_samples::AbstractMatrix{FT} where FT<:Real\nSamples defining an empirical distribution, stored as columns\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.VectorOfParameterized","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.VectorOfParameterized","text":"VectorOfParameterized <: ParameterDistributionType\n\nA distribution built from an array of Parametrized distributions. A utility to help stacking of distributions where a multivariate equivalent doesn't exist.\n\nFields\n\ndistribution::AbstractVector{DT} where DT<:Distributions.Distribution\nA vector of parameterized distributions\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#Constraints","page":"ParameterDistributions","title":"Constraints","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"Constraint\nno_constraint\nbounded_below\nbounded_above\nbounded\nlength(c::CType) where {CType <: ConstraintType}\nsize(c::CType) where {CType <: ConstraintType}","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.Constraint","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.Constraint","text":"Constraint{T} <: ConstraintType\n\nClass describing a 1D bijection between constrained and unconstrained spaces. Included parametric types for T:\n\nNoConstraint\nBoundedBelow\nBoundedAbove\nBounded\n\nFields\n\nconstrained_to_unconstrained::Function\nA map from constrained domain -> (-Inf,Inf)\nc_to_u_jacobian::Function\nThe jacobian of the map from constrained domain -> (-Inf,Inf)\nunconstrained_to_constrained::Function\nMap from (-Inf,Inf) -> constrained domain\nbounds::Union{Nothing, Dict}\nDictionary of values used to build the Constraint (e.g. \"lowerbound\" or \"upperbound\")\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.no_constraint","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.no_constraint","text":"no_constraint()\n\nConstructs a Constraint with no constraints, enforced by maps x -> x and x -> x.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.bounded_below","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.bounded_below","text":"bounded_below(lower_bound::FT) where {FT <: Real}\n\nConstructs a Constraint with provided lower bound, enforced by maps x -> log(x - lower_bound) and x -> exp(x) + lower_bound.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.bounded_above","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.bounded_above","text":"bounded_above(upper_bound::FT) where {FT <: Real}\n\nConstructs a Constraint with provided upper bound, enforced by maps x -> log(upper_bound - x) and x -> upper_bound - exp(x).\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.bounded","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.bounded","text":"bounded(lower_bound::Real, upper_bound::Real)\n\nConstructs a Constraint with provided upper and lower bounds, enforced by maps x -> log((x - lower_bound) / (upper_bound - x)) and x -> (upper_bound * exp(x) + lower_bound) / (exp(x) + 1).\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Base.length-Tuple{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType","page":"ParameterDistributions","title":"Base.length","text":"length(c<:ConstraintType)\n\nA constraint has length 1. \n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#Base.size-Tuple{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType","page":"ParameterDistributions","title":"Base.size","text":"size(c<:ConstraintType)\n\nA constraint has size 1.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#ParameterDistributions-2","page":"ParameterDistributions","title":"ParameterDistributions","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"ParameterDistribution\nconstrained_gaussian\nn_samples\nget_name\nget_dimensions\nget_n_samples\nget_all_constraints(::ParameterDistribution)\nget_constraint_type\nget_bounds\nbatch\nget_distribution\nsample\nlogpdf\nmean\nvar\ncov\ntransform_constrained_to_unconstrained(::ParameterDistribution, ::AbstractVector)\ntransform_constrained_to_unconstrained(::ParameterDistribution, ::AbstractMatrix)\ntransform_constrained_to_unconstrained(::ParameterDistribution, ::Dict)\ntransform_unconstrained_to_constrained(::ParameterDistribution, ::AbstractVector)\ntransform_unconstrained_to_constrained(::ParameterDistribution, ::AbstractMatrix)\ntransform_unconstrained_to_constrained(::ParameterDistribution, ::Dict)","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution","text":"ParameterDistribution\n\nStructure to hold a parameter distribution, always stored as an array of distributions internally.\n\nFields\n\ndistribution::AbstractVector{PDType} where PDType<:EnsembleKalmanProcesses.ParameterDistributions.ParameterDistributionType\nVector of parameter distributions, defined in unconstrained space\nconstraint::AbstractVector{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType\nVector of constraints defining transformations between constrained and unconstrained space\nname::AbstractVector{ST} where ST<:AbstractString\nVector of parameter names\n\nConstructors\n\nParameterDistribution(distribution, constraint, name)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:289.\n\nParameterDistribution(param_dist_dict)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:305.\n\nParameterDistribution(distribution, constraint, name)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:389.\n\nParameterDistribution(distribution_samples, constraint, name)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:431.\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.constrained_gaussian","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.constrained_gaussian","text":"constrained_gaussian(\n name::AbstractString,\n μ_c::Real,\n σ_c::Real,\n lower_bound::Real,\n upper_bound::Real;\n repeats = 1,\n optim_algorithm::Optim.AbstractOptimizer = NelderMead(),\n optim_kwargs...,\n)\n\nConstructor for a 1D ParameterDistribution consisting of a transformed Gaussian, constrained to have support on [lower_bound, upper_bound], with first two moments μ_c and σ_c^2. The moment integrals can't be done in closed form, so we set the parameters of the distribution with numerical optimization.\n\nnote: Note\nThe intended use case is defining priors set from user expertise for use in inference with adequate data, so for the sake of performance we only require that the optimization reproduce μ_c, σ_c to a loose tolerance (1e-5). Warnings are logged when the optimization fails.\n\nnote: Note\nThe distribution may be bimodal for σ_c large relative to the width of the bound interval. In extreme cases the distribution becomes concentrated at the bound endpoints. We regard this as a feature, not a bug, and do not warn the user when bimodality occurs.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.n_samples","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.n_samples","text":"n_samples(d<:Samples)\n\nThe number of samples in the array.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_name","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_name","text":"get_name(pd::ParameterDistribution)\n\nReturns a list of ParameterDistribution names.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_dimensions","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_dimensions","text":"get_dimensions(pd::ParameterDistribution; function_parameter_opt = \"dof\")\n\nThe number of dimensions of the parameter space. (Also represents other dimensions of interest for FunctionParameterDistributionTypes with keyword argument)\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_n_samples","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_n_samples","text":"get_n_samples(pd::ParameterDistribution)\n\nThe number of samples in a Samples distribution\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints","text":"get_all_constraints(pd::ParameterDistribution; return_dict = false)\n\nReturns the (flattened) array of constraints of the parameter distribution. or as a dictionary (\"param_name\" => constraints)\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_constraint_type","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_constraint_type","text":"get_bounds(c::Constraint{T})\n\nGets the parametric type T.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_bounds","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_bounds","text":"get_bounds(c::Constraint)\n\nGets the bounds field from the Constraint.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.batch","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.batch","text":"batch(pd::ParameterDistribution; function_parameter_opt = \"dof\")\n\nReturns a list of contiguous [collect(1:i), collect(i+1:j),... ] used to split parameter arrays by distribution dimensions. function_parameter_opt is passed to ndims in the special case of FunctionParameterDistributionTypes.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_distribution","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_distribution","text":"get_distribution(pd::ParameterDistribution)\n\nReturns a Dict of ParameterDistribution distributions, with the parameter names as dictionary keys. For parameters represented by Samples, the samples are returned as a 2D (parameter_dimension x n_samples) array.\n\n\n\n\n\ngets the, distribution over the coefficients\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#StatsBase.sample","page":"ParameterDistributions","title":"StatsBase.sample","text":"sample([rng], pd::ParameterDistribution, [n_draws])\n\nDraws n_draws samples from the parameter distributions pd. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\nsample([rng], d::Samples, [n_draws])\n\nDraws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\nsample([rng], d::Parameterized, [n_draws])\n\nDraws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\nsample([rng], d::VectorOfParameterized, [n_draws])\n\nDraws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Distributions.logpdf","page":"ParameterDistributions","title":"Distributions.logpdf","text":"logpdf(pd::ParameterDistribution, xarray::Array{<:Real,1})\n\nObtains the independent logpdfs of the parameter distributions at xarray (non-Samples Distributions only), and returns their sum.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Statistics.mean","page":"ParameterDistributions","title":"Statistics.mean","text":"mean(pd::ParameterDistribution)\n\nReturns a concatenated mean of the parameter distributions. \n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Statistics.var","page":"ParameterDistributions","title":"Statistics.var","text":"var(pd::ParameterDistribution)\n\nReturns a flattened variance of the distributions\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Statistics.cov","page":"ParameterDistributions","title":"Statistics.cov","text":"cov(pd::ParameterDistribution)\n\nReturns a dense blocked (co)variance of the distributions.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractVector}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the (possibly) constrained space into unconstrained space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractMatrix}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the (possibly) constrained space into unconstrained space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, Dict}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(d::ParameterDistribution, x::Dict)\n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Here, x contains parameter names as keys, and 1- or 2-arrays as parameter samples.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractVector}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the unconstrained space into (possibly constrained) space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractMatrix}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the unconstrained space into (possibly constrained) space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, Dict}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(d::ParameterDistribution, x::Dict)\n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Here, x contains parameter names as keys, and 1- or 2-arrays as parameter samples.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#FunctionParameterDistributions","page":"ParameterDistributions","title":"FunctionParameterDistributions","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"GaussianRandomFieldsPackage\nGaussianRandomFieldInterface\nndims(grfi::GaussianRandomFieldInterface)\nget_all_constraints(grfi::GaussianRandomFieldInterface)\ntransform_constrained_to_unconstrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractVector{FT}) where {FT <: Real}\ntransform_constrained_to_unconstrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractMatrix{FT}) where {FT <: Real}\ntransform_unconstrained_to_constrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractVector{FT}) where {FT <: Real}\ntransform_unconstrained_to_constrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractMatrix{FT}) where {FT <: Real}","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage","text":"abstract type GaussianRandomFieldsPackage\n\nType to dispatch which Gaussian Random Field package to use:\n\nGRFJL uses the Julia Package GaussianRandomFields.jl \n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface","text":"struct GaussianRandomFieldInterface <: FunctionParameterDistributionType\n\nGaussianRandomFieldInterface object based on a GRF package. Only a ND->1D output-dimension field interface is implemented.\n\nFields\n\ngaussian_random_field::Any\nGRF object, containing the mapping from the field of coefficients to the discrete function\npackage::EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage\nthe choice of GRF package\ndistribution::EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution\nthe distribution of the coefficients that we shall compute with\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#Base.ndims-Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface}","page":"ParameterDistributions","title":"Base.ndims","text":"ndims(grfi::GaussianRandomFieldInterface, function_parameter_opt = \"dof\")\n\nProvides a relevant number of dimensions in different circumstances, If function_parameter_opt =\n\n\"dof\" : returns n_dofs(grfi), the degrees of freedom in the function\n\"eval\" : returns n_eval_pts(grfi), the number of discrete evaluation points of the function\n\"constraint\": returns 1, the number of constraints in the evaluation space \n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints-Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints","text":"get_all_constraints(grfi::GaussianRandomFieldInterface) = get_all_constraints(get_distribution(grfi))\n\ngets all the constraints of the internally stored coefficient prior distribution of the GRFI\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractVector{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractVector)\n\nAssume x is a flattened vector of evaluation points. Remove the constraint from constraint to the output space of the function. Note this is the inverse of transform_unconstrained_to_constrained(...,build_flag=false)\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractMatrix{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatrix)\n\nAssume x is a matrix with columns as flattened samples of evaluation points. Remove the constraint from constraint to the output space of the function. Note this is the inverse of transform_unconstrained_to_constrained(...,build_flag=false)\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractVector{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractVector)\n\nOptional Args build_flag::Bool = true\n\nTwo functions, depending on build_flag If true, assume x is a vector of coefficients. Perform the following 3 maps. \n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)\nBuild the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.\nApply the constraint from constraint to the output space of the function.\n\nIf false, Assume x is a flattened vector of evaluation points. Apply only step 3. above to x.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractMatrix{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatri)\n\nOptional args: build_flag::Bool = true\n\nTwo functions, depending on build_flag If true, assume x is a matrix with columns of coefficient samples. Perform the following 3 maps. \n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)\nBuild the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.\nApply the constraint from constraint to the output space of the function.\n\nIf false, Assume x is a matrix with columns as flattened samples of evaluation points. Apply only step 3. above to x.\n\n\n\n\n\n","category":"method"},{"location":"API/TOMLInterface/#TOML-interface","page":"TOML Interface","title":"TOML interface","text":"","category":"section"},{"location":"API/TOMLInterface/","page":"TOML Interface","title":"TOML Interface","text":"CurrentModule = EnsembleKalmanProcesses.TOMLInterface","category":"page"},{"location":"API/TOMLInterface/","page":"TOML Interface","title":"TOML Interface","text":"path_to_ensemble_member\nget_parameter_distribution\nget_parameter_values\nsave_parameter_ensemble\nget_admissible_parameters\nget_regularization\nwrite_log_file","category":"page"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.path_to_ensemble_member","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.path_to_ensemble_member","text":"path_to_ensemble_member(\n base_path,\n iteration,\n member,\n pad_zeros = 3,\n)\n\nObtains the file path to a specified ensemble member. The likely form is base_path/iteration_X/member_Y/ with X,Y padded with zeros. The file path can be reconstructed with: base_path - base path to where EKP parameters are stored member - number of the ensemble member (without zero padding) iteration - iteration of ensemble method (if =nothing then only the load path is used) pad_zeros - amount of digits to pad to\n\n\n\n\n\nOne can also call this without the iteration level\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_parameter_distribution","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_parameter_distribution","text":"get_parameter_distribution(param_dict, name)\n\nConstructs a ParameterDistribution for a single parameter\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values name - parameter name\n\nReturns a ParameterDistribution\n\n\n\n\n\nget_parameter_distribution(param_dict, names)\n\nConstructs a ParameterDistribution for an array of parameters\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values names - array of parameter names\n\nReturns a ParameterDistribution \n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_parameter_values","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_parameter_values","text":"get_parameter_values(param_dict, names)\n\nGets parameter values from a parameter dictionary, indexing by name.\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' values) name - iterable parameter names return_type - return type, default \"dict\", otherwise \"array\"\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.save_parameter_ensemble","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.save_parameter_ensemble","text":"save_parameter_ensemble(\n param_array,\n param_distribution,\n default_param_data,\n save_path,\n save_file,\n iteration\n pad_zeros=3,\napply_constraints=true\n)\n\nSaves the parameters in the given param_array to TOML files. The intended use is for saving the ensemble of parameters after each update of an ensemble Kalman process. Each ensemble member (column of param_array) is saved in a separate directory \"member\" (j=1, ..., Nens). The name of the saved toml file is given by save_file; it is the same for all members. A directory \"iteration\" is created in `savepath`, which contains all the \"member_\" subdirectories.\n\nArgs: param_array - array of size Nparam x Nens param_distribution - the parameter distribution underlying param_array apply_constraints - apply the constraints in param_distribution default_param_data - dict of default parameters to be combined and saved with the parameters in param_array into a toml file save_path - path to where the parameters will be saved save_file - name of the toml files to be generated iteration - the iteration of the ensemble Kalman process represented by the given param_array pad_zeros - the amount of zero-padding for the ensemble member number\n\n\n\n\n\nOne can also call this without the iteration level\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_admissible_parameters","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_admissible_parameters","text":"get_admissible_parameters(param_dict)\n\nFinds all parameters in param_dict that are admissible for calibration.\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values\n\nReturns an array of the names of all admissible parameters in param_dict. Admissible parameters must have a key \"prior\" and the value value of this is not set to \"fixed\". This allows for other parameters to be stored within the TOML file.\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_regularization","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_regularization","text":"get_regularization(param_dict, name)\n\nReturns the regularization information for a single parameter\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values name - parameter name\n\nReturns a tuple (, ), where the regularization type is either \"L1\" or \"L2\", and the regularization value is a float. Returns (nothing, nothing) if parameter has no regularization information.\n\n\n\n\n\nget_regularization(param_dict, names)\n\nReturns the regularization information for an array of parameters\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values names - array of parameter names\n\nReturns an arary of tuples (, ), with the ith tuple corresponding to the parameter names[i]. The regularization type is either \"L1\" or \"L2\", and the regularization value is a float. Returns (nothing, nothing) for parameters that have no regularization information.\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.write_log_file","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.write_log_file","text":"write_log_file(param_dict, file_path)\n\nWrites the parameters in param_dict into a .toml file\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values file_path - path of the file where parameters are saved\n\n\n\n\n\n","category":"function"},{"location":"examples/ClimateMachine_example/#HPC-interfacing-example:-ClimateMachine","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"","category":"section"},{"location":"examples/ClimateMachine_example/#Overview","page":"HPC interfacing example: ClimateMachine","title":"Overview","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This examples uses EnsembleKalmanProcesses.jl to calibrate a climate model, showcasing a workflow which is compatible with HPC resources managed with the SLURM workload manager. The workflow is based on read-write input/output files, and as such it is capable of interfacing with dynamical models in different code languages, or with complicated processing stages. The dynamical model for this example is ClimateMachine.jl, an Earth system model currently under development at CliMA.","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The calibration example makes use of a simple single atmospheric column model configuration with two learnable parameters that control turbulent mixing processes in the lower troposphere. It is also a perfect model experiment, in the sense that the ground truth is generated using the same model and a prescribed combination of parameters. The parameters used to generate the ground truth are (C_smag, C_drag) = (0.21, 0.0011). The evolution of the atmosphere for this setup is strongly influenced by C_smag, and very weakly by C_drag. Thus, we expect the EKP to recover C_smag from observations.","category":"page"},{"location":"examples/ClimateMachine_example/#Prerequisites","page":"HPC interfacing example: ClimateMachine","title":"Prerequisites","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This example requires ClimateMachine.jl to be installed in the same parent directory as EnsembleKalmanProcesses.jl. You may install ClimateMachine.jl directly from GitHub,","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ git clone https://github.com/CliMA/ClimateMachine.jl.git","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"Change into the ClimateMachine.jl directory with ","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ cd ClimateMachine.jl","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"and install all the required packages with:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project -e 'using Pkg; pkg\"instantiate\";'","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"Pre-compile the packages to allow the ClimateMachine.jl to start faster:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project -e 'using Pkg; pkg\"precompile\"'","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"You can find more information about ClimateMachine.jl here. ClimateMachine.jl is a rapidly evolving software and this example may stop working in the future, please open an issue if you find that to be the case!","category":"page"},{"location":"examples/ClimateMachine_example/#Structure","page":"HPC interfacing example: ClimateMachine","title":"Structure","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The example makes use of julia and bash scripts for interactions with the workload manager and running multiple forward model evaluations in parallel. The user-triggered script ekp_calibration.sbatch initializes and controls the flow of the calibration process, which in this case is a SLURM queue with job dependencies. The calibration bash scripts, in order of execution and with their associated julia scripts, are","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"ekp_init_calibration: Calls init_calibration.jl, which samples the initial parameter ensemble from a specified prior. The initial ensemble is stored in a set of parameter files.\nekp_single_cm_run: Script called in parallel by the workload manager. Each copy of the script submits a single forward model run (i.e., a ClimateMachine.jl run) given a specific pair of parameters (C_smag, C_drag) read from a corresponding file. The output of each forward model run is stored in a separate NetCDF file.\nekp_cont_calibration: Calls sstep_calibration.jl, which reads from a NetCDF file the output generated by ClimateMachine.jl in step 2 and performs an iteration of the Ensemble Kalman Inversion algorithm, updating the parameter ensemble. The new parameters are stored in new parameter files.","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This flow follows steps 1->2->3->2->3->... for a user-specified number of iterations.","category":"page"},{"location":"examples/ClimateMachine_example/#Running-the-Example","page":"HPC interfacing example: ClimateMachine","title":"Running the Example","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"From the parent directory of ClimateMachine.jl and EnsembleKalmanProcesses.jl, change into the example directory with","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ cd EnsembleKalmanProcesses.jl/examples/ClimateMachine","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"and install all the required packages for the example with:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project -e 'using Pkg; pkg\"instantiate\";'","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"To run the example using a SLURM workload manager, simply do:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ sbatch ekp_calibration.sbatch","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The dynamical model outputs (i.e, Psi(phi)) for all runs of ClimateMachine.jl will be stored in NetCDF format in directories identifiable by their version number. Refer to the files version_XX.txt to identify each run with each ensemble member within the XX iteration of the Ensemble Kalman Process. ","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"In this example, the parameters are defined through a Gaussian prior in init_calibration.jl. Hence, the transform from constrained to unconstrained space is the identity map, and we have phi=theta. Overall the forward map mathcalG(theta) is given by applying an observation map mathcalH to the dynamical model output Psi. In this case, mathcalH returns the time average of the horizontal velocity over a specified 30 min interval after initialization. Therefore, the observation vector y contains a time-averaged vertical profile of the horizontal velocity.","category":"page"},{"location":"examples/ClimateMachine_example/#Calibration-Solution","page":"HPC interfacing example: ClimateMachine","title":"Calibration Solution","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"To aggregate the parameter ensembles theta^(1) theta^(2) dots theta^(J) generated during the calibration process, you may use the agg_clima_ekp(...) function located in helper_funcs.jl,","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"include(joinpath(@__DIR__, \"helper_funcs.jl\"))\n\nagg_clima_ekp(2) # This generates the output containing the ensembles for each iteration, input is the number of parameters","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This will create the JLD file ekp_clima.jld. We may read the file as follows","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"using JLD\n\nθ = load(\"ekp_clima.jld\")[\"ekp_u\"]\nprintln(typeof(θ)) # Array{Array{Float64,2},1}, outer dimension is N_iter, inner Array{Float64,2} of size = (J, p)","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The optimal parameter vector determined by the ensemble Kalman inversion is the ensemble mean of the particles after the last iteration. Following the previous script,","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"using Statistics\n\nθ_opt = mean(θ[end], dims=1)","category":"page"},{"location":"unscented_kalman_inversion/#Unscented-Kalman-Inversion","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"One of the ensemble Kalman processes implemented in EnsembleKalmanProcesses.jl is the unscented Kalman inversion (Huang, Schneider, Stuart, 2022). The unscented Kalman inversion (UKI) is a derivative-free method for approximate Bayesian inference. We seek to find the posterior parameter distribution theta in mathbbR^p from the inverse problem","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" y = mathcalG(theta) + eta","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where mathcalG denotes the forward map, y in mathbbR^d is the vector of observations and eta sim mathcalN(0 Gamma_y) is additive Gaussian noise. Note that p is the size of the parameter vector theta and d is taken to be the size of the observation vector y. The UKI algorithm has the following properties","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"UKI has a fixed ensemble size, with members forming a quadrature stencil (rather than the random positioning of the particles from methods such as EKI). There are two quadrature options, symmetric (a 2p + 1-size stencil), and simplex (a p+2-size stencil).\nUKI has uncertainty quantification capabilities, it gives both mean and covariance approximation (no ensemble collapse and no empirical variance inflation) of the posterior distribution, the 3-sigma confidence interval covers the truth parameters for perfect models.","category":"page"},{"location":"unscented_kalman_inversion/#Algorithm","page":"Unscented Kalman Inversion","title":"Algorithm","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The UKI applies the unscented Kalman filter to the following stochastic dynamical system ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"beginaligned\n textrmevolution theta_n+1 = r + alpha (theta_n - r) + omega_n+1 omega_n+1 sim mathcalN(0Sigma_omega)\n textrmobservation y_n+1 = mathcalG(theta_n+1) + nu_n+1 nu_n+1 sim mathcalN(0Sigma_nu)\nendaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The free parameters in the UKI are alpha r Sigma_nu Sigma_omega. The UKI updates both the mean m_n and covariance C_n estimations of the parameter vector theta as following","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Prediction step :","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"beginaligned\n hatm_n+1 = r+alpha(m_n-r)\n hatC_n+1 = alpha^2 C_n + Sigma_omega\nendaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Generate sigma points (\"the ensemble\") :","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"For the sigma_points = symmetric quadrature option, the ensemble is generated as follows.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"beginaligned\n hattheta_n+1^0 = hatm_n+1 \n hattheta_n+1^j = hatm_n+1 + c_j sqrthatC_n+1_j quad (1leq jleq J) \n hattheta_n+1^j+J = hatm_n+1 - c_j sqrthatC_n+1_jquad (1leq jleq J)\nendaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where sqrtC_j is the j-th column of the Cholesky factor of C. ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Analysis step :","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" beginaligned\n haty^j_n+1 = mathcalG(hattheta^j_n+1) qquad haty_n+1 = haty^0_n+1\n hatC^theta p_n+1 = sum_j=1^2JW_j^c\n (hattheta^j_n+1 - hatm_n+1 )(haty^j_n+1 - haty_n+1)^T \n hatC^pp_n+1 = sum_j=1^2JW_j^c\n (haty^j_n+1 - haty_n+1 )(haty^j_n+1 - haty_n+1)^T + Sigma_nu\n m_n+1 = hatm_n+1 + hatC^theta p_n+1(hatC^pp_n+1)^-1(y - haty_n+1)\n C_n+1 = hatC_n+1 - hatC^theta p_n+1(hatC^pp_n+1)^-1hatC^theta p_n+1^T\n endaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Where the coefficients c_j W^c_j are given by","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" beginaligned\n c_j = asqrtJ qquad W_j^c = frac12a^2J(j=1cdots2N_theta) qquad a=minsqrtfrac4J 1 \n endaligned","category":"page"},{"location":"unscented_kalman_inversion/#Choice-of-free-parameters","page":"Unscented Kalman Inversion","title":"Choice of free parameters","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The free parameters in the unscented Kalman inversion are alpha r Sigma_nu Sigma_omega, which are chosen based on theorems developed in Huang et al, 2021","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"the vector r is set to be the prior mean\nthe scalar alpha in (01 is a regularization parameter, which is used to overcome ill-posedness and overfitting. A practical guide is \nWhen the observation noise is negligible, and there are more observations than parameters (identifiable inverse problem) alpha = 1 (no regularization)\nOtherwise alpha 1. The smaller alpha is, the closer the UKI mean will converge to the prior mean.\nthe matrix Sigma_nu is the artificial observation error covariance. We set Sigma_nu = 2 Gamma_y, which makes the inverse problem consistent. \nthe matrix Sigma_omega is the artificial evolution error covariance. We set Sigma_omega = (2 - alpha^2)Lambda. We choose Lambda as following\nwhen there are more observations than parameters (identifiable inverse problem), Lambda = C_n, which is updated as the estimated covariance C_n in the n-th every iteration. This guarantees the converged covariance matrix is a good approximation to the posterior covariance matrix with an uninformative prior.\notherwise Lambda = C_0, this allows that the converged covariance matrix is a weighted average between the posterior covariance matrix with an uninformative prior and C_0.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"In short, users only need to change the alpha (α_reg), and the frequency to update the Lambda to the current covariance (update_freq). The user can first try α_reg = 1.0 and update_freq = 0 (corresponding to Lambda = C_0).","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"note: Preventing ensemble divergence\nIf UKI suffers divergence (for example when inverse problems are not well-posed), one can prevent it by using Tikhonov regularization (see Huang, Schneider, Stuart, 2022). It is used by setting the impose_prior = true flag. In this mode, the free parameters are fixed to α_reg = 1.0, update_freq = 1. ","category":"page"},{"location":"unscented_kalman_inversion/#Implementation","page":"Unscented Kalman Inversion","title":"Implementation","text":"","category":"section"},{"location":"unscented_kalman_inversion/#Initialization","page":"Unscented Kalman Inversion","title":"Initialization","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"An unscented Kalman inversion object can be created using the EnsembleKalmanProcess constructor by specifying the Unscented() process type.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Creating an ensemble Kalman inversion object requires as arguments:","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The mean value of the observed outputs, a vector of size [d];\nThe covariance of the observational noise, a matrix of size [d × d];\nThe Unscented() process type.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The initialization of the Unscented() process requires prior mean and prior covariance, and the the size of the observation d. And user defined hyperparameters α_reg and update_freq.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\n\n# need to choose regularization factor α ∈ (0,1], \n# when you have enough observation data α=1: no regularization\nα_reg = 1.0\n# update_freq 1 : approximate posterior covariance matrix with an uninformative prior\n# 0 : weighted average between posterior covariance matrix with an uninformative prior and prior\nupdate_freq = 0\n\nprocess = Unscented(prior_mean, prior_cov; α_reg = α_reg, update_freq = update_freq)\nukiobj = EnsembleKalmanProcess(truth_sample, truth.obs_noise_cov, process)\n","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Note that no information about the forward map is necessary to initialize the Unscented process. The only forward map information required by the inversion process consists of model evaluations at the ensemble elements, necessary to update the ensemble.","category":"page"},{"location":"unscented_kalman_inversion/#Constructing-the-Forward-Map","page":"Unscented Kalman Inversion","title":"Constructing the Forward Map","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"At the core of the forward map mathcalG is the dynamical model PsimathbbR^p rightarrow mathbbR^o (running Psi is usually where the computational heavy-lifting is done), but the map mathcalG may include additional components such as a transformation of the (unbounded) parameters theta to a constrained domain the dynamical model can work with, or some post-processing of the output of Psi to generate the observations. For example, mathcalG may take the following form:","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"mathcalG = mathcalH circ Psi circ mathcalT^-1","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where mathcalHmathbbR^o rightarrow mathbbR^d is the observation map and mathcalT is the transformation from the constrained to the unconstrained parameter space, such that mathcalT(phi)=theta. A family of standard transformations and their inverses are available in the ParameterDistributions module.","category":"page"},{"location":"unscented_kalman_inversion/#Updating-the-Ensemble","page":"Unscented Kalman Inversion","title":"Updating the Ensemble","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Once the unscented Kalman inversion object UKIobj has been initialized, any number of updates can be performed using the inversion algorithm.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"A call to the inversion algorithm can be performed with the update_ensemble! function. This function takes as arguments the UKIobj and the evaluations of the forward map at each element of the current ensemble. The update_ensemble! function then stores the new updated ensemble and the inputted forward map evaluations in UKIobj.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The forward map mathcalG maps the space of unconstrained parameters theta to the outputs y in mathbbR^d. In practice, the user may not have access to such a map directly. And the map is a composition of several functions. The update_ensemble! uses only the evalutaions g_ens but not the forward map ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"For implementational reasons, the update_ensemble is performed by computing analysis stage first, followed by a calculation of the next sigma ensemble. The first sigma ensemble is created in the initialization.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"# Given:\n# Ψ (some black box simulator)\n# H (some observation of the simulator output)\n# prior (prior distribution and parameter constraints)\n\nN_iter = 20 # Number of steps of the algorithm\n \nfor n in 1:N_iter\n ϕ_n = get_ϕ_final(prior, ukiobj) # Get current ensemble in constrained \"ϕ\"-space\n G_n = [H(Ψ(ϕ_n[:, i])) for i in 1:J] # Evaluate forward map\n g_ens = hcat(G_n...) # Reformat into `d x N_ens` matrix\n EnsembleKalmanProcesses.update_ensemble!(ukiobj, g_ens) # Update ensemble\nend","category":"page"},{"location":"unscented_kalman_inversion/#Solution","page":"Unscented Kalman Inversion","title":"Solution","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The solution of the unscented Kalman inversion algorithm is a Gaussian distribution whose mean and covariance can be extracted from the ''last ensemble'' (i.e., the ensemble after the last iteration). The sample mean of the last ensemble is also the \"optimal\" parameter (θ_optim) for the given calibration problem. These statistics can be accessed as follows: ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"# mean of the Gaussian distribution, also the optimal parameter for the calibration problem\nθ_optim = get_u_mean_final(ukiobj)\n# covariance of the Gaussian distribution\nsigma_optim = get_u_cov_final(ukiobj)","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"There are two examples: Lorenz96 and Cloudy.","category":"page"},{"location":"unscented_kalman_inversion/#Handling-forward-model-failures","page":"Unscented Kalman Inversion","title":"Handling forward model failures","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"In situations where the forward model mathcalG represents a diagnostic of a complex computational model, there might be cases where for some parameter combinations theta, attempting to evaluate mathcalG(theta) may result in model failure (defined as returning a NaN from the point of view of this package). In such cases, the UKI update equations must be modified to handle model failures.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"EnsembleKalmanProcesses.jl implements such modifications through the FailureHandler structure, an input to the EnsembleKalmanProcess constructor. Currently, the only failsafe modification available is SampleSuccGauss(), described in Lopez-Gomez et al (2022).","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"To employ this modification, construct the EKI object as","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\n\n# need to choose regularization factor α ∈ (0,1], \n# when you have enough observation data α=1: no regularization\nα_reg = 1.0\n# update_freq 1 : approximate posterior covariance matrix with an uninformative prior\n# 0 : weighted average between posterior covariance matrix with an uninformative prior and prior\nupdate_freq = 0\n\nprocess = Unscented(prior_mean, prior_cov; α_reg = α_reg, update_freq = update_freq)\nukiobj = EnsembleKalmanProcess(\n truth_sample,\n truth.obs_noise_cov,\n process,\n failure_handler_method = SampleSuccGauss())\n","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"info: Forward model requirements when using FailureHandlers\nThe user must determine if a model run has \"failed\", and replace the output mathcalG(theta) with NaN. The FailureHandler takes care of the rest.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"A description of the algorithmic modification is included below.","category":"page"},{"location":"unscented_kalman_inversion/#SampleSuccGauss-modification","page":"Unscented Kalman Inversion","title":"SampleSuccGauss modification","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The SampleSuccGauss() modification is based on performing the UKI quadratures over the successful sigma points. Consider the set of off-center sigma points hattheta = hattheta_s cup hattheta_f where hattheta_s^(j), j=1 dots J_s are successful members and hattheta_f^(k) are not. For ease of notation, consider an ordering of hattheta such that hattheta_s are its first J_s elements, and note that we deal with the central point hattheta^(0) separately. We estimate the covariances mathrmCov_q(mathcalG_n mathcalG_n) and mathrmCov_q(theta_n mathcalG_n) from the successful ensemble,","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" tag1 mathrmCov_q(theta_n mathcalG_n) approx sum_j=1^J_sw_sj (hattheta_s n^(j) - bartheta_sn)(mathcalG(hattheta_s n^(j)) - barmathcalG_sn)^T","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" tag2 mathrmCov_q(mathcalG_n mathcalG_n) approx sum_j=1^J_sw_sj (mathcalG(hattheta_s n^(j)) - barmathcalG_sn)(mathcalG(hattheta_s n^(j)) - barmathcalG_sn)^T","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where the weights at each successful sigma point are scaled up, to preserve the sum of weights,","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" w_sj = left(dfracsum_i=1^2p w_isum_k=1^J_s w_kright)w_j","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"In equations (1) and (2), the means bartheta_sn and barmathcalG_sn must be modified from the original formulation if the central point hattheta^(0)=m_n results in model failure. If this is the case, then an average is taken across the other (successful) ensemble members","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" bartheta_sn =\ndfrac1J_ssum_j=1^J_shattheta_s n^(j) qquad barmathcalG_sn =\ndfrac1J_ssum_j=1^J_smathcalG(hattheta_s n^(j))","category":"page"},{"location":"examples/Cloudy_example/#Cloudy-example","page":"Cloudy","title":"Cloudy Example","text":"","category":"section"},{"location":"examples/Cloudy_example/#Overview","page":"Cloudy","title":"Overview","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"This example is based on Cloudy, a microphysics model that simulates how cloud droplets collide and coalesce into larger drops. Collision-coalescence is a crucial process for the formation of rain. ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy is initialized with a mass distribution of the cloud droplets; this distribution is then evolved in time, with more and more droplets colliding and combining into bigger drops according to the droplet-droplet interactions specified by a collision-coalescence kernel. The evolution is completely determined by the shape of the initial distribution and the form of the kernel.","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"This example shows how ensemble Kalman methods can be used to learn the parameters of the initial cloud droplet mass distribution from observations of the moments of that mass distribution at a later time. The collision-coalescence kernel is assumed to be known, but one could also learn the parameters of the kernel instead of the parameters of the droplet distribution (or both).","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy is used here in a \"perfect model\" (aka \"known truth\") setting, which means that the \"observations\" are generated by Cloudy itself, by running it with the true parameter values. In more realistic applications, this parameter estimation procedure will use actual measurements of cloud properties to obtain an estimated droplet mass distribution at a previous time.","category":"page"},{"location":"examples/Cloudy_example/#Prerequisites","page":"Cloudy","title":"Prerequisites","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"In order to run this example, you need to install Cloudy.jl (the \"#master\" lets you install the current master branch):","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"pkg > add Cloudy#master","category":"page"},{"location":"examples/Cloudy_example/#Structure","page":"Cloudy","title":"Structure","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The file Cloudy_example_eki.jl sets up the inverse problem and solves it using ensemble Kalman inversion, and the file Cloudy_example_uki.jl does the same using unscented Kalman inversion. The file DynamicalModel.jl provides the functionality to run the dynamical model Psi, which in this example is Cloudy.","category":"page"},{"location":"examples/Cloudy_example/#Running-the-Example","page":"Cloudy","title":"Running the Example","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Once Cloudy is installed, the examples can be run from the julia REPL:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"# Solve inverse problem using ensemble Kalman inversion\ninclude(\"Cloudy_example_eki.jl\")","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"or","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"# Solve inverse problem using unscented Kalman inversion\ninclude(\"Cloudy_example_uki.jl\")","category":"page"},{"location":"examples/Cloudy_example/#What-Does-Cloudy-Do?","page":"Cloudy","title":"What Does Cloudy Do?","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The mathematical starting point of Cloudy is the stochastic collection equation (SCE; sometimes also called Smoluchowski equation after Marian Smoluchowski), which describes the time rate of change of f = f(m t), the mass distribution function of liquid water droplets, due to the process of collision and coalescence. The distribution function f depends on droplet mass m and time t and is defined such that f(m) text dm denotes the number of droplets with masses in the interval m m + dm per unit volume. ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The stochastic collection equation is an integro-differential equation that can be written as ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" fracpartial f(m t)partial t = frac12 int_m=0^infty f(m t) f(m-m t) mathcalC(m m-m)textdm - f(m t) int_m=0^infty f(m t)mathcalC(m m) textdm ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"where mathcalC(m m) is the collision-coalescence kernel, which encapsulates the physics of droplet-droplet interactions – it describes the rate at which two drops of masses m and m come into contact and coalesce into a drop of mass m + m. The first term on the right-hand side of the SCE describes the rate of increase of the number of drops having a mass m due to collision and coalescence of drops of masses m and m-m (where the factor frac12 avoids double counting), while the second term describes the rate of reduction of drops of mass m due to collision and coalescence of drops having a mass m with other drops. ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"We can rewrite the SCE in terms of the moments M_k of f, which are the prognostic variables in Cloudy. They are defined by","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" M_k = int_0^infty m^k f(m t) textdm","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The time rate of change of the k-th moment of f is obtained by multiplying the SCE by m^k and integrating over the entire range of droplet masses (from m=0 to infty), which yields","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" fracpartial M_k(t)partial t = frac12int_0^infty left((m+m)^k - m^k - m^kright) mathcalC(m m)f(m t)f(m t) textdm textdm (1)","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"In this example, the kernel is set to be constant – mathcalC(m m) = B = textconst – and the cloud droplet mass distribution is assumed to be a textGamma(k_t theta_t) distribution, scaled by a factor N_0t which denotes the droplet number concentration:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"f(m t) = fracN_0tGamma(k_t)theta_t^k m^k_t-1 exp(-mtheta_t)","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The parameter vector phi_t= N_0t k_t theta_t changes over time (as indicated by the subscript t), as the shape of the distribution evolves. In fact, there is a priori no reason to assume that the distribution would retain its Gamma shape over time, but this is a common assumption that is made in order to solve the closure problem (without this assumption, one would have to keep track of infinitely many moments of the mass distribution in order to uniquely identify the distribution f at each time step, which is obviously not practicable).","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"For Gamma mass distribution functions, specifying the first three moments (M_0, M_1, and M_2) is sufficient to uniquely determine the parameter vector phi_t, hence Cloudy solves equation (1) for k = 0 1 2. This mapping of the parameters of the initial cloud droplet mass distribution to the (zeroth-, first-, and second-order) moments of the distribution at a specified end time is done by DynamicalModel.jl.","category":"page"},{"location":"examples/Cloudy_example/#Setting-up-the-Inverse-Problem","page":"Cloudy","title":"Setting up the Inverse Problem","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The goal is to learn the distribution parameters at time t = 0, phi_0 = N_00 k_0 theta_0, from observations y = M_0(t_end) M_1(t_end) M_2(t_end) of the zeroth-, first-, and second-order moments of the distribution at time t_end 0 (where t_end = 1.0 in this example). This is a known truth experiment, in which the true parameters phi_0 texttrue are defined to be:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"N0_true = 300.0 # number of particles (scaling factor for Gamma distribution)\nθ_true = 1.5597 # scale parameter of Gamma distribution\nk_true = 0.0817 # shape parameter of Gamma distribution","category":"page"},{"location":"examples/Cloudy_example/#Priors","page":"Cloudy","title":"Priors","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"In the code, the priors are constructed as follows:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"par_names = [\"N0\", \"θ\", \"k\"]\n# constrained_gaussian(\"name\", desired_mean, desired_std, lower_bd, upper_bd)\nprior_N0 = constrained_gaussian(par_names[1], 400, 300, 0.4 * N0_true, Inf)\nprior_θ = constrained_gaussian(par_names[2], 1.0, 5.0, 1e-1, Inf)\nprior_k = constrained_gaussian(par_names[3], 0.2, 1.0, 1e-4, Inf)\npriors = combine_distributions([prior_N0, prior_θ, prior_k])","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"We use the recommended constrained_gaussian to add the desired scale and bounds to the prior distribution, in particular we place lower bounds to preserve positivity (and numerical stability). ","category":"page"},{"location":"examples/Cloudy_example/#Observational-Noise","page":"Cloudy","title":"Observational Noise","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy produces output y = M_0(t_end) M_1(t_end) M_2(t_end), which is assumed to be related to the parameter vector theta according to:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" y = mathcalG(theta) + eta","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"where mathcalG = Psi circ mathcalT^-1 is the forward map, and the observational noise eta is assumed to be drawn from a 3-dimensional Gaussian with distribution mathcalN(0 Gamma_y). In a perfect model setting, the observational noise represents the internal model variability. Since Cloudy is a purely deterministic model, there is no straightforward way of coming up with a covariance Gamma_y for this internal noise. We decide to use a diagonal covariance with the following entries (variances):","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Γy = convert(Array, Diagonal([100.0, 5.0, 30.0]))","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Artificial observations (\"truth samples\") are then generated by adding random samples from eta to G_t, the forward map evaluated for the true parameters:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"for i in 1:n_samples\n y_t[:, i] = G_t .+ rand(MvNormal(μ, Γy))\nend\n\ntruth = Observations.Observation(y_t, Γy, data_names)","category":"page"},{"location":"examples/Cloudy_example/#Solution-and-Output","page":"Cloudy","title":"Solution and Output","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy_example_eki.jl: The optimal parameter vector determined by the ensemble Kalman inversion is the ensemble mean of the particles after the last iteration, which is printed to standard output. An output directory is created, where two files are stored: parameter_storage_eki.jld2 and data_storage_eki.jld2, which contain all parameters and model output from the ensemble Kalman iterations, respectively (both as DataContainers.DataContainer objects). In addition, an animation is produced that shows the evolution of the ensemble of particles over subsequent iterations of the optimization, both in the computational (unconstrained) and physical (constrained) spaces.\nCloudy_example_uki.jl: In addition to a point estimate of the optimal parameter (which is again given by the ensemble mean of the last iteration and printed to standard output), unscented Kalman inversion also provides a covariance approximation of the posterior distribution. Together, the mean and covariance allow for the reconstruction of a Gaussian approximation of the posterior distribution. The evolution of this Gaussian approximation over subsequent iterations is shown as an animation over the computational (unconstrained) space. All parameters as well as the model output from the unscented Kalman inversion are stored in an output directory, as parameter_storage_uki.jld2 and data_storage_uki.jld2. ","category":"page"},{"location":"examples/Cloudy_example/#Playing-Around","page":"Cloudy","title":"Playing Around","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"If you want to play around with the Cloudy examples, you can e.g. change the type or the parameters of the initial cloud droplet mass distribution (see Cloudy.ParticleDistributions for the available distributions), by modifying these lines:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"ϕ_true = [N0_true, θ_true, k_true]\ndist_true = ParticleDistributions.GammaPrimitiveParticleDistribution(ϕ_true...)","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"(Don't forget to also change dist_type accordingly).","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"You can also experiment with different noise covariances (Γy), priors, vary the number of iterations (N_iter) or ensemble particles (N_ens), etc.","category":"page"},{"location":"API/SparseInversion/#Sparse-Ensemble-Kalman-Inversion","page":"SparseInversion","title":"Sparse Ensemble Kalman Inversion","text":"","category":"section"},{"location":"API/SparseInversion/","page":"SparseInversion","title":"SparseInversion","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/SparseInversion/","page":"SparseInversion","title":"SparseInversion","text":"SparseInversion\nsparse_eki_update\nsparse_qp","category":"page"},{"location":"API/SparseInversion/#EnsembleKalmanProcesses.SparseInversion","page":"SparseInversion","title":"EnsembleKalmanProcesses.SparseInversion","text":"SparseInversion <: Process\n\nA sparse ensemble Kalman Inversion process\n\nFields\n\nγ::AbstractFloat\nupper limit of l1-norm\nthreshold_value::AbstractFloat\nthreshold below which the norm of parameters is pruned to zero\nuc_idx::Union{Colon, AbstractVector}\nindices of parameters included in the evaluation of l1-norm constraint\nreg::AbstractFloat\na small regularization value to enhance robustness of convex optimization\n\nConstructors\n\nSparseInversion(γ, threshold_value, uc_idx, reg)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:21.\n\nSparseInversion(γ)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:31.\n\nSparseInversion()\n\n\n\n\n\n","category":"type"},{"location":"API/SparseInversion/#EnsembleKalmanProcesses.sparse_eki_update","page":"SparseInversion","title":"EnsembleKalmanProcesses.sparse_eki_update","text":" sparse_eki_update(\n ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},\n u::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n y::AbstractMatrix{FT},\n obs_noise_cov::Union{AbstractMatrix{CT}, UniformScaling{CT}},\n) where {FT <: Real, CT <: Real, IT}\n\nReturns the sparse updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (3.7) and (3.14) of Schneider et al. (2021).\n\nLocalization is applied following Tong and Morzfeld (2022).\n\n\n\n\n\n","category":"function"},{"location":"API/SparseInversion/#EnsembleKalmanProcesses.sparse_qp","page":"SparseInversion","title":"EnsembleKalmanProcesses.sparse_qp","text":"sparse_qp(\n ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},\n v_j::Vector{FT},\n cov_vv_inv::AbstractMatrix{FT},\n H_u::SparseArrays.SparseMatrixCSC{FT},\n H_g::SparseArrays.SparseMatrixCSC{FT},\n y_j::Vector{FT};\n H_uc::SparseArrays.SparseMatrixCSC{FT} = H_u,\n) where {FT, IT}\n\nSolving quadratic programming problem with sparsity constraint.\n\n\n\n\n\n","category":"function"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"EditURL = \"../../../examples/SparseLossMinimization/loss_minimization_sparse_eki.jl\"","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Minimization-of-simple-loss-functions-with-sparse-EKI","page":"Sparse Minimization Loss","title":"Minimization of simple loss functions with sparse EKI","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"First we load the required packages.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"using Distributions, LinearAlgebra, Random, Plots\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Loss-function-with-single-minimum","page":"Sparse Minimization Loss","title":"Loss function with single minimum","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"Here, we minimize the loss function","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"G₁(u) = u - u_* ","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"where u is a 2-vector of parameters and u_* is given; here u_* = (1 0).","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"u★ = [1, 0]\nG₁(u) = [sqrt((u[1] - u★[1])^2 + (u[2] - u★[2])^2)]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We set the seed for pseudo-random number generator for reproducibility.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"rng_seed = 41\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We set a stabilization level, which can aid the algorithm convergence","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"dim_output = 1\nstabilization_level = 1e-3\nΓ_stabilization = stabilization_level * Matrix(I, dim_output, dim_output)","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"The functional is positive so to minimize it we may set the target to be 0,","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"G_target = [0]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Prior-distributions","page":"Sparse Minimization Loss","title":"Prior distributions","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"As we work with a Bayesian method, we define a prior. This will behave like an \"initial guess\" for the likely region of parameter space we expect the solution to live in. Here we define Normal(02^2) distributions with no constraints","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"prior_u1 = constrained_gaussian(\"u1\", 0, 2, -Inf, Inf)\nprior_u2 = constrained_gaussian(\"u1\", 0, 2, -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"note: Note\nIn this example there are no constraints, therefore no parameter transformations.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Calibration","page":"Sparse Minimization Loss","title":"Calibration","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We choose the number of ensemble members and the number of iterations of the algorithm","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"N_ensemble = 20\nN_iterations = 10\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"The initial ensemble is constructed by sampling the prior","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"initial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"Sparse EKI parameters","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"γ = 1.0\nthreshold_value = 1e-2\nreg = 1e-3\nuc_idx = [1, 2]\n\nprocess = SparseInversion(γ, threshold_value, uc_idx, reg)","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We then initialize the Ensemble Kalman Process algorithm, with the initial ensemble, the target, the stabilization and the process type (for sparse EKI this is SparseInversion).","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"ensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, G_target, Γ_stabilization, process)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"Then we calibrate by (i) obtaining the parameters, (ii) calculate the loss function on the parameters (and concatenate), and last (iii) generate a new set of parameters using the model outputs:","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"for i in 1:N_iterations\n params_i = get_u_final(ensemble_kalman_process)\n\n g_ens = hcat([G₁(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, g_ens)\nend","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"and visualize the results:","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"u_init = get_u_prior(ensemble_kalman_process)\n\nanim_unique_minimum = @animate for i in 1:N_iterations\n u_i = get_u(ensemble_kalman_process, i)\n\n plot(\n [u★[1]],\n [u★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :red,\n label = \"optimum u⋆\",\n )\n\n plot!(\n u_i[1, :],\n u_i[2, :],\n seriestype = :scatter,\n xlims = extrema(u_init[1, :]),\n ylims = extrema(u_init[2, :]),\n xlabel = \"u₁\",\n ylabel = \"u₂\",\n markersize = 5,\n markeralpha = 0.6,\n markercolor = :blue,\n label = \"particles\",\n title = \"EKI iteration = \" * string(i),\n )\nend\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"The results show that the minimizer of G_1 is u=u_*.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"gif(anim_unique_minimum, \"unique_minimum_sparse.gif\", fps = 1) # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"This page was generated using Literate.jl.","category":"page"},{"location":"#EnsembleKalmanProcesses","page":"Home","title":"EnsembleKalmanProcesses","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"EnsembleKalmanProcesses.jl (EKP) is a library of derivative-free Bayesian optimization techniques based on ensemble Kalman Filters, a well known family of approximate filters used for data assimilation. The tools in this library enable fitting parameters found in expensive black-box computer codes without the need for adjoints or derivatives. This property makes them particularly useful when calibrating non-deterministic models, or when the training data are noisy.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Currently, the following methods are implemented in the library:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Ensemble Kalman Inversion (EKI) - The traditional optimization technique based on the Ensemble Kalman Filter EnKF (Iglesias, Law, Stuart, 2013),\nEnsemble Kalman Sampler (EKS) - also obtains a Gaussian Approximation of the posterior distribution, through a Monte Carlo integration (Garbuno-Inigo, Hoffmann, Li, Stuart, 2020),\nUnscented Kalman Inversion (UKI) - also obtains a Gaussian Approximation of the posterior distribution, through a quadrature based integration approach (Huang, Schneider, Stuart, 2022),\nSparsity-inducing Ensemble Kalman Inversion (SEKI) - Additionally adds approximate L^0 and L^1 penalization to the EKI (Schneider, Stuart, Wu, 2020).","category":"page"},{"location":"","page":"Home","title":"Home","text":"Module Purpose\nEnsembleKalmanProcesses.jl Collection of all tools\nEnsembleKalmanProcess.jl Implementations of EKI, EKS, UKI, and SEKI\nObservations.jl Structure to hold observational data\nParameterDistributions.jl Structures to hold prior and posterior distributions\nDataContainers.jl Structure to hold model parameters and outputs\nLocalizers.jl Covariance localization kernels","category":"page"},{"location":"#Learning-the-amplitude-and-vertical-shift-of-a-sine-curve","page":"Home","title":"Learning the amplitude and vertical shift of a sine curve","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"(Image: Ensemble of parameter estimates by iteration)","category":"page"},{"location":"","page":"Home","title":"Home","text":"See full example for the code.","category":"page"},{"location":"#Authors","page":"Home","title":"Authors","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"EnsembleKalmanProcesses.jl is being developed by the Climate Modeling Alliance. The main developers are Oliver R. A. Dunbar and Ignacio Lopez-Gomez.","category":"page"},{"location":"parallel_hpc/#parallel-hpc","page":"Parallelism and HPC","title":"Parallelism and High Performance Computing (HPC)","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"One benefit of ensemble methods is their ability to be parallelized. The parallellism occurs outside of the EKP update, and so is not present in the source code. On this page we provide suggestions for parallelization for two types of problems:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Run a parallel loop or map within your current Julia session.\nRun a parallel loop through a read/write file interface and workload manager. We provide some utilities to read/write files in a TOML format.","category":"page"},{"location":"parallel_hpc/#Case-1:-Parallel-code-within-Julia","page":"Parallelism and HPC","title":"Case 1: Parallel code within Julia","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Let's look at the simple example for the Lorenz 96 dynamical system. In particular we'll focus on the evaluations of the Lorenz 96 solver explicitly written in GModel.jl that contains the following loop over the N_ens-sized ensemble:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"function run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = zeros(nd, N_ens)\n for i in 1:N_ens\n # run the model with the current parameters, i.e., map θ to G(θ)\n g_ens[:, i] = lorenz_forward(settings, lorenz_params[i])\n end\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Each ensemble member i runs the Lorenz 96 model with settings configuration, and model parameters lorenz_params[i]. The runs do not interact with each other, and the user has several options to parallelize.","category":"page"},{"location":"parallel_hpc/#Running-examples:","page":"Parallelism and HPC","title":"Running examples:","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"All of the following example cases are covered in distributed_Lorenz_example.jl. At the top of file uncomment one of the following options","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"case = multithread \ncase = pmap \ncase = distfor ","category":"page"},{"location":"parallel_hpc/#Multithreading,-@threads","page":"Parallelism and HPC","title":"Multithreading, @threads","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"To parallelize with multithreading, julia must call the file with a prespecified number of threads. For example, for 4 threads, ","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"$ julia --project -t 4 distributed_Lorenz_example.jl","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"We exploit the multithreading over N_ens ensemble members in this example with the following loop in GModel_multithread.jl:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"function run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = zeros(nd, N_ens)\n Threads.@threads for i in 1:N_ens\n # run the model with the current parameters, i.e., map θ to G(θ)\n g_ens[:, i] = lorenz_forward(settings, lorenz_params[i])\n end\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"You can read more about multi-threading here.","category":"page"},{"location":"parallel_hpc/#Parallel-map,-pmap","page":"Parallelism and HPC","title":"Parallel map, pmap","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"When using multiple processes, the Julia environment must first be loaded on each worker processor. We include these lines in the main file","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\naddprocs(4; exeflags = \"--project\")","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"And we would call the file is called by","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"$ julia --project distributed_Lorenz_example","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"This ensures that we obtain 4 worker processes that are loaded with julia's current environment specified by --project (unlike when calling julia --project -p 4). We use pmap to apply a function to each element of the list (i.e the ensemble member configurations). For example, see the following code from GModel_pmap.jl,","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\nfunction run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = zeros(nd, N_ens)\n g_ens[:, :] = vcat(pmap(x -> lorenz_forward(settings, x), lorenz_params)...)\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"If pmap is called within a module, that module will also need to be loaded on all workers. For this we use the macro @everywhere module XYZ.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"You can read more about pmap here.","category":"page"},{"location":"parallel_hpc/#Distributed-loop,-@distributed-for","page":"Parallelism and HPC","title":"Distributed loop, @distributed for","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"When using multiple processes, the Julia environment must also be loaded on each worker processor. We include these lines in the main file","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\naddprocs(4; exeflags = \"--project\")","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"And we would call the file is called by","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"$ julia --project distributed_Lorenz_example","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"When using distributed loops, it is necessary to be able to write to shared memory. To do this we use the SharedArrays package. For example, see the following distributed loop in GModel_distfor ","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\nusing SharedArrays\nfunction run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = SharedArray{Float64}(nd, N_ens)\n @sync @distributed for i in 1:N_ens\n # run the model with the current parameters, i.e., map θ to G(θ)\n g_ens[:, i] = lorenz_forward(settings, lorenz_params[i])\n end\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"@sync forces the code to wait until all processes in the @distributed for loop are complete before continuing.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"If @distributed for is used within another module, that module will also need to be loaded on each worker processor. For this we use the macro @everywhere module XYZ.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"note: Note\n@distributed for is most performant when there is a large ensemble, N_ens, and the forward map is computationally cheap. Otherwise, pmap is usually the preferred choice.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"You can read more about @distributed here","category":"page"},{"location":"parallel_hpc/#Case-2:-HPC-interface","page":"Parallelism and HPC","title":"Case 2: HPC interface","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Some applications involve interfacing with non-Julia code or using HPC workload managers. In these cases we suggest using an alternative workflow where one interleaves scripts that launch EKP updates and scripts that runs the model. One possible implementation is the following loop","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Step 0(a). Write an ensemble of parameter files parameters_0_i for i = 1:N_ens, with each parameter file containing a sample from the prior distribution.\nStep 0(b). Construct EKP EKP object and save in jld2 format e.g. ekpobject.jld2.\nfor n = 1,..., N_it, do:\nStep n(a). Run N_ens forward models, with forward model i running with the corresponding parameter file parameters_{n-1}_i. Write processed output data to file data_{n-1}_i.\nStep n(b). Run the ensemble update, by loading both ekpobject.jld2 and reading in the parameter files data_{n-1}_i for i = 1:N_ens. Perform the EKP update step. Write new parameter files parameters_n_i for i = 1:N_ens. Save the ensemble object in ekpobject.jld2\niterate n -> n+1.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"In HPC interfacing example: ClimateMachine we implement a similar loop to interface with a SLURM workload manager for HPC. Here, sbatch scripts are used to run each component of the calibration procedure. The outer loop over the EKP iterations lives in the overarching sbatch script, and for each iteration, the inner loop are realised as \"arrays\" of slurm jobs (1, ..., N_ens), launched for each ensemble member. The code excerpt below, taken from ekp_calibration.sbatch for details), illustrates this procedure:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"# First call to calibrate.jl will create the ensemble files from the priors\nid_init_ens=$(sbatch --parsable ekp_init_calibration.sbatch)\nfor it in $(seq 1 1 $n_it)\ndo\n# Parallel runs of forward model\nif [ \"$it\" = \"1\" ]; then\n id_ens_array=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_init_ens --array=1-$n ekp_single_cm_run.sbatch $it)\nelse\n id_ens_array=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_ek_upd --array=1-$n ekp_single_cm_run.sbatch $it)\nfi\nid_ek_upd=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_ens_array --export=n=$n ekp_cont_calibration.sbatch $it)\ndone","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Here a dependency tree is set up in SLURM, which iterates calls to the scripts ekp_single_cm_run.sbatch (which runs the forward model on HPC) and ekp_cont_calibration.sbatch (which performs an EKI update). We find this a smooth workflow that uses HPC resources well, and can likely be set up on other workload managers.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"For more details see the code and docs for the HPC interfacing example: ClimateMachine.","category":"page"},{"location":"API/DataContainers/#DataContainers","page":"DataContainers","title":"DataContainers","text":"","category":"section"},{"location":"API/DataContainers/","page":"DataContainers","title":"DataContainers","text":"CurrentModule = EnsembleKalmanProcesses.DataContainers","category":"page"},{"location":"API/DataContainers/","page":"DataContainers","title":"DataContainers","text":"DataContainer\nPairedDataContainer\nsize","category":"page"},{"location":"API/DataContainers/#EnsembleKalmanProcesses.DataContainers.DataContainer","page":"DataContainers","title":"EnsembleKalmanProcesses.DataContainers.DataContainer","text":"DataContainer{FT <: Real}\n\nContainer to store data samples as columns in an array.\n\n\n\n\n\n","category":"type"},{"location":"API/DataContainers/#EnsembleKalmanProcesses.DataContainers.PairedDataContainer","page":"DataContainers","title":"EnsembleKalmanProcesses.DataContainers.PairedDataContainer","text":"PairedDataContainer{FT <: Real}\n\nStores input - output pairs as data containers, there must be an equal number of inputs and outputs.\n\n\n\n\n\n","category":"type"},{"location":"API/DataContainers/#Base.size","page":"DataContainers","title":"Base.size","text":"size(c<:ConstraintType)\n\nA constraint has size 1.\n\n\n\n\n\nsize(dc::DataContainer, idx::IT) where {IT <: Integer}\n\nReturns the size of the stored data. If idx provided, it returns the size along dimension idx.\n\n\n\n\n\nsize(pdc::PairedDataContainer, idx::IT) where {IT <: Integer}\n\nReturns the sizes of the inputs and ouputs along dimension idx (if provided).\n\n\n\n\n\n","category":"function"}] +[{"location":"API/Sampler/#Ensemble-Kalman-Sampler","page":"Sampler","title":"Ensemble Kalman Sampler","text":"","category":"section"},{"location":"API/Sampler/","page":"Sampler","title":"Sampler","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/Sampler/","page":"Sampler","title":"Sampler","text":"Sampler\neks_update","category":"page"},{"location":"API/Sampler/#EnsembleKalmanProcesses.Sampler","page":"Sampler","title":"EnsembleKalmanProcesses.Sampler","text":"Sampler{FT<:AbstractFloat,IT<:Int} <: Process\n\nAn ensemble Kalman Sampler process.\n\nFields\n\nprior_mean::Vector{FT} where FT<:AbstractFloat\nMean of Gaussian parameter prior in unconstrained space\nprior_cov::Union{LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}} where FT<:AbstractFloat\nCovariance of Gaussian parameter prior in unconstrained space\n\nConstructors\n\nSampler(prior_mean, prior_cov)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:17.\n\nSampler(prior)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:23.\n\n\n\n\n\n","category":"type"},{"location":"API/Sampler/#EnsembleKalmanProcesses.eks_update","page":"Sampler","title":"EnsembleKalmanProcesses.eks_update","text":" eks_update(\n ekp::EnsembleKalmanProcess{FT, IT, Sampler{FT}},\n u::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n) where {FT <: Real, IT}\n\nReturns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the sampler algorithm.\n\nThe current implementation assumes that rows of u and g correspond to ensemble members, so it requires passing the transpose of the u and g arrays associated with ekp.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#Unscented-Kalman-Inversion","page":"Unscented","title":"Unscented Kalman Inversion","text":"","category":"section"},{"location":"API/Unscented/","page":"Unscented","title":"Unscented","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/Unscented/","page":"Unscented","title":"Unscented","text":"Unscented\nconstruct_sigma_ensemble\nconstruct_mean\nconstruct_cov\nupdate_ensemble_prediction!\nupdate_ensemble_analysis!","category":"page"},{"location":"API/Unscented/#EnsembleKalmanProcesses.Unscented","page":"Unscented","title":"EnsembleKalmanProcesses.Unscented","text":"Unscented{FT<:AbstractFloat, IT<:Int} <: Process\n\nAn unscented Kalman Inversion process.\n\nFields\n\nu_mean::Any\nan interable of arrays of size N_parameters containing the mean of the parameters (in each uki iteration a new array of mean is added), note - this is not the same as the ensemble mean of the sigma ensemble as it is taken prior to prediction\nuu_cov::Any\nan iterable of arrays of size (N_parameters x N_parameters) containing the covariance of the parameters (in each uki iteration a new array of cov is added), note - this is not the same as the ensemble cov of the sigma ensemble as it is taken prior to prediction\nobs_pred::Any\nan iterable of arrays of size N_y containing the predicted observation (in each uki iteration a new array of predicted observation is added)\nc_weights::AbstractVecOrMat{FT} where FT<:AbstractFloat\nweights in UKI\nmean_weights::AbstractVector{FT} where FT<:AbstractFloat\ncov_weights::AbstractVector{FT} where FT<:AbstractFloat\nN_ens::Int64\nnumber of particles 2N+1 or N+2\nΣ_ω::AbstractMatrix{FT} where FT<:AbstractFloat\ncovariance of the artificial evolution error\nΣ_ν_scale::AbstractFloat\ncovariance of the artificial observation error\nα_reg::AbstractFloat\nregularization parameter\nr::AbstractVector{FT} where FT<:AbstractFloat\nregularization vector\nupdate_freq::Int64\nupdate frequency\nimpose_prior::Bool\nusing augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation.\nprior_mean::Any\nprior mean - defaults to initial mean\nprior_cov::Any\nprior covariance - defaults to initial covariance\niter::Int64\ncurrent iteration number\n\nConstructors\n\nUnscented(\n u0_mean::AbstractVector{FT},\n uu0_cov::AbstractMatrix{FT};\n α_reg::FT = 1.0,\n update_freq::IT = 0,\n modified_unscented_transform::Bool = true,\n impose_prior::Bool = false,\n prior_mean::Any,\n prior_cov::Any,\n sigma_points::String = symmetric\n) where {FT <: AbstractFloat, IT <: Int}\n\nConstruct an Unscented Inversion Process.\n\nInputs:\n\nu0_mean: Mean at initialization.\nuu0_cov: Covariance at initialization.\nα_reg: Hyperparameter controlling regularization toward the prior mean (0 < α_reg ≤ 1),\n\ndefault should be 1, without regulariazion.\n\nupdate_freq: Set to 0 when the inverse problem is not identifiable, \n\nnamely the inverse problem has multiple solutions, the covariance matrix will represent only the sensitivity of the parameters, instead of posterior covariance information; set to 1 (or anything > 0) when the inverse problem is identifiable, and the covariance matrix will converge to a good approximation of the posterior covariance with an uninformative prior.\n\nmodified_unscented_transform: Modification of the UKI quadrature given in Huang et al (2021).\nimpose_prior: using augmented system (Tikhonov regularization with Kalman inversion in Chada et al 2020 and Huang et al (2022)) to regularize the inverse problem, which also imposes prior for posterior estimation. If impose_prior == true, prior mean and prior cov must be provided. This is recommended to use, especially when the number of observations is smaller than the number of parameters (ill-posed inverse problems). When this is used, other regularizations are turned off automatically.\nprior_mean: Prior mean used for regularization.\nprior_cov: Prior cov used for regularization.\nsigma_points: String of sigma point type, it can be symmetric with 2N_par+1 ensemble members or simplex with N_par+2 ensemble members.\n\nUnscented(u_mean, uu_cov, obs_pred, c_weights, mean_weights, cov_weights, N_ens, Σ_ω, Σ_ν_scale, α_reg, r, update_freq, impose_prior, prior_mean, prior_cov, iter)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:57.\n\nUnscented(u0_mean, uu0_cov)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:91.\n\nUnscented(prior)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:212.\n\n\n\n\n\n","category":"type"},{"location":"API/Unscented/#EnsembleKalmanProcesses.construct_sigma_ensemble","page":"Unscented","title":"EnsembleKalmanProcesses.construct_sigma_ensemble","text":"construct_sigma_ensemble(\n process::Unscented,\n x_mean::Array{FT},\n x_cov::AbstractMatrix{FT},\n) where {FT <: AbstractFloat, IT <: Int}\n\nConstruct the sigma ensemble based on the mean x_mean and covariance x_cov.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.construct_mean","page":"Unscented","title":"EnsembleKalmanProcesses.construct_mean","text":"construct_mean(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n x::AbstractVecOrMat{FT};\n mean_weights = uki.process.mean_weights,\n) where {FT <: AbstractFloat, IT <: Int}\n\nconstructs mean x_mean from an ensemble x.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.construct_cov","page":"Unscented","title":"EnsembleKalmanProcesses.construct_cov","text":"construct_cov(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n x::AbstractVecOrMat{FT},\n x_mean::Union{FT, AbstractVector{FT}, Nothing} = nothing;\n cov_weights = uki.process.cov_weights,\n) where {FT <: AbstractFloat, IT <: Int}\n\nConstructs covariance xx_cov from ensemble x and mean x_mean.\n\n\n\n\n\nconstruct_cov(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n x::AbstractMatrix{FT},\n x_mean::AbstractVector{FT},\n obs_mean::AbstractMatrix{FT},\n y_mean::AbstractVector{FT};\n cov_weights = uki.process.cov_weights,\n) where {FT <: AbstractFloat, IT <: Int, P <: Process}\n\nConstructs covariance xy_cov from ensemble x and mean x_mean, ensemble obs_mean and mean y_mean.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.update_ensemble_prediction!","page":"Unscented","title":"EnsembleKalmanProcesses.update_ensemble_prediction!","text":"update_ensemble_prediction!(process::Unscented, Δt::FT) where {FT <: AbstractFloat}\n\nUKI prediction step : generate sigma points.\n\n\n\n\n\n","category":"function"},{"location":"API/Unscented/#EnsembleKalmanProcesses.update_ensemble_analysis!","page":"Unscented","title":"EnsembleKalmanProcesses.update_ensemble_analysis!","text":"update_ensemble_analysis!(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n u_p::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n) where {FT <: AbstractFloat, IT <: Int}\n\nUKI analysis step : g is the predicted observations Ny x N_ens matrix\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcess","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"","category":"section"},{"location":"API/EnsembleKalmanProcess/","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/EnsembleKalmanProcess/","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"EnsembleKalmanProcess\nFailureHandler\nSampleSuccGauss\nIgnoreFailures\nget_u\nget_g\nget_ϕ\nget_u_final\nget_g_final\nget_ϕ_final\nget_u_mean\nget_u_cov\nget_g_mean\nget_ϕ_mean\nget_u_mean_final\nget_u_cov_final\nget_g_mean_final\nget_ϕ_mean_final\ncompute_error!\nget_error\nget_N_iterations\nconstruct_initial_ensemble\nupdate_ensemble!\nsample_empirical_gaussian\nsplit_indices_by_success","category":"page"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.EnsembleKalmanProcess","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.EnsembleKalmanProcess","text":"EnsembleKalmanProcess{FT <: AbstractFloat, IT <: Int, P <: Process}\n\nStructure that is used in Ensemble Kalman processes.\n\nFields\n\nu::Array{EnsembleKalmanProcesses.DataContainers.DataContainer{FT}} where FT<:AbstractFloat\narray of stores for parameters (u), each of size [N_par × N_ens]\nobs_mean::Vector{FT} where FT<:AbstractFloat\nvector of the observed vector size [N_obs]\nobs_noise_cov::Union{LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}} where FT<:AbstractFloat\ncovariance matrix of the observational noise, of size [N_obs × N_obs]\nN_ens::Int64\nensemble size\ng::Array{EnsembleKalmanProcesses.DataContainers.DataContainer{FT}} where FT<:AbstractFloat\nArray of stores for forward model outputs, each of size [N_obs × N_ens]\nerr::Vector{FT} where FT<:AbstractFloat\nvector of errors\nscheduler::EnsembleKalmanProcesses.LearningRateScheduler\nScheduler to calculate the timestep size in each EK iteration\naccelerator::EnsembleKalmanProcesses.Accelerator\naccelerator object that informs EK update steps, stores additional state variables as needed\nΔt::Vector{FT} where FT<:AbstractFloat\nstored vector of timesteps used in each EK iteration\nprocess::EnsembleKalmanProcesses.Process\nthe particular EK process (Inversion or Sampler or Unscented or TransformInversion or SparseInversion)\nrng::Random.AbstractRNG\nRandom number generator object (algorithm + seed) used for sampling and noise, for reproducibility. Defaults to Random.GLOBAL_RNG.\nfailure_handler::FailureHandler\nstruct storing failsafe update directives, implemented for (Inversion, SparseInversion, Unscented, TransformInversion)\nlocalizer::EnsembleKalmanProcesses.Localizers.Localizer\nLocalization kernel, implemented for (Inversion, SparseInversion, Unscented)\nverbose::Bool\nWhether to print diagnostics for each EK iteration\n\nGeneric constructor\n\nEnsembleKalmanProcess(\n params::AbstractMatrix{FT},\n obs_mean,\n obs_noise_cov::Union{AbstractMatrix{FT}, UniformScaling{FT}},\n process::P;\n scheduler = DefaultScheduler(1),\n Δt = FT(1),\n rng::AbstractRNG = Random.GLOBAL_RNG,\n failure_handler_method::FM = IgnoreFailures(),\n localization_method::LM = NoLocalization(),\n verbose::Bool = false,\n) where {FT <: AbstractFloat, P <: Process, FM <: FailureHandlingMethod, LM <: LocalizationMethod}\n\nInputs:\n\nparams :: Initial parameter ensemble\nobs_mean :: Vector of observations\nobs_noise_cov :: Noise covariance associated with the observations obs_mean\nprocess :: Algorithm used to evolve the ensemble\nscheduler :: Adaptive timestep calculator \nΔt :: Initial time step or learning rate\nrng :: Random number generator\nfailure_handler_method :: Method used to handle particle failures\nlocalization_method :: Method used to localize sample covariances\nverbose :: Whether to print diagnostic information\n\nOther constructors:\n\nEnsembleKalmanProcess(u, obs_mean, obs_noise_cov, N_ens, g, err, scheduler, accelerator, Δt, process, rng, failure_handler, localizer, verbose)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:117.\n\nEnsembleKalmanProcess(params, obs_mean, obs_noise_cov, process)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanProcess.jl:147.\n\nEnsembleKalmanProcess(obs_mean, obs_noise_cov, process)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:223.\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.FailureHandler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.FailureHandler","text":"FailureHandler{P <: Process, FM <: FailureHandlingMethod}\n\nStructure defining the failure handler method used in the EnsembleKalmanProcess.\n\nFields\n\nfailsafe_update::Function\nFailsafe algorithmic update equation\n\nConstructors\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:10.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanInversion.jl:22.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleKalmanSampler.jl:31.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:17.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/EnsembleTransformKalmanInversion.jl:29.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:40.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:52.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:236.\n\nFailureHandler(process, method)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/UnscentedKalmanInversion.jl:255.\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.SampleSuccGauss","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.SampleSuccGauss","text":"\" SampleSuccGauss <: FailureHandlingMethod\n\nFailure handling method that substitutes failed ensemble members by new samples from the empirical Gaussian distribution defined by the updated successful ensemble.\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.IgnoreFailures","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.IgnoreFailures","text":"Failure handling method that ignores forward model failures\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u","text":"get_u(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}\n\nReturns the unconstrained parameters at the given iteration. Returns a DataContainer object unless return_array is true.\n\n\n\n\n\nget_u(ekp::EnsembleKalmanProcess; return_array=true)\n\nReturns the unconstrained parameters from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g","text":"get_g(ekp::EnsembleKalmanProcess, iteration::IT; return_array=true) where {IT <: Integer}\n\nReturns the forward model evaluations at the given iteration. Returns a DataContainer object unless return_array is true.\n\n\n\n\n\nget_g(ekp::EnsembleKalmanProcess; return_array=true)\n\nReturns the forward model evaluations from all iterations. The outer dimension is given by the number of iterations, and the inner objects are DataContainer objects unless return_array is true.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ","text":"get_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)\n\nReturns the constrained parameters at the given iteration.\n\n\n\n\n\nget_ϕ(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)\n\nReturns the constrained parameters from all iterations. The outer dimension is given by the number of iterations.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_final","text":"get_u_final(ekp::EnsembleKalmanProcess, return_array=true)\n\nGet the unconstrained parameters at the last iteration, returning a DataContainer Object if return_array is false.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g_final","text":"get_g_final(ekp::EnsembleKalmanProcess, return_array=true)\n\nGet forward model outputs at the last iteration, returns a DataContainer Object if return_array is false.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ_final","text":"get_ϕ_final(ekp::EnsembleKalmanProcess)\n\nGet the constrained parameters at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_mean","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_mean","text":"get_u_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}\n\nReturns the mean unconstrained parameter at the given iteration.\n\n\n\n\n\nget_u_mean(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)\n\nReturns the mean unconstrained parameter at the requested iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_cov","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_cov","text":"get_u_cov(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}\n\nReturns the unconstrained parameter sample covariance at the given iteration.\n\n\n\n\n\nget_u_cov(uki::EnsembleKalmanProcess{FT, IT, Unscented}, iteration::IT)\n\nReturns the unconstrained parameter covariance at the requested iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g_mean","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g_mean","text":"get_g_mean(ekp::EnsembleKalmanProcess, iteration::IT) where {IT <: Integer}\n\nReturns the mean forward map evaluation at the given iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ_mean","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ_mean","text":"get_ϕ_mean(prior::ParameterDistribution, ekp::EnsembleKalmanProcess, iteration::IT)\n\nReturns the constrained transform of the mean unconstrained parameter at the given iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_mean_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_mean_final","text":"get_u_mean_final(ekp::EnsembleKalmanProcess)\n\nGet the mean unconstrained parameter at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_u_cov_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_u_cov_final","text":"get_u_cov_final(ekp::EnsembleKalmanProcess)\n\nGet the mean unconstrained parameter covariance at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_g_mean_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_g_mean_final","text":"get_g_mean_final(ekp::EnsembleKalmanProcess)\n\nGet the mean forward model evaluation at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_ϕ_mean_final","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_ϕ_mean_final","text":"get_ϕ_mean_final(prior::ParameterDistribution, ekp::EnsembleKalmanProcess)\n\nGet the constrained transform of the mean unconstrained parameter at the last iteration.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.compute_error!","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.compute_error!","text":"compute_error!(ekp::EnsembleKalmanProcess)\n\nComputes the covariance-weighted error of the mean forward model output, (ḡ - y)'Γ_inv(ḡ - y). The error is stored within the EnsembleKalmanProcess.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_error","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_error","text":"get_error(ekp::EnsembleKalmanProcess)\n\nReturns the mean forward model output error as a function of algorithmic time.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.get_N_iterations","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.get_N_iterations","text":"get_N_iterations(ekp::EnsembleKalmanProcess)\n\nGet number of times update has been called (equals size(g), or size(u)-1).\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.construct_initial_ensemble","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.construct_initial_ensemble","text":"construct_initial_ensemble(\n rng::AbstractRNG,\n prior::ParameterDistribution,\n N_ens::IT\n) where {IT <: Int}\nconstruct_initial_ensemble(prior::ParameterDistribution, N_ens::IT) where {IT <: Int}\n\nConstruct the initial parameters, by sampling N_ens samples from specified prior distribution. Returned with parameters as columns.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.update_ensemble!","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.update_ensemble!","text":"update_ensemble!(\n ekp::EnsembleKalmanProcess,\n g::AbstractMatrix{FT};\n multiplicative_inflation::Bool = false,\n additive_inflation::Bool = false,\n use_prior_cov::Bool = false,\n s::FT = 0.0,\n ekp_kwargs...,\n) where {FT, IT}\n\nUpdates the ensemble according to an Inversion process. Inputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nmultiplicative_inflation :: Flag indicating whether to use multiplicative inflation.\nadditive_inflation :: Flag indicating whether to use additive inflation.\nusepriorcov :: Bool specifying whether to use prior covariance estimate for additive inflation. If false (default), parameter covariance from the current iteration is used.\ns :: Scaling factor for time step in inflation step.\nekpkwargs :: Keyword arguments to pass to standard ekp updateensemble!.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, Inversion},\n g::AbstractMatrix{FT},\n process::Inversion;\n deterministic_forward_map::Bool = true,\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to an Inversion process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\ndeterministicforwardmap :: Whether output g comes from a deterministic model.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, TransformInversion},\n g::AbstractMatrix{FT},\n process::TransformInversion;\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to a TransformInversion process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},\n g::AbstractMatrix{FT},\n process::SparseInversion{FT};\n deterministic_forward_map = true,\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to a SparseInversion process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\ndeterministic_forward_map :: Whether output g comes from a deterministic model.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n ekp::EnsembleKalmanProcess{FT, IT, Sampler{FT}},\n g::AbstractMatrix{FT},\n process::Sampler{FT};\n failed_ens = nothing,\n) where {FT, IT}\n\nUpdates the ensemble according to a Sampler process. \n\nInputs:\n\nekp :: The EnsembleKalmanProcess to update.\ng :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\nupdate_ensemble!(\n uki::EnsembleKalmanProcess{FT, IT, Unscented},\n g_in::AbstractMatrix{FT},\n process::Unscented;\n failed_ens = nothing,\n) where {FT <: AbstractFloat, IT <: Int}\n\nUpdates the ensemble according to an Unscented process. \n\nInputs:\n\nuki :: The EnsembleKalmanProcess to update.\ng_in :: Model outputs, they need to be stored as a N_obs × N_ens array (i.e data are columms).\nprocess :: Type of the EKP.\nfailed_ens :: Indices of failed particles. If nothing, failures are computed as columns of g with NaN entries.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.sample_empirical_gaussian","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.sample_empirical_gaussian","text":"sample_empirical_gaussian(\n u::AbstractMatrix{FT},\n n::IT;\n inflation::Union{FT, Nothing} = nothing,\n) where {FT <: Real, IT <: Int}\n\nReturns n samples from an empirical Gaussian based on point estimates u, adding inflation if the covariance is singular.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.split_indices_by_success","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.split_indices_by_success","text":" split_indices_by_success(g::AbstractMatrix{FT}) where {FT <: Real}\n\nReturns the successful/failed particle indices given a matrix with output vectors stored as columns. Failures are defined for particles containing at least one NaN output element.\n\n\n\n\n\n","category":"function"},{"location":"API/EnsembleKalmanProcess/#scheduler_api","page":"EnsembleKalmanProcess","title":"Learning Rate Schedulers","text":"","category":"section"},{"location":"API/EnsembleKalmanProcess/","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcess","text":"DefaultScheduler\nMutableScheduler\nEKSStableScheduler\nDataMisfitController\ncalculate_timestep!","category":"page"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.DefaultScheduler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.DefaultScheduler","text":"struct DefaultScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler containing a default constant step size, users can override this temporarily within update_ensemble!.\n\nΔt_default::Any\nstep size\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.MutableScheduler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.MutableScheduler","text":"struct MutableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler containing a mutable constant step size, users can override this permanently within update_ensemble!.\n\nΔt_mutable::Vector\nmutable step size\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.EKSStableScheduler","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.EKSStableScheduler","text":"struct EKSStableScheduler{FT} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler known to be stable for EKS, In particular, Delta t = fracalphaU + varepsilon where U = (G(u) - barG(u))^TGamma^-1(G(u) - y). Cannot be overriden.\n\nnumerator::Any\nthe numerator alpha\nnugget::Any\nthe nugget term varepsilon\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.DataMisfitController","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.DataMisfitController","text":"struct DataMisfitController{FT, M, S} <: EnsembleKalmanProcesses.LearningRateScheduler\n\nScheduler from Iglesias, Yang, 2021, Based on Bayesian Tempering. Terminates at T=1 by default, and at this time, ensemble spread provides a (more) meaningful approximation of posterior uncertainty In particular, for parameters theta_j at step n, to calculate the next timestep Delta t_n = minleft(maxleft(fracJ2Phi sqrtfracJ2langle Phi Phi rangleright) 1-sum^n-1_i t_iright) where Phi_j = Gamma^-frac12(G(theta_j) - y)^2. Cannot be overriden by user provided timesteps. By default termination returns true from update_ensemble! and \n\nif on_terminate == \"stop\", stops further iteration.\nif on_terminate == \"continue_fixed\", continues iteration with the final timestep fixed\nif on_terminate == \"continue\", continues the algorithm (though no longer compares to 1-sum^n-1_i t_i) \n\nThe user may also change the T with terminate_at keyword.\n\niteration::Vector{Int64}\nthe current iteration\ninv_sqrt_noise::Vector\nthe inverse square-root of the noise covariance is stored\nterminate_at::Any\nthe algorithm time for termination, default: 1.0\non_terminate::Any\nthe action on termination, default: \"stop\",\n\n\n\n\n\n","category":"type"},{"location":"API/EnsembleKalmanProcess/#EnsembleKalmanProcesses.calculate_timestep!","page":"EnsembleKalmanProcess","title":"EnsembleKalmanProcesses.calculate_timestep!","text":"calculate_timestep!(ekp::EnsembleKalmanProcess, g::AbstractMatrix, Δt_new::Union{Nothing, AbstractFloat}) -> Any\n\n\nCalculates next timestep by pushing to ekp.Δt, !isnothing(return_value) implies termination condition has been met\n\n\n\n\n\n","category":"function"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"EditURL = \"../../../examples/AerosolActivation/aerosol_activation.jl\"","category":"page"},{"location":"literated/aerosol_activation/#Aerosol-Activation-Example","page":"Aerosol activation","title":"Aerosol Activation Example","text":"","category":"section"},{"location":"literated/aerosol_activation/#Overview","page":"Aerosol activation","title":"Overview","text":"","category":"section"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"This example is based on AerosolActivation module which is a part of the CloudMicrophysics.jl package. The AerosolActivation module computes the total number and mass of aerosol particles that get activated and become cloud droplets, given the atmospheric conditions and the initial aerosol size distribution and properties. See the AerosolActivation module docs for derivation and description of all input parameters.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"In this example we use the ensemble Kalman methods to learn two parameters that describe the chemical composition of aerosol particles based on the observed total number and mass of activated particles. The AerosolActivation model is used here in a \"perfect model\" setting, meaning that the observations are generated by the same module we are calibrating.","category":"page"},{"location":"literated/aerosol_activation/#Prerequisites","page":"Aerosol activation","title":"Prerequisites","text":"","category":"section"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"The example depends on some standard Julia libraries, as well as the CliMA packages: EnsembleKalmanProcess.jl, CLIMAParameters.jl and CloudMicrophysics.jl. To ensure that all the dependencies are met start Julia using the Project.toml file provided in the example and run the Julia package manager to download all the dependecies.","category":"page"},{"location":"literated/aerosol_activation/#Example","page":"Aerosol activation","title":"Example","text":"","category":"section"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We begin by importing some standard Julia modules, the Ensemble Kalman Process modules, CLIMA Parameter modules and Aerosol Activation modules.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"using Plots\nusing Distributions\nusing LinearAlgebra\nusing Random\n\nrng_seed = 44\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses\n\nimport CLIMAParameters\nconst CP = CLIMAParameters\nstruct EarthParameterSet <: CP.AbstractEarthParameterSet end\nconst param_set = EarthParameterSet()\n\nimport CloudMicrophysics\nconst AM = CloudMicrophysics.AerosolModel\nconst AA = CloudMicrophysics.AerosolActivation\n\nimport Thermodynamics\nconst TD = Thermodynamics\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Next, we provide the information about the priors of the parameters we want to learn. We are calibrating two parameters decribing the aerosol properties - namely the aerosol molar mass and the osmotic coefficient.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"parameter_names = [\"molar_mass\", \"osmotic_coeff\"]\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"In this test we do know the parameter values. We use them to test the convergence of EKP for aerosol activation.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"molar_mass_true = 0.058443\nosmotic_coeff_true = 0.9\ndefault_params = [molar_mass_true, osmotic_coeff_true]\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We must define parameter priors. Both parameters have to be positive definite, therefore we define the constraints to be bounded below by zero. We don't have much other prior knowledge about the parameters. We simply constrain their scale to be loosely of size 1. For more details see constrained_gaussian","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"prior1 = constrained_gaussian(parameter_names[1], 1, 1, 0, Inf)\nprior2 = constrained_gaussian(parameter_names[2], 1, 1, 0, Inf)\npriors = combine_distributions([prior1, prior2])\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Next we define the atmospheric conditions for which the calibration will take place, (air temperature in K, air pressure in Pa vertical velocity in m/s and vapor specific humidity assuming its saturated in kg/kg) This can be changed later to include more than one (T p w) combination in the calibration process","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"T = 283.15\np = 1e5\nw = 5.0\np_vs = TD.saturation_vapor_pressure(param_set, T, TD.Liquid())\nq_vs = 1 / (1 - CP.Planet.molmass_ratio(param_set) * (p_vs - p) / p_vs)\nq = TD.PhasePartition(q_vs, 0.0, 0.0)\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We also define the aerosol size distribution (lognormal, 1 mode) with (mean radius in m, geometric stdev, number concentration 1/m³). These can also be changed later to include different initial size distributions.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"r_dry = 0.243e-6\nstdev = 1.4\nN = 100.0 * 1e6 # since 1/cm³ = 1e6 1/m³\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Finally, we define additional parameters that describe the aerosol properties. The chosen aerosol is sea salt.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"dissoc_seasalt = 2.0\nsoluble_mass_frac_seasalt = 1.0\nrho_seasalt = 2170.0;\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We define a wrapper function that runs the aerosol activation module with two input parameters that will be calibrated by EKP. The output observations are the number and mass of activated aerosol.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"function run_activation_model(molar_mass_calibrated, osmotic_coeff_calibrated)\n\n accum_mode_seasalt = AM.Mode_B(\n r_dry,\n stdev,\n N,\n (1.0,),\n (soluble_mass_frac_seasalt,),\n (osmotic_coeff_calibrated,),\n (molar_mass_calibrated,),\n (dissoc_seasalt,),\n (rho_seasalt,),\n 1,\n )\n\n aerosol_distr = AM.AerosolDistribution((accum_mode_seasalt,))\n N_act = AA.total_N_activated(param_set, aerosol_distr, T, p, w, q)\n M_act = AA.total_M_activated(param_set, aerosol_distr, T, p, w, q)\n return [N_act, M_act]\nend\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"This example is run in a \"perfect model setting\", meaning the model that we calibrate is also used to generate observations. We use the total number and mass of activated aerosol particles as our observational data.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"observation_data_names = [\"N_act\", \"M_act\"];\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We generate artificial truth samples based on the default values of parameters we are calibrating.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"n_samples = 10\nG_t = run_activation_model(molar_mass_true, osmotic_coeff_true)\ny_t = zeros(length(G_t), n_samples)\n\nΓy = convert(Array, LinearAlgebra.Diagonal([0.01 * G_t[1], 0.01 * G_t[2]]))\nμ = zeros(length(G_t));\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"And add noise to the generated truth sample.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"for i in 1:n_samples\n y_t[:, i] = G_t .+ rand(Distributions.MvNormal(μ, Γy))\nend\n\ntruth_array = EKP.Observations.Observation(y_t, Γy, observation_data_names)\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"One could try for the truth to be a mean of the generated array. Or do the calibration for all individual truth samples and then compute the mean of calibrated parameters. For now we are just taking one truth array member.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"truth_sample = truth_array.samples[1];\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We use 50 ensemble members and do 10 iterations.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"N_ens = 50\nN_iter = 10\n\ninitial_par = EKP.construct_initial_ensemble(rng, priors, N_ens)\nekiobj = EKP.EnsembleKalmanProcess(initial_par, truth_sample, truth_array.obs_noise_cov, EKP.Inversion())\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Finally, we can run the Ensemble Kalman Process calibration.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"ϕ_n_values = []\nfor n in 1:N_iter\n ϕ_n = EKP.get_ϕ_final(priors, ekiobj)\n G_n = [run_activation_model(ϕ_n[:, i]...) for i in 1:N_ens]\n G_ens = hcat(G_n...)\n EKP.update_ensemble!(ekiobj, G_ens)\n\n global ϕ_n_values = vcat(ϕ_n_values, [ϕ_n])\nend\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We define some simple functions for plotting the data.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"function plot_ensemble_scatter(id)\n\n ensemble_member = 1:N_ens\n\n if id == 1\n ylabel = \"Molar mass [kg/mol]\"\n filename = \"molar_mass_scatter.pdf\"\n elseif id == 2\n ylabel = \"Osmotic coefficient [-]\"\n filename = \"osmotic_coeff_scatter.pdf\"\n end\n\n plot(\n ensemble_member,\n ϕ_n_values[1][id, 1:N_ens],\n seriestype = :scatter,\n xlabel = \"Ensemble Number\",\n ylabel = ylabel,\n legend = false,\n )\n\n for it in 2:N_iter\n plot!(ensemble_member .+ ((it - 1) * 50), ϕ_n_values[it][id, 1:N_ens], seriestype = :scatter, legend = false)\n end\n\n current()\n savefig(filename)\nend\n\nfunction plot_ensemble_means(id)\n\n number_of_iters = 1:N_iter\n means = zeros(N_iter)\n\n for it in 1:N_iter\n means[it] = mean(ϕ_n_values[it][id, 1:N_ens])\n end\n\n if id == 1\n ylabel = \"Molar mass [kg/mol]\"\n filename = \"molar_mass_average.pdf\"\n end\n if id == 2\n ylabel = \"Osmotic coefficient [-]\"\n filename = \"osmotic_coeff_average.pdf\"\n end\n\n plot(\n number_of_iters,\n means,\n markershape = :star5,\n xticks = number_of_iters,\n xlabel = \"Iteration Number\",\n ylabel = ylabel,\n label = \"Ensemble Mean\",\n )\n hline!([default_params[id]], label = \"true value\")\n\n savefig(filename)\nend\nnothing # hide","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"We plot the ensemble members and the ensemble mean for the molar mass and osmotic coefficient.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"plot_ensemble_scatter(1)\nplot_ensemble_means(1)\nplot_ensemble_scatter(2)\nplot_ensemble_means(2)","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"(Image: ) (Image: ) (Image: ) (Image: )","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"Finally, we test that the parameter values obtained via EnsembleKalmanProcesses.jl are close to the known true parameter values.","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"molar_mass_ekp = round(mean(ϕ_n_values[N_iter][1, 1:N_ens]), digits = 6)\nosmotic_coeff_ekp = round(mean(ϕ_n_values[N_iter][2, 1:N_ens]), digits = 6)\n\nprintln(\"Molar mass [kg/mol]: \", molar_mass_ekp, \" vs \", molar_mass_true)\nprintln(\"Osmotic coefficient [-]: \", osmotic_coeff_ekp, \" vs \", osmotic_coeff_true)","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"","category":"page"},{"location":"literated/aerosol_activation/","page":"Aerosol activation","title":"Aerosol activation","text":"This page was generated using Literate.jl.","category":"page"},{"location":"contributing/#Contributing","page":"Contributing","title":"Contributing","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Thank you for considering contributing to EnsembleKalmanProcesses! We encourage opening issues and pull requests (PRs).","category":"page"},{"location":"contributing/#What-to-contribute?","page":"Contributing","title":"What to contribute?","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"The easiest way to contribute is by using EnsembleKalmanProcesses, identifying problems and opening issues;\nYou can try to tackle an existing issue. It is best to outline your proposed solution in the issue thread before implementing it in a PR;\nWrite an example or tutorial. It is likely that other users may find your use of EnsembleKalmanProcesses insightful;\nImprove documentation or comments if you found something hard to use;\nImplement a new feature if you need it. We strongly encourage opening an issue to make sure the administrators are on board before opening a PR with an unsolicited feature addition.","category":"page"},{"location":"contributing/#Using-git","page":"Contributing","title":"Using git","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"If you are unfamiliar with git and version control, the following guides will be helpful:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Atlassian (bitbucket) git tutorials. A set of tips and tricks for getting started with git.\nGitHub's git tutorials. A set of resources from GitHub to learn git.","category":"page"},{"location":"contributing/#Forks-and-branches","page":"Contributing","title":"Forks and branches","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Create your own fork of EnsembleKalmanProcesses on GitHub and check out your copy:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git clone https://github.com//EnsembleKalmanProcesses.jl.git\n$ cd EnsembleKalmanProcesses.jl","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Now you have access to your fork of EnsembleKalmanProcesses through origin. Create a branch for your feature; this will hold your contribution:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git checkout -b ","category":"page"},{"location":"contributing/#Some-useful-tips","page":"Contributing","title":"Some useful tips","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"When you start working on a new feature branch, make sure you start from main by running: git checkout main and git pull.\nCreate a new branch from main by using git checkout -b .","category":"page"},{"location":"contributing/#Develop-your-feature","page":"Contributing","title":"Develop your feature","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Make sure you add tests for your code in test/ and appropriate documentation in the code and/or in docs/. Before committing your changes, you can verify their behavior by running the tests, the examples, and building the documentation locally. In addition, make sure your feature follows the formatting guidelines by running","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"julia --project=.dev .dev/climaformat.jl .","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"from the EnsembleKalmanProcesses.jl directory.","category":"page"},{"location":"contributing/#Squash-and-rebase","page":"Contributing","title":"Squash and rebase","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"When your PR is ready for review, clean up your commit history by squashing and make sure your code is current with EnsembleKalmanProcesses.jl main by rebasing. The general rule is that a PR should contain a single commit with a descriptive message.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"To make sure you are up to date with main, you can use the following workflow:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git checkout main\n$ git pull\n$ git checkout \n$ git rebase main","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"This may create conflicts with the local branch. The conflicted files will be outlined by git. To resolve conflicts, we have to manually edit the files (e.g. with vim). The conflicts will appear between >>>>, ===== and <<<<<. We need to delete these lines and pick what version we want to keep.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"To squash your commits, you can use the following command:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git rebase -i HEAD~n","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"where n is the number of commits you need to squash into one. Then, follow the instructions in the terminal. For example, to squash 4 commits:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git rebase -i HEAD~4","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"will open the following file in (typically) vim:","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":" pick 01d1124 \n pick 6340aaa \n pick ebfd367 \n pick 30e0ccb \n\n # Rebase 60709da..30e0ccb onto 60709da\n #\n # Commands:\n # p, pick = use commit\n # e, edit = use commit, but stop for amending\n # s, squash = use commit, but meld into previous commit\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\n##","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We want to keep the first commit and squash the last 3. We do so by changing the last three commits to squash and then do :wq on vim.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":" pick 01d1124 \n squash 6340aaa \n squash ebfd367 \n squash 30e0ccb \n\n # Rebase 60709da..30e0ccb onto 60709da\n #\n # Commands:\n # p, pick = use commit\n # e, edit = use commit, but stop for amending\n # s, squash = use commit, but meld into previous commit\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Then in the next screen that appears, we can just delete all messages that we do not want to show in the commit. After this is done and we are back to the console, we have to force push. We need to force push because we rewrote the local commit history.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"$ git push -uf origin ","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"You can find more information about squashing here.","category":"page"},{"location":"contributing/#Unit-testing","page":"Contributing","title":"Unit testing","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Currently a number of checks are run per commit for a given PR.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"JuliaFormatter checks if the PR is formatted with .dev/climaformat.jl.\nDocumentation rebuilds the documentation for the PR and checks if the docs are consistent and generate valid output.\nUnit Tests run subsets of the unit tests defined in tests/, using Pkg.test(). The tests are run in parallel to ensure that they finish in a reasonable time. The tests only run the latest commit for a PR, branch and will kill any stale jobs on push. These tests are only run on linux (Ubuntu LTS).","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Unit tests are run against every new commit for a given PR, the status of the unit-tests are not checked during the merge process but act as a sanity check for developers and reviewers. Depending on the content changed in the PR, some CI checks that are not necessary will be skipped. For example doc only changes do not require the unit tests to be run.","category":"page"},{"location":"contributing/#The-merge-process","page":"Contributing","title":"The merge process","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We use bors to manage merging PR's in the the EnsembleKalmanProcesses repo. If you're a collaborator and have the necessary permissions, you can type bors try in a comment on a PR to have integration test suite run on that PR, or bors r+ to try and merge the code. Bors ensures that all integration tests for a given PR always pass before merging into main. The integration tests currently run example cases in examples/. Any breaking changes will need to also update the examples/, else bors will fail.","category":"page"},{"location":"observations/#Observations","page":"Observations","title":"Observations","text":"","category":"section"},{"location":"observations/","page":"Observations","title":"Observations","text":"The Observations object is used to store the truth for convenience of the user. The ingredients are","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"Samples of the data Vector{Vector{Float}} or Array{Float, 2}. If provided as a 2D array, the samples must be provided as columns. They are stored internally as Vector{Vector{Float}}\nAn optional covariance matrix can be provided.\nThe names of the data in this object as a String or Vector{String}","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"The empirical mean is calculated automatically. If a covariance matrix is not provided, then the empirical covariance is also calculated automatically.","category":"page"},{"location":"observations/#A-simple-example:","page":"Observations","title":"A simple example:","text":"","category":"section"},{"location":"observations/","page":"Observations","title":"Observations","text":"Here is a typical construction of the object:","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"μ = zeros(5)\nΓy = rand(5, 5)\nΓy = Γy' * Γy\nyt = rand(MvNormal(μ, Γy), 100) # generate 100 samples\nname = \"zero-mean mvnormal\"\n\ntrue_data = Observations.Observation(yt, Γy, name)","category":"page"},{"location":"observations/","page":"Observations","title":"Observations","text":"Currently, the data is retrieved by accessing the stored variables, e.g the fifth data sample is given by truth_data.samples[5], or the covariance matrix by truth_data.cov.","category":"page"},{"location":"ensemble_kalman_sampler/#Ensemble-Kalman-Sampling","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampling","text":"","category":"section"},{"location":"ensemble_kalman_sampler/#What-Is-It-and-What-Does-It-Do?","page":"Ensemble Kalman Sampler","title":"What Is It and What Does It Do?","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The Ensemble Kalman Sampler (EKS) (Garbuno-Inigo et al, 2020, Cleary et al, 2020, Garbuno-Inigo et al, 2020) is a derivative-free tool for approximate Bayesian inference. It does so by approximately sampling from the posterior distribution. That is, EKS provides both point estimation (through the mean of the final ensemble) and uncertainty quantification (through the covariance of the final ensemble), this is in contrast to EKI, which only provides point estimation.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The EKS is an interacting particle system in stochastic differential equation form, and it is based on a dynamic which transforms an arbitrary initial probability distribution into an approximation of the desired posterior distribution over an infinite time horizon – see Garbuno-Inigo et al, 2020, for a comprehensive description of the method. While there are noisy variants of the standard EKI, EKS differs from them in its noise structure (as its noise is added in parameter space, not in data space), and its update rule explicitly accounts for the prior (rather than having it enter through initialization). The EKS algorithm can be understood as well as an affine invariant system of interacting particles (Garbuno-Inigo et al, 2020) for which a finite-sample correction is introduced to overcome its computational finite-sample implementation. This finite-sample corrected version of EKS is also known as the affine invariant Langevin dynamics (ALDI).","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"Perhaps as expected, the approximate posterior characterization through EKS needs more iterations, and thus more forward model evaluations, than EKI to converge to a suitable solution. This is because of the discrete-time implementation of the EKS diffusion process and the need to maintain a stable interacting particle system. However, the posterior approximation through EKS is obtained with far less computational effort than a typical Markov Chain Monte Carlo (MCMC) like Metropolis-Hastings.","category":"page"},{"location":"ensemble_kalman_sampler/#Problem-Formulation","page":"Ensemble Kalman Sampler","title":"Problem Formulation","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The data y and parameter vector theta are assumed to be related according to:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":" y = mathcalG(theta) + eta ","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where mathcalG mathbbR^p rightarrow mathbbR^d denotes the forward map, y in mathbbR^d is the vector of observations, and eta is the observational noise, which is assumed to be drawn from a d-dimensional Gaussian with distribution mathcalN(0 Gamma_y). The objective of the inverse problem is to compute the unknown parameters theta given the observations y, the known forward map mathcalG, and noise characteristics eta of the process.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"note: Note\nTo obtain Bayesian characterization for the posterior from EKS, the user must specify a Gaussian prior distribution. See Prior distributions to see how one can apply flexible constraints while maintaining Gaussian priors. ","category":"page"},{"location":"ensemble_kalman_sampler/#Ensemble-Kalman-Sampling-Algorithm","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampling Algorithm","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The EKS is based on the following update equation for the parameter vector theta^(j)_n of ensemble member j at the n-iteration:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"beginaligned\ntheta_n+1^(* j) = theta_n^(j) - dfracDelta t_nJsum_k=1^Jlangle mathcalG(theta_n^(k)) - barmathcalG_n Gamma_y^-1(mathcalG(theta_n^(j)) - y) rangle theta_n^(k) + fracd+1J left(theta_n^(j) - bar theta_n right) - Delta t_n mathsfC(Theta_n) Gamma_theta^-1 theta_n + 1^(* j) \ntheta_n + 1^j = theta_n+1^(* j) + sqrt2 Delta t_n mathsfC(Theta_n) xi_n^j \nendaligned","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where the subscript n=1 dots N_textit indicates the iteration, J is the ensemble size (i.e., the number of particles in the ensemble), Delta t_n is an internal adaptive time step (thus no need for the user to specify), Gamma_theta is the prior covariance, and xi_n^(j) sim mathcalN(0 mathrmI_p). barmathcalG_n is the ensemble mean of the forward map mathcalG(theta),","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"barmathcalG_n = dfrac1Jsum_k=1^JmathcalG(theta_n^(k))","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The p times p matrix mathsfC(Theta_n), where Theta_n = lefttheta^(j)_nright_j=1^J is the set of all ensemble particles in the n-th iteration, denotes the empirical covariance between particles","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"mathsfC(Theta_n) = frac1J sum_k=1^J (theta^(k)_n - bartheta_n) otimes (theta^(k)_n - bartheta_n)","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where bartheta_n is the ensemble mean of the particles,","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"bartheta_n = dfrac1Jsum_k=1^Jtheta^(k)_n ","category":"page"},{"location":"ensemble_kalman_sampler/#Constructing-the-Forward-Map","page":"Ensemble Kalman Sampler","title":"Constructing the Forward Map","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"At the core of the forward map mathcalG is the dynamical model PsimathbbR^p rightarrow mathbbR^o (running Psi is usually where the computational heavy-lifting is done), but the map mathcalG may include additional components such as a transformation of the (unbounded) parameters theta to a constrained domain the dynamical model can work with, or some post-processing of the output of Psi to generate the observations. For example, mathcalG may take the following form:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"mathcalG = mathcalH circ Psi circ mathcalT^-1","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"where mathcalHmathbbR^o rightarrow mathbbR^d is the observation map and mathcalT is the transformation from the constrained to the unconstrained parameter space, such that mathcalT(phi)=theta. A family of standard transformations and their inverses are available in the ParameterDistributions module.","category":"page"},{"location":"ensemble_kalman_sampler/#How-to-Construct-an-Ensemble-Kalman-Sampler","page":"Ensemble Kalman Sampler","title":"How to Construct an Ensemble Kalman Sampler","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"An EKS object can be created using the EnsembleKalmanProcess constructor by specifying the Sampler type. The constructor takes two arguments, the prior mean prior_mean and the prior covariance prior_cov.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"Creating an EKS object requires as arguments:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"An initial parameter ensemble – an array of size p × N_ens, where N_ens is the ensemble size;\nThe mean value of the observed data – a vector of length d;\nThe covariance matrix of the observational noise – an array of size d × d;\nThe Sampler(prior_mean, prior_cov) process type, with the mean (a vector of length p) and the covariance (an array of size p x p) of the parameter's prior distribution.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The following example shows how an EKS object is instantiated. An observation (y) and the covariance of the observational noise (obs_cov) are assumed to be defined previously in the code.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions # required to create the prior\n\n# Construct prior (see `ParameterDistributions.jl` docs)\nprior = ParameterDistribution(...)\nprior_mean = mean(prior)\nprior_cov = cov(prior)\n\n# Construct initial ensemble\nN_ens = 50 # ensemble size\ninitial_ensemble = construct_initial_ensemble(prior, N_ens)\n\n# Construct ensemble Kalman process\neks_process = Sampler(prior_mean, prior_cov)\neksobj = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, eks_process)","category":"page"},{"location":"ensemble_kalman_sampler/#Updating-the-ensemble","page":"Ensemble Kalman Sampler","title":"Updating the ensemble","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"Once the EKS object eksobj has been initialized, the initial ensemble of particles is iteratively updated by the update_ensemble! function, which takes as arguments the eksobj and the evaluations of the forward model at each member of the current ensemble. In the following example, the forward map G maps a parameter to the corresponding data – this is done for each parameter in the ensemble, such that the resulting g_ens is of size d x N_ens. The update_ensemble! function then stores the updated ensemble as well as the evaluations of the forward map in eksobj.","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"A typical use of the update_ensemble! function given the EKS object eksobj, the dynamical model Ψ, and the observation map H (the latter two are assumed to be defined elsewhere, e.g. in a separate module) may look as follows:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"# Given:\n# Ψ (some black box simulator)\n# H (some observation of the simulator output)\n# prior (prior distribution and parameter constraints)\n\nN_iter = 100 # Number of iterations\n\nfor n in 1:N_iter\n ϕ_n = get_ϕ_final(prior, eksobj) # Get current ensemble in constrained \"ϕ\"-space\n G_n = [H(Ψ(ϕ_n[:, i])) for i in 1:J] # Evaluate forward map\n g_ens = hcat(G_n...) # Reformat into `d x N_ens` matrix\n update_ensemble!(eksobj, g_ens) # Update ensemble\nend","category":"page"},{"location":"ensemble_kalman_sampler/#Solution","page":"Ensemble Kalman Sampler","title":"Solution","text":"","category":"section"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"The solution of the EKS algorithm is an approximate Gaussian distribution whose mean (θ_post) and covariance (Γ_post) can be extracted from the ''final ensemble'' (i.e., after the last iteration). The sample mean of the last ensemble is also the \"optimal\" parameter (θ_optim) for the given calibration problem. These statistics can be accessed as follows:","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"# mean of the Gaussian distribution, the optimal parameter in computational θ-space\nθ_post = get_u_mean_final(eksobj)\n# (empirical) covariance of the Gaussian distribution in computational θ-space\nΓ_post = get_u_cov_final(eksobj)","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"To obtain samples of this approximate posterior in the constrained space, we first sample the distribution, then transform using the constraints contained within the prior ","category":"page"},{"location":"ensemble_kalman_sampler/","page":"Ensemble Kalman Sampler","title":"Ensemble Kalman Sampler","text":"using Random, Distributions\n\nten_post_samples = rand(MvNormal(θ_post,Γ_post), 10)\nten_post_samples_phys = transform_unconstrained_to_constrained(prior, ten_post_samples) # the optimal physical parameter value","category":"page"},{"location":"examples/sinusoid_example_toml/#TOML-interface-for-fitting-parameters-of-a-sinusoid","page":"TOML interface","title":"TOML interface for fitting parameters of a sinusoid","text":"","category":"section"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Here we revisit the simple sinusoid example, with the purpose of demonstrating how the EKP tools can interact with models in a non-intrusive fashion. In particular, this example will be useful for users whose model is written in another language, requires HPC management, or requires additional data processing stages.","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"We can generally orchestrate the different stages of the calibration process using a script file. Here we employ a Linux bash script:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"> bash calibrate_script","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Which executes the following sequence of processes (in this case, calls to julia --project)","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"# generate data\njulia --project generate_data.jl \n\n# create initial ensemble and build EKI\njulia --project initialize_EKP.jl \n\n# the EKI loop\nfor i in $(seq 1 $N_iterations); do\n\n # run the model at each ensemble member\n for j in $(seq 1 $N_ensemble); do\n julia --project run_computer_model.jl $i $j\n done\n\n # update the ensemble with EKI\n julia --project update_EKP.jl $i\n \ndone","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"The interaction between the calibration tools and the forward map are only through simple readable files stored in a nested file structure: for iteration i, ensemble member j","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Parameter values are stored (with their priors) in output/iteration_i/member_j/parameters.toml\nComputer model outputs are stored in output/iteration_i/member_j/model_output.jld2","category":"page"},{"location":"examples/sinusoid_example_toml/#Inputs-and-Outputs","page":"TOML interface","title":"Inputs and Outputs","text":"","category":"section"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"The prior distributions are provided in priors.toml in TOML format.","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"[amplitude]\nprior = \"Parameterized(Normal(0.5815754049028404, 0.47238072707743883))\"\nconstraint = \"bounded_below(0.0)\"\ndescription = \"\"\"\nThe amplitude of the sine curve.\nThis yields a physical prior that is log-normal with approximate (mean,sd) = (2,1)\n\"\"\"\n\n[vert_shift]\nprior = \"Parameterized(Normal(0,5))\"\nconstraint = \"no_constraint()\"\ndescription = \"\"\"\nThe vertical shift of the sine curve.\nThis yields a physical prior that is Normal with (mean,sd) = (0,5)\n\"\"\"","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"More information on the priors and constraints are given here. More examples defining priors in TOML format may be found in test/TOMLInterface/toml/.","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"After running the example, (it takes several minutes to run), results are stored in output/eki.jld2. To view the results, one can interact with the stored objects by loading julia --project and proceeding as follows:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"julia> using EnsembleKalmanProcesses, JLD2\n\njulia> @load \"output/eki.jld2\"\n3-element Vector{Symbol}:\n :eki\n :param_dict\n :prior","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"Then, for example, the final 6-member parameter ensemble is retrieved with:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"julia> get_ϕ_final(prior,eki)\n2×6 Matrix{Float64}:\n 1.38462 1.36124 1.32444 1.26686 1.33462 1.3636\n 6.51158 6.31867 6.68542 6.12809 6.44726 6.52448","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"while the initial ensemble is retrieved with:","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"julia> get_ϕ(prior, eki, 1)\n2×6 Matrix{Float64}:\n 1.05344 1.67949 6.29847 0.951586 2.07678 1.62284\n -7.00616 -0.931872 -6.11603 0.984338 0.274007 -1.39082","category":"page"},{"location":"examples/sinusoid_example_toml/","page":"TOML interface","title":"TOML interface","text":"note: Why is it so slow?\nThe example is slow because the forward map is written in Julia, and so 99.99% of computation for each call to julia --project is precompilation. Ensembles in Julia can be accelerated by using methods discussed here, or by compiling system images with PackageCompiler.jl, for example. This example is for instructional purposes only, and so is not optimized.","category":"page"},{"location":"inflation/#Inflation","page":"Inflation","title":"Inflation","text":"","category":"section"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Inflation is an approach that slows down collapse in ensemble Kalman methods. Two distinct forms of inflation are implemented in this package. Both involve perturbing the ensemble members following the standard update rule of the chosen Kalman process. Multiplicative inflation expands ensemble members away from their mean in a deterministic manner, whereas additive inflation hinges on the addition of stochastic noise to ensemble members.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"For both implementations, a scaling factor s is included to extend functionality to cases with mini-batching. The scaling factor s multiplies the artificial time step Delta t in the inflation equations to account for sampling error. For mini-batching, the scaling factor should be:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" s = fracBC","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"where B is the mini-batch size and C is the full dataset size.","category":"page"},{"location":"inflation/#Multiplicative-Inflation","page":"Inflation","title":"Multiplicative Inflation","text":"","category":"section"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Multiplicative inflation effectively scales parameter vectors in parameter space, such that the perturbed ensemble remains in the linear span of the original ensemble. The implemented update equation follows Huang et al, 2022 eqn. 41:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"beginaligned\n m_n+1 = m_n qquad u^j_n + 1 = m_n+1 + sqrtfrac11 - s Deltat left(u^j_n - m_n right) qquad (1)\nendaligned","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"where m is the ensemble average. In this way, the parameter covariance is inflated by a factor of frac11 - s Deltat, while the ensemble mean remains fixed.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" C_n + 1 = frac11 - s Deltat C_n qquad (2)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Multiplicative inflation can be used by flagging the update_ensemble! method as follows:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" EKP.update_ensemble!(ekiobj, g_ens; multiplicative_inflation = true, s = 1.0)","category":"page"},{"location":"inflation/#Additive-Inflation","page":"Inflation","title":"Additive Inflation","text":"","category":"section"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Additive inflation is implemented by systematically adding stochastic perturbations to the parameter ensemble in the form of Gaussian noise. Additive inflation breaks the linear subspace property, meaning the parameter ensemble can evolve outside of the span of the initial ensemble. In additive inflation, the ensemble is perturbed in the following manner after the standard Kalman update:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" u_n+1 = u_n + zeta_n qquad (3) \n zeta_n sim N(0 fracs Deltat 1 - s Deltat C_n) qquad (4)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"This inflates the parameter covariance by a factor of frac11 - s Deltat as in eqn. 2 , while the ensemble mean remains fixed.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Additive inflation can be used by flagging the update_ensemble! method as follows:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, s = 1.0)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Alternatively, the prior covariance matrix may be used to generate additive noise, following:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" zeta_n sim N(0 fracs Deltat 1 - s Deltat C_0) qquad (5)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"This results in an additive increase in the parameter covariance by fracs Deltat 1 - s Deltat * C_0 , while the mean remains fixed.","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" C_n + 1 = C_n + fracs Deltat 1 - s Deltat C_0 qquad (6)","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":"Additive inflation using the scaled prior covariance (parameter covariance of initial ensemble) can be used by flagging the update_ensemble! method as follows:","category":"page"},{"location":"inflation/","page":"Inflation","title":"Inflation","text":" EKP.update_ensemble!(ekiobj, g_ens; additive_inflation = true, use_prior_cov = true, s = 1.0)","category":"page"},{"location":"API/Observations/#Observations","page":"Observations","title":"Observations","text":"","category":"section"},{"location":"API/Observations/","page":"Observations","title":"Observations","text":"CurrentModule = EnsembleKalmanProcesses.Observations","category":"page"},{"location":"API/Observations/","page":"Observations","title":"Observations","text":"Observation","category":"page"},{"location":"API/Observations/#EnsembleKalmanProcesses.Observations.Observation","page":"Observations","title":"EnsembleKalmanProcesses.Observations.Observation","text":"Observation{FT <: AbstractFloat}\n\nStructure that contains the observations\n\nFields\n\nsamples::Array{Vector{FT}, 1} where FT<:AbstractFloat\nvector of observational samples, each of length sample_dim\nobs_noise_cov::Union{Nothing, LinearAlgebra.UniformScaling{FT}, AbstractMatrix{FT}, FT} where FT<:AbstractFloat\ncovariance of the observational noise (assumed to be normally distributed); sample_dim x sample_dim (where sample_dim is the number of elements in each sample), or a scalar if the sample dim is 1. If not supplied, obs_noise_cov is set to a diagonal matrix whose non-zero elements are the variances of the samples, or to a scalar variance in the case of 1d samples. obs_noise_cov is set to nothing if only a single sample is provided.\nmean::Union{AbstractVector{FT}, FT} where FT<:AbstractFloat\nsample mean\ndata_names::Union{String, AbstractVector{String}}\nnames of the data\n\n\n\n\n\n","category":"type"},{"location":"installation_instructions/#Installation","page":"Installation instructions","title":"Installation","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"EnsembleKalmanProcesses.jl is a registered Julia package. You can install the latest version of EnsembleKalmanProcesses.jl through the built-in package manager. Press ] in the Julia REPL command prompt and","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"julia> ]\n(v1.7) pkg> add EnsembleKalmanProcesses\n(v1.7) pkg> instantiate","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"This will install the latest tagged release of the package.","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"info: But I wanna be on the bleeding edge...\nIf you want the most recent developer's version of the package thenjulia> ]\n(v1.7) pkg> add EnsembleKalmanProcesses#main\n(v1.7) pkg> instantiate","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"You can run the tests via the package manager by:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"julia> ]\n(v1.7) pkg> test EnsembleKalmanProcesses","category":"page"},{"location":"installation_instructions/#Cloning-the-repository","page":"Installation instructions","title":"Cloning the repository","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"If you are interested in getting your hands dirty and modifying the code then, you can also clone the repository and then instantiate, e.g.,","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> cd EnsembleKalmanProcesses.jl\n> julia --project -e 'using Pkg; Pkg.instantiate()'","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"info: Do I need to clone the repository?\nMost times, cloning the repository in not necessary. If you only want to use the package's functionality, adding the packages as a dependency on your project is enough.","category":"page"},{"location":"installation_instructions/#Running-the-test-suite","page":"Installation instructions","title":"Running the test suite","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"You can run the package's tests:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project -e 'using Pkg; Pkg.test()'","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"Alternatively, you can do this from within the repository:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project\njulia> ]\n(EnsembleKalmanProcesses) pkg> test","category":"page"},{"location":"installation_instructions/#Building-the-documentation-locally","page":"Installation instructions","title":"Building the documentation locally","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"Once the project is built, you can build the project documentation under the docs/ sub-project:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'\n> julia --project=docs/ docs/make.jl","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"The locally rendered HTML documentation can be viewed at docs/build/index.html","category":"page"},{"location":"installation_instructions/#Running-repository-examples","page":"Installation instructions","title":"Running repository examples","text":"","category":"section"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"We have a selection of examples, found within the examples/ directory to demonstrate different use of our toolbox. Each example directory contains a Project.toml","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"To build with the latest EnsembleKalmanProcesses.jl release:","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> cd examples/example-name/\n> julia --project -e 'using Pkg; Pkg.instantiate()'\n> julia --project example-file-name.jl","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"If you wish to run a local modified version of EnsembleKalmanProcesses.jl then try the following (starting from the EnsembleKalmanProcesses.jl package root)","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> cd examples/example-name/\n> julia --project \n> julia> ]\n> (example-name)> rm EnsembleKalmanProcesses.jl\n> (example-name)> dev ../..\n> (example-name)> instantiate","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"followed by","category":"page"},{"location":"installation_instructions/","page":"Installation instructions","title":"Installation instructions","text":"> julia --project example-file-name.jl","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"EditURL = \"../../../examples/LossMinimization/loss_minimization.jl\"","category":"page"},{"location":"literated/loss_minimization/#Minimization-of-simple-loss-functions","page":"Minimization Loss","title":"Minimization of simple loss functions","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"First we load the required packages.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"using Distributions, LinearAlgebra, Random, Plots\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\nconst EKP = EnsembleKalmanProcesses","category":"page"},{"location":"literated/loss_minimization/#Loss-function-with-single-minimum","page":"Minimization Loss","title":"Loss function with single minimum","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Here, we minimize the loss function","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G₁(u) = u - u_* ","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"where u is a 2-vector of parameters and u_* is given; here u_* = (-1 1).","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"u★ = [1, -1]\nG₁(u) = [sqrt((u[1] - u★[1])^2 + (u[2] - u★[2])^2)]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We set the seed for pseudo-random number generator for reproducibility.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"rng_seed = 41\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We set a stabilization level, which can aid the algorithm convergence","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"dim_output = 1\nstabilization_level = 1e-3\nΓ_stabilization = stabilization_level * Matrix(I, dim_output, dim_output)","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The functional is positive so to minimize it we may set the target to be 0,","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G_target = [0]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/#Prior-distributions","page":"Minimization Loss","title":"Prior distributions","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"As we work with a Bayesian method, we define a prior. This will behave like an \"initial guess\" for the likely region of parameter space we expect the solution to live in. Here we define Normal(01) distributions with no constraints","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"prior_u1 = constrained_gaussian(\"u1\", 0, 1, -Inf, Inf)\nprior_u2 = constrained_gaussian(\"u1\", 0, 1, -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"note: Note\nIn this example there are no constraints, therefore no parameter transformations.","category":"page"},{"location":"literated/loss_minimization/#Calibration","page":"Minimization Loss","title":"Calibration","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We choose the number of ensemble members and the number of iterations of the algorithm","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"N_ensemble = 20\nN_iterations = 10\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The initial ensemble is constructed by sampling the prior","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"initial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We then initialize the Ensemble Kalman Process algorithm, with the initial ensemble, the target, the stabilization and the process type (for EKI this is Inversion, initialized with Inversion()).","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"ensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, G_target, Γ_stabilization, Inversion())\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Then we calibrate by (i) obtaining the parameters, (ii) calculate the loss function on the parameters (and concatenate), and last (iii) generate a new set of parameters using the model outputs:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"for i in 1:N_iterations\n params_i = get_u_final(ensemble_kalman_process)\n\n g_ens = hcat([G₁(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, g_ens)\nend","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"and visualize the results:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"u_init = get_u_prior(ensemble_kalman_process)\n\nanim_unique_minimum = @animate for i in 1:N_iterations\n u_i = get_u(ensemble_kalman_process, i)\n\n plot(\n [u★[1]],\n [u★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :red,\n label = \"optimum u⋆\",\n )\n\n plot!(\n u_i[1, :],\n u_i[2, :],\n seriestype = :scatter,\n xlims = extrema(u_init[1, :]),\n ylims = extrema(u_init[2, :]),\n xlabel = \"u₁\",\n ylabel = \"u₂\",\n markersize = 5,\n markeralpha = 0.6,\n markercolor = :blue,\n label = \"particles\",\n title = \"EKI iteration = \" * string(i),\n )\nend\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The results show that the minimizer of G_1 is u=u_*.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"gif(anim_unique_minimum, \"unique_minimum.gif\", fps = 1) # hide","category":"page"},{"location":"literated/loss_minimization/#Loss-function-with-two-minima","page":"Minimization Loss","title":"Loss function with two minima","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Now let's do an example in which the loss function has two minima. We minimize the loss function","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G₂(u) = u - v_* u - w_* ","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"where again u is a 2-vector, and v_* and w_* are given 2-vectors. Here, we take v_* = (1 -1) and w_* = (-1 -1).","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"v★ = [1, -1]\nw★ = [-1, -1]\nG₂(u) = [sqrt(((u[1] - v★[1])^2 + (u[2] - v★[2])^2) * ((u[1] - w★[1])^2 + (u[2] - w★[2])^2))]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"The procedure is same as the single-minimum example above.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We set the seed for pseudo-random number generator for reproducibility,","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"rng_seed = 10\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"A positive function can be minimized with a target of 0,","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"G_target = [0]","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We choose the stabilization as in the single-minimum example","category":"page"},{"location":"literated/loss_minimization/#Prior-distributions-2","page":"Minimization Loss","title":"Prior distributions","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We define the prior. We can place prior information on e.g., u₁, demonstrating a belief that u₁ is more likely to be negative. This can be implemented by setting a bias in the mean of its prior distribution to e.g., -05:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"prior_u1 = constrained_gaussian(\"u1\", -0.5, sqrt(2), -Inf, Inf)\nprior_u2 = constrained_gaussian(\"u1\", 0, sqrt(2), -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"note: Note\nIn this example there are no constraints, therefore no parameter transformations.","category":"page"},{"location":"literated/loss_minimization/#Calibration-2","page":"Minimization Loss","title":"Calibration","text":"","category":"section"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We choose the number of ensemble members, the number of EKI iterations, construct our initial ensemble and the EKI with the Inversion() constructor (exactly as in the single-minimum example):","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"N_ensemble = 20\nN_iterations = 20\n\ninitial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)\n\nensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, G_target, Γ_stabilization, Inversion())","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"We calibrate by (i) obtaining the parameters, (ii) calculating the loss function on the parameters (and concatenate), and last (iii) generate a new set of parameters using the model outputs:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"for i in 1:N_iterations\n params_i = get_u_final(ensemble_kalman_process)\n\n g_ens = hcat([G₂(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, g_ens)\nend","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"and visualize the results:","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"u_init = get_u_prior(ensemble_kalman_process)\n\nanim_two_minima = @animate for i in 1:N_iterations\n u_i = get_u(ensemble_kalman_process, i)\n\n plot(\n [v★[1]],\n [v★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :red,\n label = \"optimum v⋆\",\n )\n\n plot!(\n [w★[1]],\n [w★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :green,\n label = \"optimum w⋆\",\n )\n\n plot!(\n u_i[1, :],\n u_i[2, :],\n seriestype = :scatter,\n xlims = extrema(u_init[1, :]),\n ylims = extrema(u_init[2, :]),\n xlabel = \"u₁\",\n ylabel = \"u₂\",\n markersize = 5,\n markeralpha = 0.6,\n markercolor = :blue,\n label = \"particles\",\n title = \"EKI iteration = \" * string(i),\n )\nend\nnothing # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"Our bias in the prior shifts the initial ensemble into the negative u_1 direction, and thus increases the likelihood (over different instances of the random number generator) of finding the minimizer u=w_*.","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"gif(anim_two_minima, \"two_minima.gif\", fps = 1) # hide","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"","category":"page"},{"location":"literated/loss_minimization/","page":"Minimization Loss","title":"Minimization Loss","text":"This page was generated using Literate.jl.","category":"page"},{"location":"parameter_distributions/#parameter-distributions","page":"Prior distributions","title":"Defining prior distributions","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Bayesian inference begins with an explicit prior distribution. This page describes the interface EnsembleKalmanProcesses provides for specifying priors on parameters, via the ParameterDistributions module (src/ParameterDistributions.jl).","category":"page"},{"location":"parameter_distributions/#Summary","page":"Prior distributions","title":"Summary","text":"","category":"section"},{"location":"parameter_distributions/#ParameterDistribution-objects","page":"Prior distributions","title":"ParameterDistribution objects","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"A prior is specified by a ParameterDistribution object, which has three components:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The distribution itself, given as a ParameterDistributionType object. This includes standard Julia Distributions, GaussianRandomFields as well as empirical/sample-based distributions, and thus can be univariate, multivariate or functional. To clarify, despite our use of the term \"Kalman processes,\" the prior distribution is not required to be Gaussian.\nA constraint (or array of constraints) on the domain of the distribution, given as a ConstraintType or Array{ConstraintType} object (the latter case builds a multivariate constraint as the Cartesian product of one-dimensional Constraints). This is used to enforce physical parameter values during inference: the model is never evaluated at parameter values outside the constrained region, and the posterior distribution will only be supported there.\nThe parameter name, given as a String.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"In multiparameter settings, one should define one ParameterDistribution per parameter, and then concatenate these either in the constructor or with combine_distributions. This is illustrated below and in the Example combining several distributions.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: What's up with the notation u, ϕ, and θ?\nParameters in unconstrained spaces are often denoted u or theta in the literature. In the code, method names featuring _u imply the return of a computational, unconstrained parameter.Parameters in physical/constrained spaces are often denoted mathcalT^-1(u), mathcalT^-1(theta), or phi in the literature (for some bijection mathcalT mapping to the unbounded space). In the code, method names featuring _ϕ imply the return of a physical, constrained parameter, and will always require a prior as input to perform the transformations internally.For more notations see our Glossary.","category":"page"},{"location":"parameter_distributions/#constrained-gaussian","page":"Prior distributions","title":"Recommended constructor","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"constrained_gaussian() is a streamlined constructor for ParameterDistributions which addresses the most common use case; more general forms of the constructor are documented below, but we highly recommend that users begin here when it comes to specifying priors, only using the general constructor when necessary.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Usage:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"lower_bound = 0.0\nupper_bound = 1.0\nμ_1 = 0.5\nμ_2 = 0.5\nσ_1 = 0.25\nσ_2 = 0.25","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `constrained_gaussian`, `combine_distributions`\nprior_1 = constrained_gaussian(\"param_1\", μ_1, σ_1, lower_bound, upper_bound)\nprior_2 = constrained_gaussian(\"param_2\", μ_2, σ_2, 0.0, Inf, repeats=3)\nprior = combine_distributions([prior_1, prior_2])","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior_1 is a ParameterDistribution describing a prior distribution for a parameter named \"param_1\" taking values on the interval [lower_bound, upper_bound]; the prior distribution has approximate mean μ_1 and standard deviation σ_1.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior_2 is a ParameterDistribution describing a 3-dimensional prior distribution for a parameter named \"param_2\" with each dimensions taking independent values on the half-open interval [0.0, Inf); the marginals of this prior distribution have approximate mean μ_2 and standard deviation σ_2.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The use case constrained_gaussian() addresses is when prior information is qualitative, and exact distributions of the priors are unknown: i.e., the user is only able to specify the physical and likely ranges of prior parameter values at a rough, qualitative level. constrained_gaussian() does this by constructing a ParameterDistribution corresponding to a Gaussian \"squashed\" to fit in the given constraint interval, such that the \"squashed\" distribution has the specified mean and standard deviation (e.g. prior_2 above is a log-normal for each dimension).","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The parameters of the Gaussian are chosen automatically (depending on the constraint) to reproduce the desired μ and σ — per the use case, other details of the form of the prior distribution shouldn't be important for downstream inference! ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: Slow/Failed construction?\nThe most common case of slow or failed construction is when requested parameters place too much mass at the hard boundary. A typical case is when the requested variance satisfies sigma approx mathrmdist(mumathrmboundary) Such priors can be defined, but not with our convenience constructor. If this is not the case but you still get failures please let us know!","category":"page"},{"location":"parameter_distributions/#Plotting","page":"Prior distributions","title":"Plotting","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"For quick visualization we have a plot recipe for ParameterDistribution types. This will plot marginal histograms for all dimensions of the parameter distribution. For example, ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# with values:\n# e.g. lower_bound = 0.0, upper_bound = 1.0\n# μ_1 = 0.5, σ_1 = 0.25\n# μ_2 = 0.5, σ_2 = 0.25\n\nusing Plots\nplot(prior) ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"One can also access the underlying Gaussian distributions in the unconstrained space with","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Plots\nplot(prior, constrained=false) ","category":"page"},{"location":"parameter_distributions/#Recommended-constructor-Simple-example","page":"Prior distributions","title":"Recommended constructor - Simple example","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Task: We wish to create a prior for a one-dimensional parameter. Our problem dictates that this parameter is bounded between 0 and 1; domain knowledge leads us to expect it should be around 0.7. The parameter is called point_seven.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We're told that the prior mean is 0.7; we choose a prior standard deviation of 0.15 to be sufficiently wide without putting too much mass at the upper bound. The constructor is then","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `constrained_gaussian`\nprior = constrained_gaussian(\"point_seven\", 0.7, 0.15, 0.0, 1.0)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# instead of importing ParameterDistributions & dependencies to call constructor,\n# which would make docs build longer and more fragile, simply hard-code Normal()\n# parameters found by constrained_gaussian constructor\n\nusing Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:6/400:5)\n\n#bounded in [0.0, 1.0]\ntransform_unconstrained_to_constrained(x) = 1.0 - 1.0 / (exp(x) + 1)\ndist= pdf.(Normal(0.957711, 0.78507), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np2 = plot(constrained_x_eval, dist) \nvline!([0.7]) \ntitle!(\"Prior pdf\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The pdf of the constructed prior distribution (in the physical, constrained space) looks like:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p2, legend=false, size = (450, 450)) #hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"In Simple example revisited below, we repeat this example \"manually\" with the general constructor.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: What if I want to impose the same prior on many parameters?\nThe recommended constructor can be called as constrained_gaussian(...; repeats = n) to return a combined prior formed by n identical priors.","category":"page"},{"location":"parameter_distributions/#ParameterDistribution-struct","page":"Prior distributions","title":"ParameterDistribution struct","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This section provides more details on the components of a ParameterDistribution object.","category":"page"},{"location":"parameter_distributions/#ParameterDistributionType","page":"Prior distributions","title":"ParameterDistributionType","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The ParameterDistributionType struct wraps four types for specifying different types of prior distributions:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The Parameterized type is initialized using a Julia Distributions.jl object. Samples are drawn randomly from the distribution object.\nThe VectorOfParameterized type is initialized with a vector of distributions.\nThe Samples type is initialized using a two dimensional array. Samples are drawn randomly (with replacement) from the columns of the provided array.\nThe FunctionParameterDistributionType struct defines parameters specified as fields over a domain. More detail can be found here.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"warning: Warning\nWe recommend that the distributions be unbounded (see next section), as the filtering algorithms in EnsembleKalmanProcesses are not guaranteed to preserve constraints unless defined through the ConstraintType mechanism.","category":"page"},{"location":"parameter_distributions/#ConstraintType","page":"Prior distributions","title":"ConstraintType","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The inference algorithms implemented in EnsembleKalmanProcesses assume unbounded parameter domains. To be able to handle constrained parameter values consistently, the ConstraintType defines a bijection between the physical, constrained parameter domain and an unphysical, unconstrained domain in which the filtering takes place. This bijection is specified by the functions transform_constrained_to_unconstrained and transform_unconstrained_to_constrained, which are built from either predefined constructors or user-defined constraint functions given as arguments to the ConstraintType constructor. ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We provide the following predefined constructors which implement mappings that handle the most common constraints:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"no_constraint(): The parameter is unconstrained and takes values in (-∞, ∞) (mapping is the identity).\nbounded_below(lower_bound): The parameter takes values in [lower_bound, ∞).\nbounded_above(upper_bound): The parameter takes values in (-∞, upper_bound].\nbounded(lower_bound,upper_bound): The parameter takes values on the interval [lower_bound, upper_bound].","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"These are demonstrated in ConstraintType Examples.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Currently we only support multivariate constraints which are the Cartesian product of the one-dimensional ConstraintTypes. Every component of a multidimensional parameter must have an associated constraint, so, e.g. for a multivariate ParameterDistributionType of dimension p the user must provide a p-dimensional Array{ConstraintType}. A VectorOfParameterized distribution built with distributions of dimension p and q has dimension p+q.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: Note\nWhen a nontrivial ConstraintType is given, the general constructor assumes the ParameterDistributionType is specified in the unconstrained space; the actual prior pdf is then the composition of the ParameterDistributionType's pdf with the transform_unconstrained_to_constrained transformation. We provide constrained_gaussian to define priors directly in the physical, constrained space.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"warning: Warning\nIt is up to the user to ensure any custom mappings transform_constrained_to_unconstrained and transform_unconstrained_to_constrained are inverses of each other.","category":"page"},{"location":"parameter_distributions/#The-name","page":"Prior distributions","title":"The name","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This is simply a String used to identify different parameters in multi-parameter situations, as in the methods below.","category":"page"},{"location":"parameter_distributions/#function-parameter-type","page":"Prior distributions","title":"FunctionParameterDistributionType","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Learning a function distribution is useful when one wishes to obtain a parametric representation of a function that is (relatively) agnostic of the underlying grid discretization. Most practical implementations involve posing a restrictive class of functions by truncation of a spectral decomposition. The function is then represented as a set of coefficients of these modes (known as degrees of freedom), rather than directly through the values at evaluation points.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"As a subtype of ParameterDistributionType, we currently support one option for specifying prior distributions over functions:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The GaussianRandomFieldInterface type is initialized with a Gaussian Random Field object and the GRF package. Currently we support objects from GaussianRandomFields.jl with package GRFJL(). Gaussian random fields allow the definition of scalar function distributions defined over a uniform mesh on interval, rectangular, and hyper-rectangular domains.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"As with other ParameterDistributions, a function distribution, is built from a name, a FunctionPameterDistributionType struct and a constraint, here only one, placed on the scalar output space of the function using a Constraint().","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: constraints\nThe transformation transform_unconstrained_to_constrained, will map from (unconstrained) degrees of freedom, to (constrained) evaluations of the function on a numerical grid. In particular, the transform_constrained_to_unconstrained is no longer the inverse of this map, it now simply maps from constrained evaluations to unconstrained evaluations on the grid.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We provide an example construction here.","category":"page"},{"location":"parameter_distributions/#ParameterDistribution-constructor","page":"Prior distributions","title":"ParameterDistribution constructor","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The Recommended constructor, constrained_gaussian(), is described above. For more general cases in which the prior needs to be specified in more detail, a ParameterDistribution may be constructed \"manually\" from its component objects:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`, `combine_distributions`\nusing Distributions\ndistribution_1 = Parameterized(Normal(0,1))\ndistribution_2 = Parameterized(Normal(0,1))\nconstraint_1 = no_constraint()\nconstraint_2 = no_constraint()\nname_1 = \"m\"\nname_2 = \"mm\"","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`, `combine_distributions`\nprior_1 = ParameterDistribution(distribution_1, constraint_1, name_1)\nprior_2 = ParameterDistribution(distribution_2, constraint_2, name_2)\nprior = combine_distributions( [prior_1, prior_2])\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Arguments may also be provided as a Dict:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `ParameterDistribution`\ndict_1 = Dict(\"distribution\" => distribution_1, \"constraint\" => constraint_1, \"name\" => name_1)\ndict_2 = Dict(\"distribution\" => distribution_2, \"constraint\" => constraint_2, \"name\" => name_2)\nprior = ParameterDistribution( [dict_1, dict_2] )\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We provide Additional Examples below; see also examples in the package examples/ and unit tests found in test/ParameterDistributions/runtests.jl.","category":"page"},{"location":"parameter_distributions/#ParameterDistribution-methods","page":"Prior distributions","title":"ParameterDistribution methods","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"These functions typically return a Dict with ParameterDistribution.name as a keys, or an Array if requested:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"get_name: returns the name(s) of parameters in the ParameterDistribution.\nget_distribution: returns the distributions (ParameterDistributionType objects) in the ParameterDistribution. Note that this is not the prior pdf used for inference if nontrivial constraints have been applied.\nmean, var, cov, sample, logpdf: mean, variance, covariance, logpdf or samples the Julia Distribution if Parameterized, or draws from the list of samples if Samples. Extends the StatsBase definitions. Note that these do not correspond to the prior pdf used for inference if nontrivial constraints have been applied.\ntransform_unconstrained_to_constrained: Applies the constraint mappings.\ntransform_constrained_to_unconstrained: Applies the inverse constraint mappings.","category":"page"},{"location":"parameter_distributions/#Additional-Examples","page":"Prior distributions","title":"Additional Examples","text":"","category":"section"},{"location":"parameter_distributions/#Simple-example-revisited","page":"Prior distributions","title":"Simple example revisited","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"To illustrate what the constrained_gaussian constructor is doing, in this section we repeat the Recommended constructor - Simple example given above, using the \"manual,\" general-purpose constructor. Let's bring in the packages we will require","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `bounded`, `Parameterized`, and `ParameterDistribution` \nusing Distributions # for `Normal`\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Then we initialize the constraint first,","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"constraint = bounded(0, 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This defines the following transformation to the constrained space (and also its inverse)","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = exp(x) / (exp(x) + 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The prior mean should be around 0.7 (in the constrained space), and one can find that the push-forward of a particular normal distribution, namely, transform_unconstrained_to_constrained(Normal(mean = 1, sd = 0.5)) gives a prior pdf with 95% of its mass between [0.5, 0.88]. ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This is the main difference from the use of the constrained_gaussian constructor: in that example, the constructor numerically solved for the parameters of the Normal() which would reproduce the requested μ, σ for the physical, constrained quantity (since no closed-form transformation for the moments exists.)","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"distribution = Parameterized(Normal(1, 0.5))\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Finally we attach the name","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"name = \"point_seven\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"and the distribution is created by either:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior = ParameterDistribution(distribution, constraint, name)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"or","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"prior_dict = Dict(\"distribution\" => distribution, \"constraint\" => constraint, \"name\" => name)\nprior = ParameterDistribution(prior_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-3:6/400:3)\n\n#bounded in [0.0, 1.0]\ntransform_unconstrained_to_constrained(x) = exp(x) / (exp(x) + 1)\ndist= pdf.(Normal(1, 0.5), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(x_eval, dist,) \nvline!([1.0]) \ntitle!(\"Normal(1, 0.5)\")\n\np2 = plot(constrained_x_eval, dist) \nvline!([transform_unconstrained_to_constrained(1.0)]) \ntitle!(\"Constrained Normal(1, 0.5)\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The pdf of the Normal distribution and its transform to the physical, constrained space are:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p1, p2, legend=false, size = (900, 450)) #hide","category":"page"},{"location":"parameter_distributions/#samples-example","page":"Prior distributions","title":"Sample-based distribution","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We repeat the work of Simple example revisited, but now assuming that to create our prior, we only have samples given by the histogram:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# instead of importing ParameterDistributions & dependencies to call constructor,\n# which would make docs build longer and more fragile, simply hard-code Normal()\n# parameters found by constrained_gaussian constructor\n\nusing Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 5000\n\n#bounded in [0.0, 1.0]\ntransform_unconstrained_to_constrained(x) = 1.0 - 1.0 / (exp(x) + 1)\nsamples = rand(Normal(0.957711, 0.78507), N)\nconstrained_samples = transform_unconstrained_to_constrained.(samples)\n\np3 = histogram(constrained_samples, bins=50) \nvline!([0.7]) \ntitle!(\"Prior of samples\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p3, legend=false, size = (450, 450)) #hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Imagine we do not know this distribution is bounded. To create a ParameterDistribution one can take a matrix constrained_samples whose columns are this data:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Samples`, `no_constraint`, `ParameterDistribution`, `bounded`\nconstrained_samples = [0.1 0.2 0.3 0.4] # hide\ndistribution = Samples(constrained_samples)\nconstraint = no_constraint()\nname = \"point_seven\"\nprior = ParameterDistribution(distribution, constraint, name)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"note: Note\nThis naive implementation will not enforce any boundaries during the algorithm implementation.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Imagine that we know about the boundedness of this distribution, then, as in Simple example revisited, we define the constraint","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"constraint = bounded(0, 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"which stores the transformation:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"unconstrained_samples = constraint.constrained_to_unconstrained.(constrained_samples)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"This maps the samples into an unbounded space, giving the following histogram:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"# instead of importing ParameterDistributions & dependencies to call constructor,\n# which would make docs build longer and more fragile, simply hard-code Normal()\n# parameters found by constrained_gaussian constructor\n\nusing Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 5000\n\n# bounded in [0.0, 1.0]\n# transform_unconstrained_to_constrained(x) = 1.0 - 1.0 / (exp(x) + 1.0)\n transform_constrained_to_unconstrained(x) = log(1.0 / (1.0 - x) - 1.0)\nunconstrained_samples = rand(Normal(0.957711, 0.78507), N)\n\np3 = histogram(unconstrained_samples, bins=50) \nvline!([transform_constrained_to_unconstrained(0.7)]) \ntitle!(\"Prior of samples\")","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"p = plot(p3, legend=false, size = (450, 450)) #hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"As before we define a Samples distribution from matrix whose columns are the (now unconstrained) samples, along with a name to create the ParameterDistribution.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"distribution = Samples(unconstrained_samples)\nname = \"point_seven\"\nprior = ParameterDistribution(distribution, constraint, name)\nnothing # hide","category":"page"},{"location":"parameter_distributions/#Example-combining-several-distributions","page":"Prior distributions","title":"Example combining several distributions","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"To show how to combine priors in a more complex setting (e.g. for an entire parametrized process), we create a 25-dimensional parameter distribution from three dictionaries.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Bring in the packages!","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions\n# for `bounded_below`, `bounded`, `Constraint`, `no_constraint`,\n# `Parameterized`, `Samples`,`VectorOfParameterized`,\n# `ParameterDistribution`, `combine_distributions`\nusing LinearAlgebra # for `SymTridiagonal`, `Matrix`\nusing Distributions # for `MvNormal`, `Beta`\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The first parameter is a 3-dimensional distribution, with the following bound constraints on parameters in physical space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"c1 = repeat([bounded_below(0)], 3)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We know that a multivariate normal represents its distribution in the transformed (unbounded) space. Here we take a tridiagonal covariance matrix.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"diagonal_val = 0.5 * ones(3)\nudiag_val = 0.25 * ones(2)\nmean = ones(3)\ncovariance = Matrix(SymTridiagonal(diagonal_val, udiag_val))\nd1 = Parameterized(MvNormal(mean, covariance)) # 3D multivariate normal\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We also provide a name","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"name1 = \"constrained_mvnormal\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The second parameter is a 2-dimensional one. It is only given by 4 samples in the transformed space - (where one will typically generate samples). It is bounded in the first dimension by the constraint shown, there is a user provided transform for the second dimension - using the default constructor.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"d2 = Samples([1.0 5.0 9.0 13.0; 3.0 7.0 11.0 15.0]) # 4 samples of 2D parameter space\n\ntransform = (x -> 3 * x + 14)\njac_transform = (x -> 3)\ninverse_transform = (x -> (x - 14) / 3)\nabstract type Affine <: ConstraintType end\n\nc2 = [bounded(10, 15),\n Constraint{Affine}(transform, jac_transform, inverse_transform, nothing)]\nname2 = \"constrained_sampled\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The final parameter is 4-dimensional, defined as a list of i.i.d univariate distributions we make use of the VectorOfParameterized type","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"d3 = VectorOfParameterized(repeat([Beta(2,2)],4))\nc3 = repeat([no_constraint()],4)\nname3 = \"Beta\"\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The full prior distribution for this setting is created either through building simple distributions and combining","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"u1 = ParameterDistribution(d1, c1, name1)\nu2 = ParameterDistribution(d2, c2, name2)\nu3 = ParameterDistribution(d3, c3, name3)\nu = combine_distributions( [u1, u2, u3])\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"or an array of the parameter specifications as dictionaries.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"param_dict1 = Dict(\"distribution\" => d1, \"constraint\" => c1, \"name\" => name1)\nparam_dict2 = Dict(\"distribution\" => d2, \"constraint\" => c2, \"name\" => name2)\nparam_dict3 = Dict(\"distribution\" => d3, \"constraint\" => c3, \"name\" => name3)\nu = ParameterDistribution([param_dict1, param_dict2, param_dict3])\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We can visualize the marginals of the constrained distributions,","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Plots\nplot(u)","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"and the unconstrained distributions similarly,","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Plots\nplot(u, constrained = false)","category":"page"},{"location":"parameter_distributions/#function-example","page":"Prior distributions","title":"Function Distribution Example","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"Here, define a function parameter distribution on 01 times 12 , bounded by -5-3 and with correlation lengthscales 0.05. First, we get the packages:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # For `ParameterDistribution`\nusing Random, Distributions # for `rand` and `Normal`\nusing Plots\n# We must `import` the GRF package, rather than call a `using` statement here\nimport GaussianRandomFields # for `GaussianRandomFields`","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"then, we use the GaussianRandomFields.jl package to define the distribution of choice. This distribution is unbounded. Here we take a Matern kernel, and define our evaluation grid on the domain. We choose 30 degrees of freedom (dofs), so this function distribution is specified through the value of 30 learnable coefficients. ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"const GRF = GaussianRandomFields\n# Define a `GaussianRandomFields` object\ninput_dim = 2 # Define a 2D -> 1D function\ndofs = 30 # the number of modes defining the distribution\npoints = [collect(0:0.01:1), collect(1:0.02:2)] # the 2D domain grid (uniform in each dimension)\n\ngrfjl_obj = GRF.GaussianRandomField(\n GRF.CovarianceFunction(input_dim, GRF.Matern(0.05, 2)),\n GRF.KarhunenLoeve(dofs),\n points...,\n) # the Gaussian Random Field object from the package\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We define our parameter distribution wrapper, where GRFJL() indicates the GRF package used. We also impose bounds into an interval -5-3 (here applied to the output space).","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"grf = GaussianRandomFieldInterface(grfjl_obj, GRFJL()) # our wrapper\npd = ParameterDistribution(\n Dict(\n \"distribution\" => grf,\n \"constraint\" => bounded(-5, -3), \n \"name\" => \"func_in_min5_min3\",\n )\n) # The ParameterDistribution with constraint in the output space\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"We plot 4 samples of this distribution. Samples are taken over the (30-dimensional) degrees of freedom, and then we apply the transform_unconstrained_to_costrained map to (i) build the function distribution, (ii) evaluate it on the numerical grid, and (iii) constrain the output with our prescribed bounds.","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"shape = [length(pp) for pp in points]\nsamples_constrained_flat = [transform_unconstrained_to_constrained(pd, rand(Normal(0,1), dofs)) for i = 1:4] \nplts = [contour(points..., reshape(samples_constrained_flat[i], shape...)', fill = true,) for i =1:4]\nplot(plts..., legend=false, size=(800,800)) ","category":"page"},{"location":"parameter_distributions/#ConstraintType-Examples","page":"Prior distributions","title":"ConstraintType Examples","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"For each for the predefined ConstraintTypes, we present animations of the resulting constrained prior distribution for","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions, Distributions # hide\nμ = 0 # hide\nσ = 1 # hide\ndistribution = Parameterized(Normal(μ, σ))\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where we vary μ and σ respectively. As noted above, in the presence of a nontrivial constraint, μ and σ will no longer correspond to the mean and standard deviation of the prior distribution (which is taken in the physical, constrained space).","category":"page"},{"location":"parameter_distributions/#Without-constraints:-\"constraint\"-no_constraints()","page":"Prior distributions","title":"Without constraints: \"constraint\" => no_constraints()","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior based on an unconstrained Normal(0.5, 1) distribution:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `no_constraint`, `ParameterDistribution`\nusing Distributions # for `Normal`\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => no_constraint(),\n\"name\" => \"unbounded_parameter\",\n)\n\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where no_constraint() automatically defines the identity constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = x\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the constrained space (which is trivial here):","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:10/200:5)\nmean_varying = collect(-3:6/(N+1):3)\nsd_varying = collect(0.1:2.9/(N+1):3)\n\n# no constraint\ntransform_unconstrained_to_constrained(x) = x\n\nmean0norm(n) = pdf.(Normal(0, sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1, p2, layout=(1, 2), size = (900, 450), legend = false)\n \nanim_unbounded = @animate for n = 1:length(mean_varying)\n #set new y data \n p[1][1][:y] = mean0norm(n) \n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\" \n p[2][1][:y] = sd1norm(n) \n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_unbounded, \"anim_unbounded.gif\", fps = 5) # hide","category":"page"},{"location":"parameter_distributions/#Bounded-below-by-0:-\"constraint\"-bounded_below(0)","page":"Prior distributions","title":"Bounded below by 0: \"constraint\" => bounded_below(0)","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior for a parameter which is bounded below by 0 (i.e. its only physical values are positive), and which has a Normal(0.5, 1) distribution in the unconstrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `bounded_below`, `ParameterDistribution`\nusing Distributions # for `Normal`\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => bounded_below(0),\n\"name\" => \"bounded_below_parameter\",\n)\n\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where bounded_below(0) automatically defines the constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = exp(x)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the physical, constrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:10/400:5)\nmean_varying = collect(-1:5/(N+1):4)\nsd_varying = collect(0.1:3.9/(N+1):4)\n\n#bounded below by 0\ntransform_unconstrained_to_constrained(x) = exp(x)\n\nmean0norm(n) = pdf.(Normal(0,sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1,p2, layout=(1,2), size = (900,450), legend=false)\n \nanim_bounded_below = @animate for n = 1:length(mean_varying) \n #set new y data \n p[1][1][:y] = mean0norm(n) \n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\"\n p[2][1][:y] = sd1norm(n) \n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_bounded_below, \"anim_bounded_below.gif\", fps = 5) # hide","category":"page"},{"location":"parameter_distributions/#Bounded-above-by-10.0:-\"constraint\"-bounded_above(10)","page":"Prior distributions","title":"Bounded above by 10.0: \"constraint\" => bounded_above(10)","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior for a parameter which is bounded above by ten, and which has a Normal(0.5, 1) distribution in the unconstrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions # for `Parameterized`, `bounded_above`, `ParameterDistribution`\nusing Distributions\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => bounded_above(10),\n\"name\" => \"bounded_above_parameter\",\n)\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where bounded_above(10) automatically defines the constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = 10 - exp(-x)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the physical, constrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-5:4/400:5)\nmean_varying = collect(-1:5/(N+1):4)\nsd_varying = collect(0.1:3.9/(N+1):4)\n\n#bounded above by 10.0\ntransform_unconstrained_to_constrained(x) = 10 - exp(-x)\n\nmean0norm(n) = pdf.(Normal(0, sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1, p2, layout=(1, 2), size = (900, 450), legend=false)\n \nanim_bounded_above = @animate for n = 1:length(mean_varying)[1]\n #set new y data\n p[1][1][:y] = mean0norm(n)\n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\"\n p[2][1][:y] = sd1norm(n)\n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_bounded_above, \"anim_bounded_above.gif\", fps = 5) # hide","category":"page"},{"location":"parameter_distributions/#Bounded-between-5-and-10:-\"constraint\"-bounded(5,-10)","page":"Prior distributions","title":"Bounded between 5 and 10: \"constraint\" => bounded(5, 10)","text":"","category":"section"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following specifies a prior for a parameter whose physical values lie in the range between 5 and 10, and which has a Normal(0.5, 1) distribution in the unconstrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using EnsembleKalmanProcesses.ParameterDistributions# for `Parameterized`, `bounded`, `ParameterDistribution`\nusing Distributions # for `Normal`\n\nparam_dict = Dict(\n\"distribution\" => Parameterized(Normal(0.5, 1)),\n\"constraint\" => bounded(5, 10),\n\"name\" => \"bounded_parameter\",\n)\n\nprior = ParameterDistribution(param_dict)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"where bounded(-1, 5) automatically defines the constraint map","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"transform_unconstrained_to_constrained(x) = 10 - 5 / (exp(x) + 1)\nnothing # hide","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"The following plots show the effect of varying μ and σ in the physical, constrained space:","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"using Distributions\nusing Plots\nPlots.default(lw=2)\n\nN = 50\nx_eval = collect(-10:20/400:10)\nmean_varying = collect(-3:2/(N+1):3)\nsd_varying = collect(0.1:0.9/(N+1):10)\n\n#bounded in [5.0, 10.0]\ntransform_unconstrained_to_constrained(x) = 10 - 5 / (exp(x) + 1)\n\nmean0norm(n) = pdf.(Normal(0, sd_varying[n]), x_eval)\nsd1norm(n) = pdf.(Normal(mean_varying[n], 1), x_eval)\nconstrained_x_eval = transform_unconstrained_to_constrained.(x_eval)\n\np1 = plot(constrained_x_eval, mean0norm.(1))\nvline!([transform_unconstrained_to_constrained(0)])\n\np2 = plot(constrained_x_eval, sd1norm.(1))\nvline!([transform_unconstrained_to_constrained(mean_varying[1])])\n\np = plot(p1, p2, layout=(1, 2), size = (900, 450), legend=false)\n \nanim_bounded = @animate for n = 1:length(mean_varying)\n #set new y data\n p[1][1][:y] = mean0norm(n)\n p[1][:title] = \"Transformed Normal(0, \" * string(round(sd_varying[n], digits=3)) * \")\"\n p[2][1][:y] = sd1norm(n)\n p[2][2][:x] = [transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n]),\n transform_unconstrained_to_constrained(mean_varying[n])]\n p[2][:title] = \"Transformed Normal(\" * string(round(mean_varying[n], digits=3)) * \", 1)\"\nend ","category":"page"},{"location":"parameter_distributions/","page":"Prior distributions","title":"Prior distributions","text":"gif(anim_bounded, \"anim_bounded.gif\", fps = 10) # hide","category":"page"},{"location":"internal_data_representation/#Wrapping-up-data","page":"Internal data representation","title":"Wrapping up data","text":"","category":"section"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"To provide a consistent form for data (such as observations, parameter ensembles, model evaluations) across the package, we store the data in simple wrappers internally.","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"Data is always stored as columns of AbstractMatrix. That is, we obey the format","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"[ data dimension x number of data samples ]","category":"page"},{"location":"internal_data_representation/#The-DataContainer","page":"Internal data representation","title":"The DataContainer","text":"","category":"section"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"A DataContainer is constructed initially by copying and perhaps transposing matrix data","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"dc = DataContainer(abstract_matrix; data_are_columns = true)","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"The flag data_are_columns indicates whether the provided data is stored column- or row-wise. The data is retrieved with","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"get_data(dc)","category":"page"},{"location":"internal_data_representation/#The-PairedDataContainer","page":"Internal data representation","title":"The PairedDataContainer","text":"","category":"section"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"A PairedDataContainer stores pairs of inputs and outputs in the form of DataContainers. It is constructed from two data matrices, or from two DataContainers.","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"pdc = PairedDataContainer(input_matrix, output_matrix; data_are_columns = true)\npdc = PairedDataContainer(input_data_container, output_data_container)","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"Data is retrieved with","category":"page"},{"location":"internal_data_representation/","page":"Internal data representation","title":"Internal data representation","text":"get_data(pdc) # returns both inputs and outputs\nget_inputs(pdc)\nget_outputs(pdc)","category":"page"},{"location":"learning_rate_scheduler/#learning-rate-schedulers","page":"Learning rate schedulers","title":"Learning Rate Schedulers (a.k.a) Timestepping","text":"","category":"section"},{"location":"learning_rate_scheduler/#Overview","page":"Learning rate schedulers","title":"Overview","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"We demonstrate the behaviour of different learning rate schedulers through solution of a nonlinear inverse problem.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"In this example we have a model that produces the exponential of a sinusoid f(A v) = exp(A sin(t) + v) forall t in 02pi. Given an initial guess of the parameters as A^* sim mathcalN(21) and v^* sim mathcalN(025), the inverse problem is to estimate the parameters from a noisy observation of only the maximum and mean value of the true model output.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"We shall compare the following configurations of implemented schedulers. ","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Fixed, \"long\" timestep DefaultScheduler(0.5) - orange\nFixed, \"short\" timestep DefaultScheduler(0.02) - green\nAdaptive timestep (designed originally to ensure EKS remains stable) EKSStableScheduler() Kovachki & Stuart 2018 - red\nMisfit controlling timestep (Terminating) DataMisfitController() Iglesias & Yang 2021 - purple\nMisfit controlling timestep (Continuing beyond Terminate condition) DataMisfitController(on_terminate=\"continue\") - brown","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"One can define the schedulers as","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"scheduler = DefaultScheduler(0.5) # fixed stepsize, default values: 1","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Then when constructing an EnsembleKalmanProcess, one uses the keyword argument","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"ekpobj = EKP.EnsembleKalmanProcess(args...; scheduler = scheduler, kwargs...)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"A variety of other schedulers can be defined similarly:","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"scheduler = MutableScheduler(2) # modifiable stepsize\nscheduler = EKSStableScheduler(numerator=10.0, nugget = 0.01) # Stable for EKS\nscheduler = DataMisfitController(on_terminate = \"continue\") # non-terminating","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Please see the learning rate schedulers API for defaults and other details","category":"page"},{"location":"learning_rate_scheduler/#Early-termination","page":"Learning rate schedulers","title":"Early termination","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Early termination can be implemented in the calibration loop as ","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"using EnsembleKalmanProcesses # for get_ϕ_final, update_ensemble!\n# given\n# * the number of iterations `N_iter`\n# * a prior `prior`\n# * a forward map `G`\n# * the EKP object `ekpobj`\n\nfor i in 1:N_iter\n params_i = get_ϕ_final(prior, ekpobj)\n g_ens = G(params_i)\n terminated = update_ensemble!(ekpobj, g_ens) # check for termination\n if !isnothing(terminated) # if termination is flagged, break the loop\n break\n end\nend ","category":"page"},{"location":"learning_rate_scheduler/#Timestep-and-termination-time","page":"Learning rate schedulers","title":"Timestep and termination time","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Recall, for example for EKI, we perform updates of our ensemble of parameters j=1dotsJ at step n = 1dotsN_mathrmit using","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"theta_n+1^(j) = theta_n^(j) - dfracDelta t_nJsum_k=1^J left langle mathcalG(theta_n^(k)) - barmathcalG_n Gamma_y^-1 left ( mathcalG(theta_n^(j)) - y right ) right rangle theta_n^(k)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"where barmathcalG_n is the mean value of mathcalG(theta_n) across ensemble members. We denote the current time t_n = sum_i=1^nDelta t_i, and the termination time as T = t_N_mathrmit.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"note: Note\nAdaptive Schedulers typically try to make the biggest update that controls some measure of this update. For example, EKSStableScheduler() controls the frobenius norm of the update, while DataMisfitController() controls the Jeffrey divergence between the two steps. Largely they follow a pattern of scheduling very small initial timesteps, leading to much larger steps at later times.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"There are two termination times that the theory indicates are useful","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"T=1: In the linear Gaussian case, the theta_N_mathrmit will represent the posterior distribution. In nonlinear case it should still provide an approximation to the posterior distribution. Note that as the posterior does not necessarily optimize the data-misfit we find bartheta_N_mathrmit (the ensemble mean) provides a conservative estimate of the true parameters, while retaining spread. It is noted in Iglesias & Yang 2021 that with small enough (or well chosen) step-sizes this estimate at T=1 satisfies a discrepancy principle with respect to the observational noise.\nTto infty: Though theoretical concerns have been made with respect to continuation beyond T=1 for inversion methods such as EKI, in practice we commonly see better optimization of the data-misfit, and thus better representation bartheta_N_mathrmit to the true parameters. As expected this procedure leads to ensemble collapse, and so no meaningful information can be taken from the posterior spread, and the optimizer is not likely to be the posterior mode.","category":"page"},{"location":"learning_rate_scheduler/#The-experiment-with-EKI-and-UKI","page":"Learning rate schedulers","title":"The experiment with EKI & UKI","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"We assess the schedulers by solving the inverse problem with EKI and UKI (we average results over 100 initial ensembles in the case of EKI). We will not draw comparisons between EKI and UKI here, rather we use them to observe consistent behavior in the schedulers. Shown below are the solution plots of one solve with each timestepper, for both methods. ","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"(Image: Solution EKI) (Image: Solution UKI)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Top: EKI, Bottom: UKI. Left: The true model over 02pi (black), and solution schedulers (colors). Right: The noisy observation (black) of mean and max of the model; the distribution it was sampled from (gray-ribbon), and the corresponding ensemble-mean approximation given from each scheduler (colors).","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"To assess the timestepping we show the convergence plot against the algorithm iteration we measure two quantities.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"error (solid) is defined by frac1N_enssum^N_ens_i=1 theta_i - theta^* ^2 where theta_i are ensemble members and theta^* is the true value used to create the observed data.\nspread (dashed) is defined by frac1N_enssum^N_ens_i=1 theta_i - bartheta ^2 where theta_i are ensemble members and bartheta is the mean over these members.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"(Image: Error vs spread EKI) (Image: Error vs spread UKI)","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Top: EKI. Bottom: UKI. Left: the error and spread of the different timesteppers at over iterations of the algorithm for a single run. Right: the error and spread of the different timesteppers at their final iterations, (for EKI, averaged from 100 initial conditions).","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Finding the Posterior (terminating at T=1):","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"DMC with termination (purple), closely mimics a small-fixed timestep (green) that finishes stepping at T=1. Both retain more spread than other approaches, and DMC is far more efficient, typically terminating after around 10-20 steps, where fixed-stepping takes 50. We see that (for this experiment) this is a conservative estimate, as continuing to solve (e.g. brown) until later times often leads to a better error while still retaining similar \"error vs spread\" curves (before inevitable collapse). This is consistent with the concept of approximating the posterior, over seeking an optimizer.\nThe behavior observed in UKI is similar to EKI","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Optimizing the objective function (continuing T to infty):","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"Large fixed step (orange). This is very efficient, but can get stuck when drawn too large, (perhaps unintuitive from a gradient-descent perspective). It typically also collapses the ensemble. On average it gives lower error to the true parameters than DMC. \nBoth EKSStable and DMC with continuation schedulers, perform very similarly. Both retain good ensemble spread during convergence, and collapse after finding a local optimum. This optimum on average has the best error to the true parameters in this experiment. They appear to consistently find the same optimum as Ttoinfty but DMC finds this in fewer iterations.\nThe UKI behavior is largely similar to EKI here, except that ensemble spread is retained in the Ttoinfty limit in all cases, from inflation of the parameter covariance (Sigma_omega) within our implementation. ","category":"page"},{"location":"learning_rate_scheduler/#DMC-as-a-default-in-future?","page":"Learning rate schedulers","title":"DMC as a default in future?","text":"","category":"section"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"This experiment motivates the possibility of making DMC (with/without) continuation a default timestepper in future releases, for EKI/SEKI/UKI. Currently we will retain constant timestepping as default while we investigate further.","category":"page"},{"location":"learning_rate_scheduler/","page":"Learning rate schedulers","title":"Learning rate schedulers","text":"warning: Ensemble Kalman Sampler\nWe observe blow-up in EKS, when not using the EKSStableScheduler.","category":"page"},{"location":"examples/darcy/#Learning-the-permiability-field-in-a-Darcy-flow","page":"Darcy flow","title":"Learning the permiability field in a Darcy flow","text":"","category":"section"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"In this example, we illustrate a simple function learning problem. We are presented with an unknown field that is discretized with a finite-dimensional approximation (e.g. spatial discretization). When learning this field, if one represents each pointwise value at a gridpoint as a parameter, increasing the spatial resolution leads to increasingly high dimensional learning problems, thus giving poor computational scaling and increasingly ill-posed inverse problems from fixed data. If instead, we treat the approximation as a discretized function living in a function space, then one can learn coefficients of a basis of this function space. Since it is commonly the case that functions have relatively low effective dimension in this space, the dependence on the spatial discretization only arises in discretization error, which vanishes as resolution is increased.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We will solve for an unknown permeability field kappa governing the pressure field of a Darcy flow on a square 2D domain. To learn about the permeability we shall take few pointwise measurements of the solved pressure field within the domain. The forward solver is a simple finite difference scheme taken and modified from code here.","category":"page"},{"location":"examples/darcy/#Walkthrough-of-the-code","page":"Darcy flow","title":"Walkthrough of the code","text":"","category":"section"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"First we load standard packages,","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"using LinearAlgebra\nusing Distributions\nusing Random\nusing JLD2","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"the package to define the function distributions,","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"import GaussianRandomFields # we wrap this so we don't want to use \"using\"\nconst GRF = GaussianRandomFields","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"and finally the EKP packages.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We include the forward solver here.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"include(\"GModel.jl\")","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We define the spatial domain and discretization,","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"rng = Random.MersenneTwister(seed)\ndim = 2\nN, L = 80, 1.0\npts_per_dim = LinRange(0, L, N)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"To provide a simple test case, we assume that the true function parameter is a particular sample from the function space we set up to define our prior. We choose a value of the truth that doesnt have a vanishingly small probability under the prior defined by a probability distribution over functions; taken to be a family of Gaussian Random Fields (GRF). This function distribution is characterized by a covariance function (Matern) and an appropriate representation (Karhunen-Loeve expansion). The representation is truncated to a finite number of coefficients, the degrees of freedom (dofs), which define the effective dimension of the learning problem that is decoupled from the spatial discretization. Larger dofs may be required to represent multiscale functions, but come at an increased dimension of the parameter space and therefore a typical increase in cost and difficulty of the learning problem. For more details see GaussianRandomFields.jl","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"smoothness = 2.0\ncorr_length = 0.5\ndofs = 50\n\ngrf = GRF.GaussianRandomField(\n GRF.CovarianceFunction(dim, GRF.Matern(smoothness, corr_length)),\n GRF.KarhunenLoeve(dofs),\n pts_per_dim,\n pts_per_dim,\n)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We define a wrapper around the GRF, and as the permeability field must be positive we introduce a domain constraint into the function distribution. ","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"pkg = GRFJL()\ndistribution = GaussianRandomFieldInterface(grf, pkg) # our wrapper from EKP\ndomain_constraint = bounded_below(0) # make κ positive\npd = ParameterDistribution(\n Dict(\"distribution\" => distribution, \"name\" => \"kappa\", \"constraint\" => domain_constraint),\n) # the fully constrained parameter distribution","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"Henceforth, the GRF is interfaced in the same manner as any other parameter distribution with regards to interface. We choose the true value by setting all degrees of freedom u_mathrmtrue = -15; this choice is arbitrary, upto not having a vanishingly small mass under the prior. We then use the EKP transform function to build the corresponding instance of the kappa_mathrmtrue.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"u_true = -1.5 * ones(dofs,1) # the truth parameter\nκ_true = transform_unconstrained_to_constrained(pd, u_true) # builds and constrains the function.\nκ_true = reshape(κ_true, N, N)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We generate the data sample for the truth in a perfect model setting by evaluating the the model here, and observing the pressure field at a few subsampled points in each dimension (here obs_ΔN, samples every 10 points in each dimension, leading to a 7 times 7 observation grid), and we assume 5% additive observational noise on the measurements.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"obs_ΔN = 10 \ndarcy = Setup_Param(pts_per_dim, obs_ΔN, κ_true) \nh_2d = solve_Darcy_2D(darcy, κ_true)\ny_noiseless = compute_obs(darcy, h_2d)\nobs_noise_cov = 0.05^2 * I(length(y_noiseless)) * (maximum(y_noiseless) - minimum(y_noiseless))\ntruth_sample = vec(y_noiseless + rand(rng, MvNormal(zeros(length(y_noiseless)), obs_noise_cov)))","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"Now we set up the Bayesian inversion algorithm. The prior we have already defined to construct our truth","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"prior = pd","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We define some algorithm parameters, here we take ensemble members larger than the dimension of the parameter space to ensure a full rank ensemble covariance.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"N_ens = dofs + 2 # number of ensemble members\nN_iter = 20 # number of EKI iterations","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We sample the initial ensemble from the prior, and create the EKP object as an EKI algorithm using the Inversion() keyword, we also use the DataMisfitController() learning rate scheduler","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"initial_params = construct_initial_ensemble(rng, prior, N_ens) \nekiobj = EKP.EnsembleKalmanProcess(initial_params, truth_sample, obs_noise_cov, Inversion(), scheduler=DataMisfitController())","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We perform the inversion loop. Remember that within calls to get_ϕ_final the EKP transformations are applied, thus the ensemble that is returned will be the positively-bounded permeability field evaluated at all the discretization points. Each ensemble member is stored as a column and therefore for uses such as plotting one needs to reshape to the desired dimension.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"err = zeros(N_iter)\nfor i in 1:N_iter\n params_i = get_ϕ_final(prior, ekiobj)\n g_ens = run_G_ensemble(darcy, params_i)\n EKP.update_ensemble!(ekiobj, g_ens)\nend","category":"page"},{"location":"examples/darcy/#Inversion-results","page":"Darcy flow","title":"Inversion results","text":"","category":"section"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We plot first the prior ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean. ","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"(Image: Darcy prior)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"Now we plot the final ensemble mean and pointwise variance of the permeability field, and also the pressure field solved with the ensemble mean.","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"(Image: Darcy final)","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"We can compare this with the true permeability and pressure field:","category":"page"},{"location":"examples/darcy/","page":"Darcy flow","title":"Darcy flow","text":"(Image: Darcy truth)","category":"page"},{"location":"glossary/#Glossary","page":"Glossary","title":"Glossary","text":"","category":"section"},{"location":"glossary/","page":"Glossary","title":"Glossary","text":"The following list includes the names and symbols of recurring concepts in EnsembleKalmanProcesses.jl. Some of these variables do not appear in the codebase, which relies on array programming for performance. Contributions to the codebase require following this notational convention. Similarly, if you find inconsistencies in the documentation or codebase, please report an issue on GitHub.","category":"page"},{"location":"glossary/","page":"Glossary","title":"Glossary","text":"Name Symbol (Theory/Docs) Symbol (Code)\nParameter vector, Parameters (unconstrained space) theta, u, mathcalT(phi) θ,u\nParameter vector, Parameters (physical / constrained space) phi, mathcalT^-1(theta) ϕ\nParameter vector size, Number of parameters p N_par\nEnsemble size J N_ens\nEnsemble particles, members theta^(j) \nNumber of iterations N_rm it N_iter\nObservation vector, Observations, Data vector y y\nObservation vector size, Data vector size d N_obs\nObservational noise eta obs_noise\nObservational noise covariance Gamma_y obs_noise_cov\nHilbert space inner product langle phi Gamma^-1 psi rangle \nForward map mathcalG G\nDynamical model Psi Ψ\nTransform map (constrained to unconstrained) mathcalT T\nObservation map mathcalH H\nPrior covariance (unconstrained space) Gamma_theta prior_cov\nPrior mean (unconstrained space) m_theta prior_mean","category":"page"},{"location":"API/Inversion/#Ensemble-Kalman-Inversion","page":"Inversion","title":"Ensemble Kalman Inversion","text":"","category":"section"},{"location":"API/Inversion/","page":"Inversion","title":"Inversion","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/Inversion/","page":"Inversion","title":"Inversion","text":"Inversion\neki_update","category":"page"},{"location":"API/Inversion/#EnsembleKalmanProcesses.Inversion","page":"Inversion","title":"EnsembleKalmanProcesses.Inversion","text":"Inversion <: Process\n\nAn ensemble Kalman Inversion process\n\n\n\n\n\n","category":"type"},{"location":"API/Inversion/#EnsembleKalmanProcesses.eki_update","page":"Inversion","title":"EnsembleKalmanProcesses.eki_update","text":" eki_update(\n ekp::EnsembleKalmanProcess{FT, IT, Inversion},\n u::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n y::AbstractMatrix{FT},\n obs_noise_cov::Union{AbstractMatrix{CT}, UniformScaling{CT}},\n) where {FT <: Real, IT, CT <: Real}\n\nReturns the updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (4) and (5) of Schillings and Stuart (2017).\n\nLocalization is implemented following the ekp.localizer.\n\n\n\n\n\n","category":"function"},{"location":"examples/lorenz_example/#Lorenz-example","page":"Lorenz","title":"Lorenz 96 example","text":"","category":"section"},{"location":"examples/lorenz_example/#Overview","page":"Lorenz","title":"Overview","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The Lorenz 96 (hereafter L96) example is a toy-problem for the application of the EnsembleKalmanProcesses.jl optimization and approximate uncertainty quantification methodologies. Here is L96 with additional periodic-in-time forcing, we try to determine parameters (sinusoidal amplitude and stationary component of the forcing) from some output statistics. The standard L96 equations are implemented with an additional forcing term with time dependence. The output statistics which are used for learning are the finite time-averaged variances.","category":"page"},{"location":"examples/lorenz_example/#Lorenz-96-equations","page":"Lorenz","title":"Lorenz 96 equations","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The standard single-scale L96 equations are implemented. The Lorenz 96 system (Lorenz, 1996) is given by ","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"fracd x_id t = (x_i+1 - x_i-2) x_i-1 - x_i + F","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"with i indicating the index of the given longitude. The number of longitudes is given by N. The boundary conditions are given by","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"x_-1 = x_N-1 x_0 = x_N x_N+1 = x_1","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The time scaling is such that the characteristic time is 5 days (Lorenz, 1996). For very small values of F, the solutions x_i decay to F after the initial transient feature. For moderate values of F, the solutions are periodic, and for larger values of F, the system is chaotic. The solution variance is a function of the forcing magnitude. Variations in the base state as a function of time can be imposed through a time-dependent forcing term F(t).","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"A temporal forcing term is defined","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"F = F_s + A sin(omega t)","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"with steady-state forcing F_s, transient forcing amplitude A, and transient forcing frequency omega. The total forcing F must be within the chaotic regime of L96 for all time given the prescribed N.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The L96 dynamics are solved with RK4 integration.","category":"page"},{"location":"examples/lorenz_example/#Structure","page":"Lorenz","title":"Structure","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The main code is located in Lorenz_example.jl which provides the functionality to run the L96 dynamical system, extract time-averaged statistics from the L96 states, and use the time-average statistics for optimization and uncertainty quantification.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The L96 system is solved in GModel.jl according to the time integration settings specified in LSettings and the L96 parameters specified in LParams. The types of statistics to be collected are detailed in GModel.jl.","category":"page"},{"location":"examples/lorenz_example/#Lorenz-dynamics-inputs","page":"Lorenz","title":"Lorenz dynamics inputs","text":"","category":"section"},{"location":"examples/lorenz_example/#Dynamics-settings","page":"Lorenz","title":"Dynamics settings","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The use of the transient forcing term is with the flag, dynamics. Stationary forcing is dynamics=1 (A=0) and transient forcing is used with dynamics=2 (Aneq0). The default parameters are specified in Lorenz_example.jl and can be modified as necessary. The system is solved over time horizon 0 to tend at fixed time step dt.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"N = 36\ndt = 1/64\nt_start = 800","category":"page"},{"location":"examples/lorenz_example/#Inverse-problem-settings","page":"Lorenz","title":"Inverse problem settings","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The states are integrated over time Ts_days to construct the time averaged statistics for use by the optimization. The specification of the statistics to be gathered from the states are provided by stats_type. The Ensemble Kalman Process (EKP) settings are","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"N_ens = 20 # number of ensemble members\nN_iter = 5 # number of EKI iterations","category":"page"},{"location":"examples/lorenz_example/#Setting-up-the-Inverse-Problem","page":"Lorenz","title":"Setting up the Inverse Problem","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The goal is to learn F_s and A based on the time averaged statistics in a perfect model setting. The true parameters are","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"F_true = 8. # Mean F\nA_true = 2.5 # Transient F amplitude\nω_true = 2. * π / (360. / τc) # Frequency of the transient F\nparams_true = [F_true, A_true]\nparam_names = [\"F\", \"A\"]","category":"page"},{"location":"examples/lorenz_example/#Priors","page":"Lorenz","title":"Priors","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"We implement (biased) priors as follows","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"prior_means = [F_true + 1.0, A_true + 0.5]\nprior_stds = [2.0, 0.5 * A_true]\n# constrained_gaussian(\"name\", desired_mean, desired_std, lower_bd, upper_bd)\nprior_F = constrained_gaussian(param_names[1], prior_means[1], prior_stds[1], 0, Inf)\nprior_A = constrained_gaussian(param_names[2], prior_means[2], prior_stds[2], 0, Inf)\npriors = combine_distributions([prior_F, prior_A])","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"We use the recommended constrained_gaussian to add the desired scale and bounds to the prior distribution, in particular we place lower bounds to preserve positivity. ","category":"page"},{"location":"examples/lorenz_example/#Observational-Noise","page":"Lorenz","title":"Observational Noise","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The observational noise can be generated using the L96 system or prescribed, as specified by var_prescribe. ","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"var_prescribe==false The observational noise is constructed by generating independent instantiations of the L96 statistics of interest at the true parameters for different initial conditions. The empirical covariance matrix is constructed.","category":"page"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"var_prescribe==true The observational noise is prescribed as a Gaussian distribution with prescribed mean and variance.","category":"page"},{"location":"examples/lorenz_example/#Running-the-Example","page":"Lorenz","title":"Running the Example","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The L96 parameter estimation can be run using julia --project Lorenz_example.jl","category":"page"},{"location":"examples/lorenz_example/#Solution-and-Output","page":"Lorenz","title":"Solution and Output","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The output will provide the estimated parameters in the constrained ϕ-space. The priors are required in the get-method to apply these constraints.","category":"page"},{"location":"examples/lorenz_example/#Printed-output","page":"Lorenz","title":"Printed output","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"# EKI results: Has the ensemble collapsed toward the truth?\nprintln(\"True parameters: \")\nprintln(params_true)\nprintln(\"\\nEKI results:\")\nprintln(get_ϕ_mean_final(priors, ekiobj))","category":"page"},{"location":"examples/lorenz_example/#Saved-output","page":"Lorenz","title":"Saved output","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"The parameters and forward model outputs will be saved in parameter_storage.jld2 and data_storage.jld2, respectively. The data will be saved in the directory output.","category":"page"},{"location":"examples/lorenz_example/#Plots","page":"Lorenz","title":"Plots","text":"","category":"section"},{"location":"examples/lorenz_example/","page":"Lorenz","title":"Lorenz","text":"A scatter plot animation of the ensemble convergence to the true parameters is saved in the directory output.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"EditURL = \"../../../examples/Sinusoid/sinusoid_example.jl\"","category":"page"},{"location":"literated/sinusoid_example/#sinusoid-example","page":"Simple example","title":"Fitting parameters of a sinusoid","text":"","category":"section"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"In this example we have a model that produces a sinusoid f(A v) = A sin(phi + t) + v forall t in 02pi, with a random phase phi. Given an initial guess of the parameters as A^* sim mathcalN(21) and v^* sim mathcalN(025), our goal is to estimate the parameters from a noisy observation of the maximum, minimum, and mean of the true model output.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"First, we load the packages we need:","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"using LinearAlgebra, Random\n\nusing Distributions, Plots\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses\nnothing # hide\n\n# Setting up the model and data for our inverse problem","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Now, we define a model which generates a sinusoid given parameters theta: an amplitude and a vertical shift. We will estimate these parameters from data. The model adds a random phase shift upon evaluation.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"dt = 0.01\ntrange = 0:dt:(2 * pi + dt)\nfunction model(amplitude, vert_shift)\n phi = 2 * pi * rand(rng)\n return amplitude * sin.(trange .+ phi) .+ vert_shift\nend\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Seed for pseudo-random number generator.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"rng_seed = 41\nrng = Random.MersenneTwister(rng_seed)\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We then define G(theta), which returns the observables of the sinusoid given a parameter vector. These observables should be defined such that they are informative about the parameters we wish to estimate. Here, the two observables are the y range of the curve (which is informative about its amplitude), as well as its mean (which is informative about its vertical shift).","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"function G(u)\n theta, vert_shift = u\n sincurve = model(theta, vert_shift)\n return [maximum(sincurve) - minimum(sincurve), mean(sincurve)]\nend\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Suppose we have a noisy observation of the true system. Here, we create a pseudo-observation y by running our model with the correct parameters and adding Gaussian noise to the output.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"dim_output = 2\n\nΓ = 0.1 * I\nnoise_dist = MvNormal(zeros(dim_output), Γ)\n\ntheta_true = [1.0, 7.0]\ny = G(theta_true) .+ rand(noise_dist)\nnothing # hide\n\n# Solving the inverse problem","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We now define prior distributions on the two parameters. For the amplitude, we define a prior with mean 2 and standard deviation 1. It is additionally constrained to be nonnegative. For the vertical shift we define a Gaussian prior with mean 0 and standard deviation 5.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"prior_u1 = constrained_gaussian(\"amplitude\", 2, 1, 0, Inf)\nprior_u2 = constrained_gaussian(\"vert_shift\", 0, 5, -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We now generate the initial ensemble and set up the ensemble Kalman inversion.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"N_ensemble = 5\nN_iterations = 5\n\ninitial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)\n\nensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, y, Γ, Inversion(); rng = rng)\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We are now ready to carry out the inversion. At each iteration, we get the ensemble from the last iteration, apply G(theta) to each ensemble member, and apply the Kalman update to the ensemble.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"for i in 1:N_iterations\n params_i = get_ϕ_final(prior, ensemble_kalman_process)\n\n G_ens = hcat([G(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, G_ens)\nend\nnothing # hide","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"Finally, we get the ensemble after the last iteration. This provides our estimate of the parameters.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"final_ensemble = get_ϕ_final(prior, ensemble_kalman_process)","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"To visualize the success of the inversion, we plot model with the true parameters, the initial ensemble, and the final ensemble.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"plot(trange, model(theta_true...), c = :black, label = \"Truth\", legend = :bottomright, linewidth = 2)\nplot!(\n trange,\n [model(get_ϕ(prior, ensemble_kalman_process, 1)[:, i]...) for i in 1:N_ensemble],\n c = :red,\n label = [\"Initial ensemble\" \"\" \"\" \"\" \"\"],\n)\nplot!(trange, [model(final_ensemble[:, i]...) for i in 1:N_ensemble], c = :blue, label = [\"Final ensemble\" \"\" \"\" \"\" \"\"])\n\nxlabel!(\"Time\")","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"We see that the final ensemble is much closer to the truth. Note that the random phase shift is of no consequence.","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"","category":"page"},{"location":"literated/sinusoid_example/","page":"Simple example","title":"Simple example","text":"This page was generated using Literate.jl.","category":"page"},{"location":"examples/template_example/#Template-example","page":"Template","title":"Template example","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"We provide the following template for how the tools may be applied.","category":"page"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"For small examples typically have 2 files.","category":"page"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"DynamicalModel.jl Contains the dynamical model Psi and the observation map mathcalH. The inputs should be the so-called free parameters (in the constrained/physical space that is the input domain of the dynamical model) we are interested in learning, and the output should be the measured data.\nThe example script which contains the inverse problem setup and solve","category":"page"},{"location":"examples/template_example/#The-structure-of-the-example-script","page":"Template","title":"The structure of the example script","text":"","category":"section"},{"location":"examples/template_example/#Create-the-data-and-the-setting-for-the-model","page":"Template","title":"Create the data and the setting for the model","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Set up the forward model.\nConstruct/load the truth data. ","category":"page"},{"location":"examples/template_example/#Set-up-the-inverse-problem","page":"Template","title":"Set up the inverse problem","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Define the prior distributions, and generate an initial ensemble.\nInitialize the process tool you would like to use (we recommend you begin with Inversion()). \ninitialize the EnsembleKalmanProcess object","category":"page"},{"location":"examples/template_example/#Solve-the-inverse-problem,-in-a-loop","page":"Template","title":"Solve the inverse problem, in a loop","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Obtain the current parameter ensemble\nTransform them from the unbounded computational space to the physical space\ncall the forward model on the ensemble of parameters, producing an ensemble of measured data\ncall the update_ensemble! function to generate a new parameter ensemble based on the new data","category":"page"},{"location":"examples/template_example/#Get-the-solution","page":"Template","title":"Get the solution","text":"","category":"section"},{"location":"examples/template_example/","page":"Template","title":"Template","text":"Obtain the final parameter ensemble, compute desired statistics here.\nTransform the final ensemble into the physical space for use in prediction studies with the forward model.","category":"page"},{"location":"localization/#Localization-and-Sampling-Error-Correction-(SEC)","page":"Localization and SEC","title":"Localization and Sampling Error Correction (SEC)","text":"","category":"section"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"Ensemble Kalman inversion (EKI) seeks to find an optimal parameter vector theta in mathbbR^p by minimizing the mismatch between some data y in mathbbR^d and the forward model output mathcalG(theta) in mathbbR^d. Instead of relying on derivatives of the map mathcalG with respect to theta to find the optimum, EKI leverages sample covariances mathrmCov(theta mathcalG) and mathrmCov(mathcalG mathcalG) diagnosed from an ensemble of J particles,","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":" tag1\n beginaligned\n mathrmCov(theta mathcalG) = dfrac1Jsum_j=1^J\n (theta^(j) - m)(mathcalG(theta^(j)) - barmathcalG)^T \n\n mathrmCov(mathcalG mathcalG) = dfrac1Jsum_j=1^J\n (mathcalG(theta^(j)) - barmathcalG)(mathcalG(theta^(j)) - barmathcalG)^T \n endaligned","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"where m and barmathcalG are the ensemble averages of theta and mathcalG(theta), respectively.","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"For models with just a few (p) parameters, we can typically afford to use J p ensemble members, such that the sample covariance mathrmCov(theta mathcalG) is full rank. Using more ensemble members than the number of model parameters, EKI can in theory probe all dimensions of parameter space to find the optimum parameter vector.","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"For models with a lot of parameters (e.g., a deep neural network), computational constraints limit the size of the ensemble to J p or even J ll p members. Due to the characteristics of the EKI update equation, this means that the method can only find the minimum in the (J-1)-dimensional space spanned by the initial ensemble, leaving p-J+1 dimensions unexplored. This is known as the subspace property of EKI. As the dimensional gap p-J increases, we can expect the solution of the algorithm to deteriorate.","category":"page"},{"location":"localization/#Enter-Localization","page":"Localization and SEC","title":"Enter Localization","text":"","category":"section"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"In algebraic terms, the extent to which we can explore the dimensions of parameter space is roughly given by the rank of the matrices in equation (1). In the case J p, the rank of mathrmCov(theta mathcalG) is limited to mathrmmin(d J-1). It has been shown that the performance of ensemble Kalman methods with J p can be greatly improved by boosting this rank through an elementwise product with a suitable localization kernel Lambda,","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"tag2 mathrmrank(mathrmCov(theta mathcalG) odot Lambda) geq mathrmrank(mathrmCov(theta mathcalG))","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"Substituting the covariance mathrmCov(theta mathcalG) by the boosted version defined in the left-hand side of equation (2), EKI is able to break the subspace property and explore additional dimensions in parameter space. Localization is an empirical way of correcting for the sampling error due to a small ensemble size, and so it can also be interpreted as a sampling error correction (SEC) method.","category":"page"},{"location":"localization/#Localization-in-EnsembleKalmanProcesses","page":"Localization and SEC","title":"Localization in EnsembleKalmanProcesses","text":"","category":"section"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"A wide variety of localization kernels are available in EnsembleKalmanProcesses.jl under the module Localizers. The optimal localization kernel will depend on the structure of the problem at hand, so the user is encouraged to try different kernels and review their references in the literature.","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"In practice, the localization method is chosen at EnsembleKalmanProcess construction time,","category":"page"},{"location":"localization/","page":"Localization and SEC","title":"Localization and SEC","text":"using Distributions\nusing LinearAlgebra\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nusing EnsembleKalmanProcesses.Localizers\nconst EKP = EnsembleKalmanProcesses\n\np = 10; d = 20; J = 6\n\n# Construct initial ensemble\npriors = ParameterDistribution[]\nfor i in 1:p\n push!(priors, ParameterDistribution(Parameterized(Normal(0.0, 0.5)), no_constraint(), string(\"u\", i)))\nend\nprior = combine_distributions(priors)\ninitial_ensemble = EKP.construct_initial_ensemble(prior, J)\n\ny = 10.0 * rand(d)\nΓ = 1.0 * I\n\n# Construct EKP object with localization. Some examples of localization methods:\nlocs = [Delta(), RBF(1.0), RBF(0.1), BernoulliDropout(0.1), SEC(10.0), SECFisher(), SEC(1.0, 0.1)]\nfor loc in locs\n ekiobj = EKP.EnsembleKalmanProcess(initial_ensemble, y, Γ, Inversion(); localization_method = loc)\nend","category":"page"},{"location":"ensemble_kalman_inversion/#Ensemble-Kalman-Inversion","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"One of the ensemble Kalman processes implemented in EnsembleKalmanProcesses.jl is the ensemble Kalman inversion (Iglesias et al, 2013). The ensemble Kalman inversion (EKI) is a derivative-free ensemble optimization method that seeks to find the optimal parameters theta in mathbbR^p in the inverse problem defined by the data-model relation","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"tag1 y = mathcalG(theta) + eta ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where mathcalG denotes the forward map, y in mathbbR^d is the vector of observations and eta in mathbbR^d is additive noise. Note that p is the size of the parameter vector theta and d the size of the observation vector y. Here, we take eta sim mathcalN(0 Gamma_y) from a d-dimensional Gaussian with zero mean and covariance matrix Gamma_y. This noise structure aims to represent the correlations between observations.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The optimal parameters theta^* in mathbbR^p given relation (1) minimize the loss","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"mathcalL(theta y) = langle mathcalG(theta) - y Gamma_y^-1 left ( mathcalG(theta) - y right ) rangle","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"which can be interpreted as the negative log-likelihood given a Gaussian likelihood.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Denoting the parameter vector of the j-th ensemble member at the n-th iteration as theta^(j)_n, its update equation from n to n+1 under EKI is","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"tag2 theta_n+1^(j) = theta_n^(j) - dfracDelta t_nJsum_k=1^J left langle mathcalG(theta_n^(k)) - barmathcalG_n Gamma_y^-1 left ( mathcalG(theta_n^(j)) - y right ) right rangle theta_n^(k) ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where the subscript n=1 dots N_rm it indicates the iteration, J is the number of members in the ensemble, barmathcalG_n is the mean value of mathcalG(theta_n) across ensemble members,","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"barmathcalG_n = dfrac1Jsum_k=1^JmathcalG(theta_n^(k)) ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"and angle brackets denote the Euclidean inner product. By multiplying with Gamma_y^-1 we render the inner product non-dimensional.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The EKI algorithm is considered converged when the ensemble achieves sufficient consensus/collapse in parameter space. The final estimate bartheta_N_rm it is taken to be the ensemble mean at the final iteration,","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"bartheta_N_rm it = dfrac1Jsum_k=1^Jtheta_N_rm it^(k)","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"For typical applications, a near-optimal solution theta can be found after as few as 10 iterations of the algorithm, or 10cdot J evaluations of the forward model mathcalG. The basic algorithm requires J geq p, and better performance is often seen with larger ensembles; a good rule of thumb is to start with J=10p. The algorithm also extends to J p , using localizers to maintain performance in these situations (see the Localizers.jl module).","category":"page"},{"location":"ensemble_kalman_inversion/#Constructing-the-Forward-Map","page":"Ensemble Kalman Inversion","title":"Constructing the Forward Map","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The forward map mathcalG maps the space of unconstrained parameters theta in mathbbR^p to the space of outputs y in mathbbR^d. In practice, the user may not have access to such a map directly. Consider a situation where the goal is to learn a set of parameters phi of a dynamical model Psi mathbbR^p rightarrow mathbbR^o, given observations y in mathbbR^d and a set of constraints on the value of phi. Then, the forward map may be constructed as","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"mathcalG = mathcalH circ Psi circ mathcalT^-1","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where mathcalH mathbbR^o rightarrow mathbbR^d is the observation map and mathcalT is the transformation map from constrained to unconstrained parameter spaces, such that mathcalT(phi) = theta. A family of standard transformation maps and their inverse are available in the ParameterDistributions module.","category":"page"},{"location":"ensemble_kalman_inversion/#Creating-the-EKI-Object","page":"Ensemble Kalman Inversion","title":"Creating the EKI Object","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"An ensemble Kalman inversion object can be created using the EnsembleKalmanProcess constructor by specifying the Inversion() process type.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Creating an ensemble Kalman inversion object requires as arguments:","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"An initial parameter ensemble, Array{Float, 2} of size [p × J];\nThe mean value of the observed outputs, a vector of size [d];\nThe covariance of the observational noise, a matrix of size [d × d];\nThe Inversion() process type.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A typical initialization of the Inversion() process takes a user-defined prior, a summary of the observation statistics given by the mean y and covariance obs_noise_cov, and a desired number of members in the ensemble,","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\nJ = 50 # number of ensemble members\ninitial_ensemble = construct_initial_ensemble(prior, J) # Initialize ensemble from prior\n\nekiobj = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, Inversion())","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"See the Prior distributions section to learn about the construction of priors in EnsembleKalmanProcesses.jl. The prior is assumed to be over the unconstrained parameter space where theta is defined. For applications where enforcing parameter bounds is necessary, the ParameterDistributions module provides functions to map from constrained to unconstrained space and vice versa. ","category":"page"},{"location":"ensemble_kalman_inversion/#Updating-the-Ensemble","page":"Ensemble Kalman Inversion","title":"Updating the Ensemble","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Once the ensemble Kalman inversion object ekiobj has been initialized, any number of updates can be performed using the inversion algorithm.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A call to the inversion algorithm can be performed with the update_ensemble! function. This function takes as arguments the ekiobj and the evaluations of the forward map at each member of the current ensemble. The update_ensemble! function then stores the new updated ensemble and the inputted forward map evaluations in ekiobj. ","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A typical use of the update_ensemble! function given the ensemble Kalman inversion object ekiobj, the dynamical model Ψ and the observation map H is","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"# Given:\n# Ψ (some black box simulator)\n# H (some observation of the simulator output)\n# prior (prior distribution and parameter constraints)\n\nN_iter = 20 # Number of steps of the algorithm\n\nfor n in 1:N_iter\n ϕ_n = get_ϕ_final(prior, ekiobj) # Get current ensemble in constrained \"ϕ\"-space\n G_n = [H(Ψ(ϕ_n[:, i])) for i in 1:J]\n g_ens = hcat(G_n...) # Evaluate forward map \n update_ensemble!(ekiobj, g_ens) # Update ensemble\nend","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"In the previous update, note that the parameters stored in ekiobj are given in the unconstrained Gaussian space where the EKI algorithm is performed. The map mathcalT^-1 between this unconstrained space and the (possibly constrained) physical space of parameters is encoded in the prior object. The dynamical model Ψ accepts as inputs the parameters in (possibly constrained) physical space, so it is necessary to use the getter get_ϕ_final which applies transform_unconstrained_to_constrained to the ensemble. See the Prior distributions section for more details on parameter transformations. ","category":"page"},{"location":"ensemble_kalman_inversion/#Solution","page":"Ensemble Kalman Inversion","title":"Solution","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The EKI algorithm drives the initial ensemble, sampled from the prior, towards the support region of the posterior distribution. The algorithm also drives the ensemble members towards consensus. The optimal parameter θ_optim found by the algorithm is given by the mean of the last ensemble (i.e., the ensemble after the last iteration),","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"θ_optim = get_u_mean_final(ekiobj) # optimal parameter","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"To obtain the optimal value in the constrained space, we use the getter with the constrained prior as input","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"ϕ_optim = get_ϕ_mean_final(prior, ekiobj) # the optimal physical parameter value","category":"page"},{"location":"ensemble_kalman_inversion/#Handling-forward-model-failures","page":"Ensemble Kalman Inversion","title":"Handling forward model failures","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"In situations where the forward model mathcalG represents a diagnostic of a complex computational model, there might be cases where for some parameter combinations theta, attempting to evaluate mathcalG(theta) may result in model failure (defined as returning a NaN from the point of view of this package). In such cases, the EKI update equation (2) must be modified to handle model failures.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"EnsembleKalmanProcesses.jl implements such modifications through the FailureHandler structure, an input to the EnsembleKalmanProcess constructor. Currently, the only failsafe modification available is SampleSuccGauss(), described in Lopez-Gomez et al (2022).","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"To employ this modification, construct the EKI object as","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\nJ = 50 # number of ensemble members\ninitial_ensemble = construct_initial_ensemble(prior, J) # Initialize ensemble from prior\n\nekiobj = EnsembleKalmanProcess(\n initial_ensemble,\n y,\n obs_noise_cov,\n Inversion(),\n failure_handler_method = SampleSuccGauss())","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"info: Forward model requirements when using FailureHandlers\nThe user must determine if a model run has \"failed\", and replace the output mathcalG(theta) with NaN. The FailureHandler takes care of the rest.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"A description of the algorithmic modification is included below.","category":"page"},{"location":"ensemble_kalman_inversion/#SampleSuccGauss()","page":"Ensemble Kalman Inversion","title":"SampleSuccGauss()","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"The SampleSuccGauss() modification is based on updating all ensemble members with a distribution given by only the successful parameter ensemble. Let Theta_sn= theta^(1)_sndotstheta^(J_s)_sn be the successful ensemble, for which each evaluation mathcalG(theta^(j)_sn) does not fail, and let theta_fn^(k) be the ensemble members for which the evaluation mathcalG(theta^(k)_fn) fails. The successful ensemble Theta_sn is updated to Theta_sn+1 using expression (2), and each failed ensemble member as","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":" theta_fn+1^(k) sim mathcalN left(m_s n+1 Sigma_s n+1 right)","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"where","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":" m_s n+1 = dfrac1J_ssum_j=1^J_s theta_sn+1^(j) qquad Sigma_s n+1 = mathrmCov(theta_s n+1 theta_s n+1) + kappa_*^-1mu_s1I_p","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"Here, kappa_* is a limiting condition number, mu_s1 is the largest eigenvalue of the sample covariance mathrmCov(theta_s n+1 theta_s n+1) and I_p is the identity matrix of size ptimes p.","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"warning: Warning\nThis modification is not a magic bullet. If large fractions of ensemble members fail during an iteration, this will degenerate the span of the ensemble.","category":"page"},{"location":"ensemble_kalman_inversion/#Sparsity-Inducing-Ensemble-Kalman-Inversion","page":"Ensemble Kalman Inversion","title":"Sparsity-Inducing Ensemble Kalman Inversion","text":"","category":"section"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"We include Sparsity-inducing Ensemble Kalman Inversion (SEKI) to add approximate L^0 and L^1 penalization to the EKI (Schneider, Stuart, Wu, 2020).","category":"page"},{"location":"ensemble_kalman_inversion/","page":"Ensemble Kalman Inversion","title":"Ensemble Kalman Inversion","text":"warning: Warning\nThe algorithm suffers from robustness issues, and therefore we urge caution in using the tool","category":"page"},{"location":"API/Localizers/#Localizers","page":"Localizers","title":"Localizers","text":"","category":"section"},{"location":"API/Localizers/","page":"Localizers","title":"Localizers","text":"CurrentModule = EnsembleKalmanProcesses.Localizers","category":"page"},{"location":"API/Localizers/","page":"Localizers","title":"Localizers","text":"Localizer\nRBF\nBernoulliDropout\nSEC\nSECFisher\nDelta\nNoLocalization","category":"page"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.Localizer","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.Localizer","text":"Localizer{LM <: LocalizationMethod, T}\n\nStructure that defines a localize function, based on a localization method.\n\nFields\n\nlocalize::Function\nLocalizing function of the form: cov -> kernel .* cov\n\nConstructors\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:122.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:128.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:134.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:179.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:199.\n\nLocalizer(localization, p, d, J)\nLocalizer(localization, p, d, J, T)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/Localizers.jl:238.\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.RBF","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.RBF","text":"RBF{FT <: Real} <: LocalizationMethod\n\nRadial basis function localization method. Covariance terms C_ij are damped through multiplication with a centered Gaussian with standardized deviation d(ij)= vert i-j vert l.\n\nFields\n\nlengthscale::Real\nLength scale defining the RBF kernel\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.BernoulliDropout","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.BernoulliDropout","text":"BernoulliDropout{FT <: Real} <: LocalizationMethod\n\nLocalization method that drops cross-covariance terms with probability 1-p, retaining a Hermitian structure.\n\nFields\n\nprob::Real\nProbability of keeping a given cross-covariance term\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.SEC","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.SEC","text":"SEC{FT <: Real} <: LocalizationMethod\n\nSampling error correction that shrinks correlations by a factor of vert r vert ^alpha, as per Lee (2021). Sparsity of the resulting correlations can be imposed through the parameter r_0.\n\nLee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341\n\nFields\n\nα::Real\nControls degree of sampling error correction\nr_0::Real\nCutoff correlation\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.SECFisher","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.SECFisher","text":"SECFisher <: LocalizationMethod\n\nSampling error correction for EKI, as per Lee (2021), but using the method from Flowerdew (2015) based on the Fisher transformation. Correlations are shrinked by a factor determined by the sample correlation and the ensemble size. \n\nFlowerdew, J. (2015). Towards a theory of optimal localisation. Tellus A: Dynamic Meteorology and Oceanography, 67(1), 25257. https://doi.org/10.3402/tellusa.v67.25257\n\nLee, Y. (2021). Sampling error correction in ensemble Kalman inversion. arXiv:2105.11341 [cs, math]. http://arxiv.org/abs/2105.11341\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.Delta","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.Delta","text":"Dirac delta localization method, with an identity matrix as the kernel.\n\n\n\n\n\n","category":"type"},{"location":"API/Localizers/#EnsembleKalmanProcesses.Localizers.NoLocalization","page":"Localizers","title":"EnsembleKalmanProcesses.Localizers.NoLocalization","text":"Idempotent localization method.\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#ParameterDistributions","page":"ParameterDistributions","title":"ParameterDistributions","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"CurrentModule = EnsembleKalmanProcesses.ParameterDistributions","category":"page"},{"location":"API/ParameterDistributions/#ParameterDistributionTypes","page":"ParameterDistributions","title":"ParameterDistributionTypes","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"Parameterized\nSamples\nVectorOfParameterized","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.Parameterized","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.Parameterized","text":"Parameterized <: ParameterDistributionType\n\nA distribution constructed from a parameterized formula (e.g Julia Distributions.jl)\n\nFields\n\ndistribution::Distributions.Distribution\nA parameterized distribution\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.Samples","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.Samples","text":"Samples{FT <: Real} <: ParameterDistributionType\n\nA distribution comprised of only samples, stored as columns of parameters.\n\nFields\n\ndistribution_samples::AbstractMatrix{FT} where FT<:Real\nSamples defining an empirical distribution, stored as columns\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.VectorOfParameterized","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.VectorOfParameterized","text":"VectorOfParameterized <: ParameterDistributionType\n\nA distribution built from an array of Parametrized distributions. A utility to help stacking of distributions where a multivariate equivalent doesn't exist.\n\nFields\n\ndistribution::AbstractVector{DT} where DT<:Distributions.Distribution\nA vector of parameterized distributions\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#Constraints","page":"ParameterDistributions","title":"Constraints","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"Constraint\nno_constraint\nbounded_below\nbounded_above\nbounded\nlength(c::CType) where {CType <: ConstraintType}\nsize(c::CType) where {CType <: ConstraintType}","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.Constraint","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.Constraint","text":"Constraint{T} <: ConstraintType\n\nClass describing a 1D bijection between constrained and unconstrained spaces. Included parametric types for T:\n\nNoConstraint\nBoundedBelow\nBoundedAbove\nBounded\n\nFields\n\nconstrained_to_unconstrained::Function\nA map from constrained domain -> (-Inf,Inf)\nc_to_u_jacobian::Function\nThe jacobian of the map from constrained domain -> (-Inf,Inf)\nunconstrained_to_constrained::Function\nMap from (-Inf,Inf) -> constrained domain\nbounds::Union{Nothing, Dict}\nDictionary of values used to build the Constraint (e.g. \"lowerbound\" or \"upperbound\")\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.no_constraint","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.no_constraint","text":"no_constraint()\n\nConstructs a Constraint with no constraints, enforced by maps x -> x and x -> x.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.bounded_below","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.bounded_below","text":"bounded_below(lower_bound::FT) where {FT <: Real}\n\nConstructs a Constraint with provided lower bound, enforced by maps x -> log(x - lower_bound) and x -> exp(x) + lower_bound.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.bounded_above","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.bounded_above","text":"bounded_above(upper_bound::FT) where {FT <: Real}\n\nConstructs a Constraint with provided upper bound, enforced by maps x -> log(upper_bound - x) and x -> upper_bound - exp(x).\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.bounded","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.bounded","text":"bounded(lower_bound::Real, upper_bound::Real)\n\nConstructs a Constraint with provided upper and lower bounds, enforced by maps x -> log((x - lower_bound) / (upper_bound - x)) and x -> (upper_bound * exp(x) + lower_bound) / (exp(x) + 1).\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Base.length-Tuple{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType","page":"ParameterDistributions","title":"Base.length","text":"length(c<:ConstraintType)\n\nA constraint has length 1. \n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#Base.size-Tuple{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType","page":"ParameterDistributions","title":"Base.size","text":"size(c<:ConstraintType)\n\nA constraint has size 1.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#ParameterDistributions-2","page":"ParameterDistributions","title":"ParameterDistributions","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"ParameterDistribution\nconstrained_gaussian\nn_samples\nget_name\nget_dimensions\nget_n_samples\nget_all_constraints(::ParameterDistribution)\nget_constraint_type\nget_bounds\nbatch\nget_distribution\nsample\nlogpdf\nmean\nvar\ncov\ntransform_constrained_to_unconstrained(::ParameterDistribution, ::AbstractVector)\ntransform_constrained_to_unconstrained(::ParameterDistribution, ::AbstractMatrix)\ntransform_constrained_to_unconstrained(::ParameterDistribution, ::Dict)\ntransform_unconstrained_to_constrained(::ParameterDistribution, ::AbstractVector)\ntransform_unconstrained_to_constrained(::ParameterDistribution, ::AbstractMatrix)\ntransform_unconstrained_to_constrained(::ParameterDistribution, ::Dict)","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution","text":"ParameterDistribution\n\nStructure to hold a parameter distribution, always stored as an array of distributions internally.\n\nFields\n\ndistribution::AbstractVector{PDType} where PDType<:EnsembleKalmanProcesses.ParameterDistributions.ParameterDistributionType\nVector of parameter distributions, defined in unconstrained space\nconstraint::AbstractVector{CType} where CType<:EnsembleKalmanProcesses.ParameterDistributions.ConstraintType\nVector of constraints defining transformations between constrained and unconstrained space\nname::AbstractVector{ST} where ST<:AbstractString\nVector of parameter names\n\nConstructors\n\nParameterDistribution(distribution, constraint, name)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:289.\n\nParameterDistribution(param_dist_dict)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:305.\n\nParameterDistribution(distribution, constraint, name)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:389.\n\nParameterDistribution(distribution_samples, constraint, name)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/ParameterDistributions.jl:431.\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.constrained_gaussian","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.constrained_gaussian","text":"constrained_gaussian(\n name::AbstractString,\n μ_c::Real,\n σ_c::Real,\n lower_bound::Real,\n upper_bound::Real;\n repeats = 1,\n optim_algorithm::Optim.AbstractOptimizer = NelderMead(),\n optim_kwargs...,\n)\n\nConstructor for a 1D ParameterDistribution consisting of a transformed Gaussian, constrained to have support on [lower_bound, upper_bound], with first two moments μ_c and σ_c^2. The moment integrals can't be done in closed form, so we set the parameters of the distribution with numerical optimization.\n\nnote: Note\nThe intended use case is defining priors set from user expertise for use in inference with adequate data, so for the sake of performance we only require that the optimization reproduce μ_c, σ_c to a loose tolerance (1e-5). Warnings are logged when the optimization fails.\n\nnote: Note\nThe distribution may be bimodal for σ_c large relative to the width of the bound interval. In extreme cases the distribution becomes concentrated at the bound endpoints. We regard this as a feature, not a bug, and do not warn the user when bimodality occurs.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.n_samples","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.n_samples","text":"n_samples(d<:Samples)\n\nThe number of samples in the array.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_name","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_name","text":"get_name(pd::ParameterDistribution)\n\nReturns a list of ParameterDistribution names.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_dimensions","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_dimensions","text":"get_dimensions(pd::ParameterDistribution; function_parameter_opt = \"dof\")\n\nThe number of dimensions of the parameter space. (Also represents other dimensions of interest for FunctionParameterDistributionTypes with keyword argument)\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_n_samples","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_n_samples","text":"get_n_samples(pd::ParameterDistribution)\n\nThe number of samples in a Samples distribution\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints","text":"get_all_constraints(pd::ParameterDistribution; return_dict = false)\n\nReturns the (flattened) array of constraints of the parameter distribution. or as a dictionary (\"param_name\" => constraints)\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_constraint_type","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_constraint_type","text":"get_bounds(c::Constraint{T})\n\nGets the parametric type T.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_bounds","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_bounds","text":"get_bounds(c::Constraint)\n\nGets the bounds field from the Constraint.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.batch","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.batch","text":"batch(pd::ParameterDistribution; function_parameter_opt = \"dof\")\n\nReturns a list of contiguous [collect(1:i), collect(i+1:j),... ] used to split parameter arrays by distribution dimensions. function_parameter_opt is passed to ndims in the special case of FunctionParameterDistributionTypes.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_distribution","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_distribution","text":"get_distribution(pd::ParameterDistribution)\n\nReturns a Dict of ParameterDistribution distributions, with the parameter names as dictionary keys. For parameters represented by Samples, the samples are returned as a 2D (parameter_dimension x n_samples) array.\n\n\n\n\n\ngets the, distribution over the coefficients\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#StatsBase.sample","page":"ParameterDistributions","title":"StatsBase.sample","text":"sample([rng], pd::ParameterDistribution, [n_draws])\n\nDraws n_draws samples from the parameter distributions pd. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\nsample([rng], d::Samples, [n_draws])\n\nDraws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\nsample([rng], d::Parameterized, [n_draws])\n\nDraws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\nsample([rng], d::VectorOfParameterized, [n_draws])\n\nDraws n_draws samples from the parameter distributions d. Returns an array, with parameters as columns. rng is optional and defaults to Random.GLOBAL_RNG. n_draws is optional and defaults to 1. Performed in computational space.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Distributions.logpdf","page":"ParameterDistributions","title":"Distributions.logpdf","text":"logpdf(pd::ParameterDistribution, xarray::Array{<:Real,1})\n\nObtains the independent logpdfs of the parameter distributions at xarray (non-Samples Distributions only), and returns their sum.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Statistics.mean","page":"ParameterDistributions","title":"Statistics.mean","text":"mean(pd::ParameterDistribution)\n\nReturns a concatenated mean of the parameter distributions. \n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Statistics.var","page":"ParameterDistributions","title":"Statistics.var","text":"var(pd::ParameterDistribution)\n\nReturns a flattened variance of the distributions\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#Statistics.cov","page":"ParameterDistributions","title":"Statistics.cov","text":"cov(pd::ParameterDistribution)\n\nReturns a dense blocked (co)variance of the distributions.\n\n\n\n\n\n","category":"function"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractVector}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the (possibly) constrained space into unconstrained space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractMatrix}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the (possibly) constrained space into unconstrained space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, Dict}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(d::ParameterDistribution, x::Dict)\n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Here, x contains parameter names as keys, and 1- or 2-arrays as parameter samples.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractVector}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the unconstrained space into (possibly constrained) space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, AbstractMatrix}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(pd::ParameterDistribution, x::Array{Array{<:Real,2},1})\n\nApply the transformation to map parameter sample ensembles x from the unconstrained space into (possibly constrained) space. Here, x is an iterable of parameters sample ensembles for different EKP iterations.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Tuple{EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution, Dict}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(d::ParameterDistribution, x::Dict)\n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Here, x contains parameter names as keys, and 1- or 2-arrays as parameter samples.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#FunctionParameterDistributions","page":"ParameterDistributions","title":"FunctionParameterDistributions","text":"","category":"section"},{"location":"API/ParameterDistributions/","page":"ParameterDistributions","title":"ParameterDistributions","text":"GaussianRandomFieldsPackage\nGaussianRandomFieldInterface\nndims(grfi::GaussianRandomFieldInterface)\nget_all_constraints(grfi::GaussianRandomFieldInterface)\ntransform_constrained_to_unconstrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractVector{FT}) where {FT <: Real}\ntransform_constrained_to_unconstrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractMatrix{FT}) where {FT <: Real}\ntransform_unconstrained_to_constrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractVector{FT}) where {FT <: Real}\ntransform_unconstrained_to_constrained(::GaussianRandomFieldInterface, ::AbstractVector, ::AbstractMatrix{FT}) where {FT <: Real}","category":"page"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage","text":"abstract type GaussianRandomFieldsPackage\n\nType to dispatch which Gaussian Random Field package to use:\n\nGRFJL uses the Julia Package GaussianRandomFields.jl \n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface","text":"struct GaussianRandomFieldInterface <: FunctionParameterDistributionType\n\nGaussianRandomFieldInterface object based on a GRF package. Only a ND->1D output-dimension field interface is implemented.\n\nFields\n\ngaussian_random_field::Any\nGRF object, containing the mapping from the field of coefficients to the discrete function\npackage::EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldsPackage\nthe choice of GRF package\ndistribution::EnsembleKalmanProcesses.ParameterDistributions.ParameterDistribution\nthe distribution of the coefficients that we shall compute with\n\n\n\n\n\n","category":"type"},{"location":"API/ParameterDistributions/#Base.ndims-Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface}","page":"ParameterDistributions","title":"Base.ndims","text":"ndims(grfi::GaussianRandomFieldInterface, function_parameter_opt = \"dof\")\n\nProvides a relevant number of dimensions in different circumstances, If function_parameter_opt =\n\n\"dof\" : returns n_dofs(grfi), the degrees of freedom in the function\n\"eval\" : returns n_eval_pts(grfi), the number of discrete evaluation points of the function\n\"constraint\": returns 1, the number of constraints in the evaluation space \n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints-Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface}","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.get_all_constraints","text":"get_all_constraints(grfi::GaussianRandomFieldInterface) = get_all_constraints(get_distribution(grfi))\n\ngets all the constraints of the internally stored coefficient prior distribution of the GRFI\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractVector{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractVector)\n\nAssume x is a flattened vector of evaluation points. Remove the constraint from constraint to the output space of the function. Note this is the inverse of transform_unconstrained_to_constrained(...,build_flag=false)\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractMatrix{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_constrained_to_unconstrained","text":"transform_constrained_to_unconstrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatrix)\n\nAssume x is a matrix with columns as flattened samples of evaluation points. Remove the constraint from constraint to the output space of the function. Note this is the inverse of transform_unconstrained_to_constrained(...,build_flag=false)\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractVector{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractVector)\n\nOptional Args build_flag::Bool = true\n\nTwo functions, depending on build_flag If true, assume x is a vector of coefficients. Perform the following 3 maps. \n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)\nBuild the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.\nApply the constraint from constraint to the output space of the function.\n\nIf false, Assume x is a flattened vector of evaluation points. Apply only step 3. above to x.\n\n\n\n\n\n","category":"method"},{"location":"API/ParameterDistributions/#EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained-Union{Tuple{FT}, Tuple{EnsembleKalmanProcesses.ParameterDistributions.GaussianRandomFieldInterface, AbstractVector, AbstractMatrix{FT}}} where FT<:Real","page":"ParameterDistributions","title":"EnsembleKalmanProcesses.ParameterDistributions.transform_unconstrained_to_constrained","text":"transform_unconstrained_to_constrained(d::GaussianRandomFieldInterface, constraint::AbstractVector, x::AbstractMatri)\n\nOptional args: build_flag::Bool = true\n\nTwo functions, depending on build_flag If true, assume x is a matrix with columns of coefficient samples. Perform the following 3 maps. \n\nApply the transformation to map (possibly constrained) parameter samples x into the unconstrained space. Using internally stored constraints (given by the coefficient prior)\nBuild the unconstrained (flattened) function sample at the evaluation points from these constrained coefficients.\nApply the constraint from constraint to the output space of the function.\n\nIf false, Assume x is a matrix with columns as flattened samples of evaluation points. Apply only step 3. above to x.\n\n\n\n\n\n","category":"method"},{"location":"API/TOMLInterface/#TOML-interface","page":"TOML Interface","title":"TOML interface","text":"","category":"section"},{"location":"API/TOMLInterface/","page":"TOML Interface","title":"TOML Interface","text":"CurrentModule = EnsembleKalmanProcesses.TOMLInterface","category":"page"},{"location":"API/TOMLInterface/","page":"TOML Interface","title":"TOML Interface","text":"path_to_ensemble_member\nget_parameter_distribution\nget_parameter_values\nsave_parameter_ensemble\nget_admissible_parameters\nget_regularization\nwrite_log_file","category":"page"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.path_to_ensemble_member","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.path_to_ensemble_member","text":"path_to_ensemble_member(\n base_path,\n iteration,\n member,\n pad_zeros = 3,\n)\n\nObtains the file path to a specified ensemble member. The likely form is base_path/iteration_X/member_Y/ with X,Y padded with zeros. The file path can be reconstructed with: base_path - base path to where EKP parameters are stored member - number of the ensemble member (without zero padding) iteration - iteration of ensemble method (if =nothing then only the load path is used) pad_zeros - amount of digits to pad to\n\n\n\n\n\nOne can also call this without the iteration level\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_parameter_distribution","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_parameter_distribution","text":"get_parameter_distribution(param_dict, name)\n\nConstructs a ParameterDistribution for a single parameter\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values name - parameter name\n\nReturns a ParameterDistribution\n\n\n\n\n\nget_parameter_distribution(param_dict, names)\n\nConstructs a ParameterDistribution for an array of parameters\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' prior distributions and constraints) as values names - array of parameter names\n\nReturns a ParameterDistribution \n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_parameter_values","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_parameter_values","text":"get_parameter_values(param_dict, names)\n\nGets parameter values from a parameter dictionary, indexing by name.\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information (in particular, the parameters' values) name - iterable parameter names return_type - return type, default \"dict\", otherwise \"array\"\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.save_parameter_ensemble","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.save_parameter_ensemble","text":"save_parameter_ensemble(\n param_array,\n param_distribution,\n default_param_data,\n save_path,\n save_file,\n iteration\n pad_zeros=3,\napply_constraints=true\n)\n\nSaves the parameters in the given param_array to TOML files. The intended use is for saving the ensemble of parameters after each update of an ensemble Kalman process. Each ensemble member (column of param_array) is saved in a separate directory \"member\" (j=1, ..., Nens). The name of the saved toml file is given by save_file; it is the same for all members. A directory \"iteration\" is created in `savepath`, which contains all the \"member_\" subdirectories.\n\nArgs: param_array - array of size Nparam x Nens param_distribution - the parameter distribution underlying param_array apply_constraints - apply the constraints in param_distribution default_param_data - dict of default parameters to be combined and saved with the parameters in param_array into a toml file save_path - path to where the parameters will be saved save_file - name of the toml files to be generated iteration - the iteration of the ensemble Kalman process represented by the given param_array pad_zeros - the amount of zero-padding for the ensemble member number\n\n\n\n\n\nOne can also call this without the iteration level\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_admissible_parameters","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_admissible_parameters","text":"get_admissible_parameters(param_dict)\n\nFinds all parameters in param_dict that are admissible for calibration.\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values\n\nReturns an array of the names of all admissible parameters in param_dict. Admissible parameters must have a key \"prior\" and the value value of this is not set to \"fixed\". This allows for other parameters to be stored within the TOML file.\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.get_regularization","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.get_regularization","text":"get_regularization(param_dict, name)\n\nReturns the regularization information for a single parameter\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values name - parameter name\n\nReturns a tuple (, ), where the regularization type is either \"L1\" or \"L2\", and the regularization value is a float. Returns (nothing, nothing) if parameter has no regularization information.\n\n\n\n\n\nget_regularization(param_dict, names)\n\nReturns the regularization information for an array of parameters\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionary of parameter information as values names - array of parameter names\n\nReturns an arary of tuples (, ), with the ith tuple corresponding to the parameter names[i]. The regularization type is either \"L1\" or \"L2\", and the regularization value is a float. Returns (nothing, nothing) for parameters that have no regularization information.\n\n\n\n\n\n","category":"function"},{"location":"API/TOMLInterface/#EnsembleKalmanProcesses.TOMLInterface.write_log_file","page":"TOML Interface","title":"EnsembleKalmanProcesses.TOMLInterface.write_log_file","text":"write_log_file(param_dict, file_path)\n\nWrites the parameters in param_dict into a .toml file\n\nArgs: param_dict - nested dictionary that has parameter names as keys and the corresponding dictionaries of parameter information as values file_path - path of the file where parameters are saved\n\n\n\n\n\n","category":"function"},{"location":"examples/ClimateMachine_example/#HPC-interfacing-example:-ClimateMachine","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"","category":"section"},{"location":"examples/ClimateMachine_example/#Overview","page":"HPC interfacing example: ClimateMachine","title":"Overview","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This examples uses EnsembleKalmanProcesses.jl to calibrate a climate model, showcasing a workflow which is compatible with HPC resources managed with the SLURM workload manager. The workflow is based on read-write input/output files, and as such it is capable of interfacing with dynamical models in different code languages, or with complicated processing stages. The dynamical model for this example is ClimateMachine.jl, an Earth system model currently under development at CliMA.","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The calibration example makes use of a simple single atmospheric column model configuration with two learnable parameters that control turbulent mixing processes in the lower troposphere. It is also a perfect model experiment, in the sense that the ground truth is generated using the same model and a prescribed combination of parameters. The parameters used to generate the ground truth are (C_smag, C_drag) = (0.21, 0.0011). The evolution of the atmosphere for this setup is strongly influenced by C_smag, and very weakly by C_drag. Thus, we expect the EKP to recover C_smag from observations.","category":"page"},{"location":"examples/ClimateMachine_example/#Prerequisites","page":"HPC interfacing example: ClimateMachine","title":"Prerequisites","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This example requires ClimateMachine.jl to be installed in the same parent directory as EnsembleKalmanProcesses.jl. You may install ClimateMachine.jl directly from GitHub,","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ git clone https://github.com/CliMA/ClimateMachine.jl.git","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"Change into the ClimateMachine.jl directory with ","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ cd ClimateMachine.jl","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"and install all the required packages with:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project -e 'using Pkg; pkg\"instantiate\";'","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"Pre-compile the packages to allow the ClimateMachine.jl to start faster:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project -e 'using Pkg; pkg\"precompile\"'","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"You can find more information about ClimateMachine.jl here. ClimateMachine.jl is a rapidly evolving software and this example may stop working in the future, please open an issue if you find that to be the case!","category":"page"},{"location":"examples/ClimateMachine_example/#Structure","page":"HPC interfacing example: ClimateMachine","title":"Structure","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The example makes use of julia and bash scripts for interactions with the workload manager and running multiple forward model evaluations in parallel. The user-triggered script ekp_calibration.sbatch initializes and controls the flow of the calibration process, which in this case is a SLURM queue with job dependencies. The calibration bash scripts, in order of execution and with their associated julia scripts, are","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"ekp_init_calibration: Calls init_calibration.jl, which samples the initial parameter ensemble from a specified prior. The initial ensemble is stored in a set of parameter files.\nekp_single_cm_run: Script called in parallel by the workload manager. Each copy of the script submits a single forward model run (i.e., a ClimateMachine.jl run) given a specific pair of parameters (C_smag, C_drag) read from a corresponding file. The output of each forward model run is stored in a separate NetCDF file.\nekp_cont_calibration: Calls sstep_calibration.jl, which reads from a NetCDF file the output generated by ClimateMachine.jl in step 2 and performs an iteration of the Ensemble Kalman Inversion algorithm, updating the parameter ensemble. The new parameters are stored in new parameter files.","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This flow follows steps 1->2->3->2->3->... for a user-specified number of iterations.","category":"page"},{"location":"examples/ClimateMachine_example/#Running-the-Example","page":"HPC interfacing example: ClimateMachine","title":"Running the Example","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"From the parent directory of ClimateMachine.jl and EnsembleKalmanProcesses.jl, change into the example directory with","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ cd EnsembleKalmanProcesses.jl/examples/ClimateMachine","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"and install all the required packages for the example with:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project -e 'using Pkg; pkg\"instantiate\";'","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"To run the example using a SLURM workload manager, simply do:","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ sbatch ekp_calibration.sbatch","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The dynamical model outputs (i.e, Psi(phi)) for all runs of ClimateMachine.jl will be stored in NetCDF format in directories identifiable by their version number. Refer to the files version_XX.txt to identify each run with each ensemble member within the XX iteration of the Ensemble Kalman Process. ","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"In this example, the parameters are defined through a Gaussian prior in init_calibration.jl. Hence, the transform from constrained to unconstrained space is the identity map, and we have phi=theta. Overall the forward map mathcalG(theta) is given by applying an observation map mathcalH to the dynamical model output Psi. In this case, mathcalH returns the time average of the horizontal velocity over a specified 30 min interval after initialization. Therefore, the observation vector y contains a time-averaged vertical profile of the horizontal velocity.","category":"page"},{"location":"examples/ClimateMachine_example/#Calibration-Solution","page":"HPC interfacing example: ClimateMachine","title":"Calibration Solution","text":"","category":"section"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"To aggregate the parameter ensembles theta^(1) theta^(2) dots theta^(J) generated during the calibration process, you may use the agg_clima_ekp(...) function located in helper_funcs.jl,","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"$ julia --project","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"include(joinpath(@__DIR__, \"helper_funcs.jl\"))\n\nagg_clima_ekp(2) # This generates the output containing the ensembles for each iteration, input is the number of parameters","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"This will create the JLD file ekp_clima.jld. We may read the file as follows","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"using JLD\n\nθ = load(\"ekp_clima.jld\")[\"ekp_u\"]\nprintln(typeof(θ)) # Array{Array{Float64,2},1}, outer dimension is N_iter, inner Array{Float64,2} of size = (J, p)","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"The optimal parameter vector determined by the ensemble Kalman inversion is the ensemble mean of the particles after the last iteration. Following the previous script,","category":"page"},{"location":"examples/ClimateMachine_example/","page":"HPC interfacing example: ClimateMachine","title":"HPC interfacing example: ClimateMachine","text":"using Statistics\n\nθ_opt = mean(θ[end], dims=1)","category":"page"},{"location":"unscented_kalman_inversion/#Unscented-Kalman-Inversion","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"One of the ensemble Kalman processes implemented in EnsembleKalmanProcesses.jl is the unscented Kalman inversion (Huang, Schneider, Stuart, 2022). The unscented Kalman inversion (UKI) is a derivative-free method for approximate Bayesian inference. We seek to find the posterior parameter distribution theta in mathbbR^p from the inverse problem","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" y = mathcalG(theta) + eta","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where mathcalG denotes the forward map, y in mathbbR^d is the vector of observations and eta sim mathcalN(0 Gamma_y) is additive Gaussian noise. Note that p is the size of the parameter vector theta and d is taken to be the size of the observation vector y. The UKI algorithm has the following properties","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"UKI has a fixed ensemble size, with members forming a quadrature stencil (rather than the random positioning of the particles from methods such as EKI). There are two quadrature options, symmetric (a 2p + 1-size stencil), and simplex (a p+2-size stencil).\nUKI has uncertainty quantification capabilities, it gives both mean and covariance approximation (no ensemble collapse and no empirical variance inflation) of the posterior distribution, the 3-sigma confidence interval covers the truth parameters for perfect models.","category":"page"},{"location":"unscented_kalman_inversion/#Algorithm","page":"Unscented Kalman Inversion","title":"Algorithm","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The UKI applies the unscented Kalman filter to the following stochastic dynamical system ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"beginaligned\n textrmevolution theta_n+1 = r + alpha (theta_n - r) + omega_n+1 omega_n+1 sim mathcalN(0Sigma_omega)\n textrmobservation y_n+1 = mathcalG(theta_n+1) + nu_n+1 nu_n+1 sim mathcalN(0Sigma_nu)\nendaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The free parameters in the UKI are alpha r Sigma_nu Sigma_omega. The UKI updates both the mean m_n and covariance C_n estimations of the parameter vector theta as following","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Prediction step :","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"beginaligned\n hatm_n+1 = r+alpha(m_n-r)\n hatC_n+1 = alpha^2 C_n + Sigma_omega\nendaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Generate sigma points (\"the ensemble\") :","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"For the sigma_points = symmetric quadrature option, the ensemble is generated as follows.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"beginaligned\n hattheta_n+1^0 = hatm_n+1 \n hattheta_n+1^j = hatm_n+1 + c_j sqrthatC_n+1_j quad (1leq jleq J) \n hattheta_n+1^j+J = hatm_n+1 - c_j sqrthatC_n+1_jquad (1leq jleq J)\nendaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where sqrtC_j is the j-th column of the Cholesky factor of C. ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Analysis step :","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" beginaligned\n haty^j_n+1 = mathcalG(hattheta^j_n+1) qquad haty_n+1 = haty^0_n+1\n hatC^theta p_n+1 = sum_j=1^2JW_j^c\n (hattheta^j_n+1 - hatm_n+1 )(haty^j_n+1 - haty_n+1)^T \n hatC^pp_n+1 = sum_j=1^2JW_j^c\n (haty^j_n+1 - haty_n+1 )(haty^j_n+1 - haty_n+1)^T + Sigma_nu\n m_n+1 = hatm_n+1 + hatC^theta p_n+1(hatC^pp_n+1)^-1(y - haty_n+1)\n C_n+1 = hatC_n+1 - hatC^theta p_n+1(hatC^pp_n+1)^-1hatC^theta p_n+1^T\n endaligned","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Where the coefficients c_j W^c_j are given by","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" beginaligned\n c_j = asqrtJ qquad W_j^c = frac12a^2J(j=1cdots2N_theta) qquad a=minsqrtfrac4J 1 \n endaligned","category":"page"},{"location":"unscented_kalman_inversion/#Choice-of-free-parameters","page":"Unscented Kalman Inversion","title":"Choice of free parameters","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The free parameters in the unscented Kalman inversion are alpha r Sigma_nu Sigma_omega, which are chosen based on theorems developed in Huang et al, 2021","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"the vector r is set to be the prior mean\nthe scalar alpha in (01 is a regularization parameter, which is used to overcome ill-posedness and overfitting. A practical guide is \nWhen the observation noise is negligible, and there are more observations than parameters (identifiable inverse problem) alpha = 1 (no regularization)\nOtherwise alpha 1. The smaller alpha is, the closer the UKI mean will converge to the prior mean.\nthe matrix Sigma_nu is the artificial observation error covariance. We set Sigma_nu = 2 Gamma_y, which makes the inverse problem consistent. \nthe matrix Sigma_omega is the artificial evolution error covariance. We set Sigma_omega = (2 - alpha^2)Lambda. We choose Lambda as following\nwhen there are more observations than parameters (identifiable inverse problem), Lambda = C_n, which is updated as the estimated covariance C_n in the n-th every iteration. This guarantees the converged covariance matrix is a good approximation to the posterior covariance matrix with an uninformative prior.\notherwise Lambda = C_0, this allows that the converged covariance matrix is a weighted average between the posterior covariance matrix with an uninformative prior and C_0.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"In short, users only need to change the alpha (α_reg), and the frequency to update the Lambda to the current covariance (update_freq). The user can first try α_reg = 1.0 and update_freq = 0 (corresponding to Lambda = C_0).","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"note: Preventing ensemble divergence\nIf UKI suffers divergence (for example when inverse problems are not well-posed), one can prevent it by using Tikhonov regularization (see Huang, Schneider, Stuart, 2022). It is used by setting the impose_prior = true flag. In this mode, the free parameters are fixed to α_reg = 1.0, update_freq = 1. ","category":"page"},{"location":"unscented_kalman_inversion/#Implementation","page":"Unscented Kalman Inversion","title":"Implementation","text":"","category":"section"},{"location":"unscented_kalman_inversion/#Initialization","page":"Unscented Kalman Inversion","title":"Initialization","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"An unscented Kalman inversion object can be created using the EnsembleKalmanProcess constructor by specifying the Unscented() process type.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Creating an ensemble Kalman inversion object requires as arguments:","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The mean value of the observed outputs, a vector of size [d];\nThe covariance of the observational noise, a matrix of size [d × d];\nThe Unscented() process type.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The initialization of the Unscented() process requires prior mean and prior covariance, and the the size of the observation d. And user defined hyperparameters α_reg and update_freq.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\n\n# need to choose regularization factor α ∈ (0,1], \n# when you have enough observation data α=1: no regularization\nα_reg = 1.0\n# update_freq 1 : approximate posterior covariance matrix with an uninformative prior\n# 0 : weighted average between posterior covariance matrix with an uninformative prior and prior\nupdate_freq = 0\n\nprocess = Unscented(prior_mean, prior_cov; α_reg = α_reg, update_freq = update_freq)\nukiobj = EnsembleKalmanProcess(truth_sample, truth.obs_noise_cov, process)\n","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Note that no information about the forward map is necessary to initialize the Unscented process. The only forward map information required by the inversion process consists of model evaluations at the ensemble elements, necessary to update the ensemble.","category":"page"},{"location":"unscented_kalman_inversion/#Constructing-the-Forward-Map","page":"Unscented Kalman Inversion","title":"Constructing the Forward Map","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"At the core of the forward map mathcalG is the dynamical model PsimathbbR^p rightarrow mathbbR^o (running Psi is usually where the computational heavy-lifting is done), but the map mathcalG may include additional components such as a transformation of the (unbounded) parameters theta to a constrained domain the dynamical model can work with, or some post-processing of the output of Psi to generate the observations. For example, mathcalG may take the following form:","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"mathcalG = mathcalH circ Psi circ mathcalT^-1","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where mathcalHmathbbR^o rightarrow mathbbR^d is the observation map and mathcalT is the transformation from the constrained to the unconstrained parameter space, such that mathcalT(phi)=theta. A family of standard transformations and their inverses are available in the ParameterDistributions module.","category":"page"},{"location":"unscented_kalman_inversion/#Updating-the-Ensemble","page":"Unscented Kalman Inversion","title":"Updating the Ensemble","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"Once the unscented Kalman inversion object UKIobj has been initialized, any number of updates can be performed using the inversion algorithm.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"A call to the inversion algorithm can be performed with the update_ensemble! function. This function takes as arguments the UKIobj and the evaluations of the forward map at each element of the current ensemble. The update_ensemble! function then stores the new updated ensemble and the inputted forward map evaluations in UKIobj.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The forward map mathcalG maps the space of unconstrained parameters theta to the outputs y in mathbbR^d. In practice, the user may not have access to such a map directly. And the map is a composition of several functions. The update_ensemble! uses only the evalutaions g_ens but not the forward map ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"For implementational reasons, the update_ensemble is performed by computing analysis stage first, followed by a calculation of the next sigma ensemble. The first sigma ensemble is created in the initialization.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"# Given:\n# Ψ (some black box simulator)\n# H (some observation of the simulator output)\n# prior (prior distribution and parameter constraints)\n\nN_iter = 20 # Number of steps of the algorithm\n \nfor n in 1:N_iter\n ϕ_n = get_ϕ_final(prior, ukiobj) # Get current ensemble in constrained \"ϕ\"-space\n G_n = [H(Ψ(ϕ_n[:, i])) for i in 1:J] # Evaluate forward map\n g_ens = hcat(G_n...) # Reformat into `d x N_ens` matrix\n EnsembleKalmanProcesses.update_ensemble!(ukiobj, g_ens) # Update ensemble\nend","category":"page"},{"location":"unscented_kalman_inversion/#Solution","page":"Unscented Kalman Inversion","title":"Solution","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The solution of the unscented Kalman inversion algorithm is a Gaussian distribution whose mean and covariance can be extracted from the ''last ensemble'' (i.e., the ensemble after the last iteration). The sample mean of the last ensemble is also the \"optimal\" parameter (θ_optim) for the given calibration problem. These statistics can be accessed as follows: ","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"# mean of the Gaussian distribution, also the optimal parameter for the calibration problem\nθ_optim = get_u_mean_final(ukiobj)\n# covariance of the Gaussian distribution\nsigma_optim = get_u_cov_final(ukiobj)","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"There are two examples: Lorenz96 and Cloudy.","category":"page"},{"location":"unscented_kalman_inversion/#Handling-forward-model-failures","page":"Unscented Kalman Inversion","title":"Handling forward model failures","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"In situations where the forward model mathcalG represents a diagnostic of a complex computational model, there might be cases where for some parameter combinations theta, attempting to evaluate mathcalG(theta) may result in model failure (defined as returning a NaN from the point of view of this package). In such cases, the UKI update equations must be modified to handle model failures.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"EnsembleKalmanProcesses.jl implements such modifications through the FailureHandler structure, an input to the EnsembleKalmanProcess constructor. Currently, the only failsafe modification available is SampleSuccGauss(), described in Lopez-Gomez et al (2022).","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"To employ this modification, construct the EKI object as","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"using EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\n\n\n# need to choose regularization factor α ∈ (0,1], \n# when you have enough observation data α=1: no regularization\nα_reg = 1.0\n# update_freq 1 : approximate posterior covariance matrix with an uninformative prior\n# 0 : weighted average between posterior covariance matrix with an uninformative prior and prior\nupdate_freq = 0\n\nprocess = Unscented(prior_mean, prior_cov; α_reg = α_reg, update_freq = update_freq)\nukiobj = EnsembleKalmanProcess(\n truth_sample,\n truth.obs_noise_cov,\n process,\n failure_handler_method = SampleSuccGauss())\n","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"info: Forward model requirements when using FailureHandlers\nThe user must determine if a model run has \"failed\", and replace the output mathcalG(theta) with NaN. The FailureHandler takes care of the rest.","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"A description of the algorithmic modification is included below.","category":"page"},{"location":"unscented_kalman_inversion/#SampleSuccGauss-modification","page":"Unscented Kalman Inversion","title":"SampleSuccGauss modification","text":"","category":"section"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"The SampleSuccGauss() modification is based on performing the UKI quadratures over the successful sigma points. Consider the set of off-center sigma points hattheta = hattheta_s cup hattheta_f where hattheta_s^(j), j=1 dots J_s are successful members and hattheta_f^(k) are not. For ease of notation, consider an ordering of hattheta such that hattheta_s are its first J_s elements, and note that we deal with the central point hattheta^(0) separately. We estimate the covariances mathrmCov_q(mathcalG_n mathcalG_n) and mathrmCov_q(theta_n mathcalG_n) from the successful ensemble,","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" tag1 mathrmCov_q(theta_n mathcalG_n) approx sum_j=1^J_sw_sj (hattheta_s n^(j) - bartheta_sn)(mathcalG(hattheta_s n^(j)) - barmathcalG_sn)^T","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" tag2 mathrmCov_q(mathcalG_n mathcalG_n) approx sum_j=1^J_sw_sj (mathcalG(hattheta_s n^(j)) - barmathcalG_sn)(mathcalG(hattheta_s n^(j)) - barmathcalG_sn)^T","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"where the weights at each successful sigma point are scaled up, to preserve the sum of weights,","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" w_sj = left(dfracsum_i=1^2p w_isum_k=1^J_s w_kright)w_j","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":"In equations (1) and (2), the means bartheta_sn and barmathcalG_sn must be modified from the original formulation if the central point hattheta^(0)=m_n results in model failure. If this is the case, then an average is taken across the other (successful) ensemble members","category":"page"},{"location":"unscented_kalman_inversion/","page":"Unscented Kalman Inversion","title":"Unscented Kalman Inversion","text":" bartheta_sn =\ndfrac1J_ssum_j=1^J_shattheta_s n^(j) qquad barmathcalG_sn =\ndfrac1J_ssum_j=1^J_smathcalG(hattheta_s n^(j))","category":"page"},{"location":"examples/Cloudy_example/#Cloudy-example","page":"Cloudy","title":"Cloudy Example","text":"","category":"section"},{"location":"examples/Cloudy_example/#Overview","page":"Cloudy","title":"Overview","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"This example is based on Cloudy, a microphysics model that simulates how cloud droplets collide and coalesce into larger drops. Collision-coalescence is a crucial process for the formation of rain. ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy is initialized with a mass distribution of the cloud droplets; this distribution is then evolved in time, with more and more droplets colliding and combining into bigger drops according to the droplet-droplet interactions specified by a collision-coalescence kernel. The evolution is completely determined by the shape of the initial distribution and the form of the kernel.","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"This example shows how ensemble Kalman methods can be used to learn the parameters of the initial cloud droplet mass distribution from observations of the moments of that mass distribution at a later time. The collision-coalescence kernel is assumed to be known, but one could also learn the parameters of the kernel instead of the parameters of the droplet distribution (or both).","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy is used here in a \"perfect model\" (aka \"known truth\") setting, which means that the \"observations\" are generated by Cloudy itself, by running it with the true parameter values. In more realistic applications, this parameter estimation procedure will use actual measurements of cloud properties to obtain an estimated droplet mass distribution at a previous time.","category":"page"},{"location":"examples/Cloudy_example/#Prerequisites","page":"Cloudy","title":"Prerequisites","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"In order to run this example, you need to install Cloudy.jl (the \"#master\" lets you install the current master branch):","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"pkg > add Cloudy#master","category":"page"},{"location":"examples/Cloudy_example/#Structure","page":"Cloudy","title":"Structure","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The file Cloudy_example_eki.jl sets up the inverse problem and solves it using ensemble Kalman inversion, and the file Cloudy_example_uki.jl does the same using unscented Kalman inversion. The file DynamicalModel.jl provides the functionality to run the dynamical model Psi, which in this example is Cloudy.","category":"page"},{"location":"examples/Cloudy_example/#Running-the-Example","page":"Cloudy","title":"Running the Example","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Once Cloudy is installed, the examples can be run from the julia REPL:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"# Solve inverse problem using ensemble Kalman inversion\ninclude(\"Cloudy_example_eki.jl\")","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"or","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"# Solve inverse problem using unscented Kalman inversion\ninclude(\"Cloudy_example_uki.jl\")","category":"page"},{"location":"examples/Cloudy_example/#What-Does-Cloudy-Do?","page":"Cloudy","title":"What Does Cloudy Do?","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The mathematical starting point of Cloudy is the stochastic collection equation (SCE; sometimes also called Smoluchowski equation after Marian Smoluchowski), which describes the time rate of change of f = f(m t), the mass distribution function of liquid water droplets, due to the process of collision and coalescence. The distribution function f depends on droplet mass m and time t and is defined such that f(m) text dm denotes the number of droplets with masses in the interval m m + dm per unit volume. ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The stochastic collection equation is an integro-differential equation that can be written as ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" fracpartial f(m t)partial t = frac12 int_m=0^infty f(m t) f(m-m t) mathcalC(m m-m)textdm - f(m t) int_m=0^infty f(m t)mathcalC(m m) textdm ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"where mathcalC(m m) is the collision-coalescence kernel, which encapsulates the physics of droplet-droplet interactions – it describes the rate at which two drops of masses m and m come into contact and coalesce into a drop of mass m + m. The first term on the right-hand side of the SCE describes the rate of increase of the number of drops having a mass m due to collision and coalescence of drops of masses m and m-m (where the factor frac12 avoids double counting), while the second term describes the rate of reduction of drops of mass m due to collision and coalescence of drops having a mass m with other drops. ","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"We can rewrite the SCE in terms of the moments M_k of f, which are the prognostic variables in Cloudy. They are defined by","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" M_k = int_0^infty m^k f(m t) textdm","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The time rate of change of the k-th moment of f is obtained by multiplying the SCE by m^k and integrating over the entire range of droplet masses (from m=0 to infty), which yields","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" fracpartial M_k(t)partial t = frac12int_0^infty left((m+m)^k - m^k - m^kright) mathcalC(m m)f(m t)f(m t) textdm textdm (1)","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"In this example, the kernel is set to be constant – mathcalC(m m) = B = textconst – and the cloud droplet mass distribution is assumed to be a textGamma(k_t theta_t) distribution, scaled by a factor N_0t which denotes the droplet number concentration:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"f(m t) = fracN_0tGamma(k_t)theta_t^k m^k_t-1 exp(-mtheta_t)","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The parameter vector phi_t= N_0t k_t theta_t changes over time (as indicated by the subscript t), as the shape of the distribution evolves. In fact, there is a priori no reason to assume that the distribution would retain its Gamma shape over time, but this is a common assumption that is made in order to solve the closure problem (without this assumption, one would have to keep track of infinitely many moments of the mass distribution in order to uniquely identify the distribution f at each time step, which is obviously not practicable).","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"For Gamma mass distribution functions, specifying the first three moments (M_0, M_1, and M_2) is sufficient to uniquely determine the parameter vector phi_t, hence Cloudy solves equation (1) for k = 0 1 2. This mapping of the parameters of the initial cloud droplet mass distribution to the (zeroth-, first-, and second-order) moments of the distribution at a specified end time is done by DynamicalModel.jl.","category":"page"},{"location":"examples/Cloudy_example/#Setting-up-the-Inverse-Problem","page":"Cloudy","title":"Setting up the Inverse Problem","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"The goal is to learn the distribution parameters at time t = 0, phi_0 = N_00 k_0 theta_0, from observations y = M_0(t_end) M_1(t_end) M_2(t_end) of the zeroth-, first-, and second-order moments of the distribution at time t_end 0 (where t_end = 1.0 in this example). This is a known truth experiment, in which the true parameters phi_0 texttrue are defined to be:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"N0_true = 300.0 # number of particles (scaling factor for Gamma distribution)\nθ_true = 1.5597 # scale parameter of Gamma distribution\nk_true = 0.0817 # shape parameter of Gamma distribution","category":"page"},{"location":"examples/Cloudy_example/#Priors","page":"Cloudy","title":"Priors","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"In the code, the priors are constructed as follows:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"par_names = [\"N0\", \"θ\", \"k\"]\n# constrained_gaussian(\"name\", desired_mean, desired_std, lower_bd, upper_bd)\nprior_N0 = constrained_gaussian(par_names[1], 400, 300, 0.4 * N0_true, Inf)\nprior_θ = constrained_gaussian(par_names[2], 1.0, 5.0, 1e-1, Inf)\nprior_k = constrained_gaussian(par_names[3], 0.2, 1.0, 1e-4, Inf)\npriors = combine_distributions([prior_N0, prior_θ, prior_k])","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"We use the recommended constrained_gaussian to add the desired scale and bounds to the prior distribution, in particular we place lower bounds to preserve positivity (and numerical stability). ","category":"page"},{"location":"examples/Cloudy_example/#Observational-Noise","page":"Cloudy","title":"Observational Noise","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy produces output y = M_0(t_end) M_1(t_end) M_2(t_end), which is assumed to be related to the parameter vector theta according to:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":" y = mathcalG(theta) + eta","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"where mathcalG = Psi circ mathcalT^-1 is the forward map, and the observational noise eta is assumed to be drawn from a 3-dimensional Gaussian with distribution mathcalN(0 Gamma_y). In a perfect model setting, the observational noise represents the internal model variability. Since Cloudy is a purely deterministic model, there is no straightforward way of coming up with a covariance Gamma_y for this internal noise. We decide to use a diagonal covariance with the following entries (variances):","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Γy = convert(Array, Diagonal([100.0, 5.0, 30.0]))","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Artificial observations (\"truth samples\") are then generated by adding random samples from eta to G_t, the forward map evaluated for the true parameters:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"for i in 1:n_samples\n y_t[:, i] = G_t .+ rand(MvNormal(μ, Γy))\nend\n\ntruth = Observations.Observation(y_t, Γy, data_names)","category":"page"},{"location":"examples/Cloudy_example/#Solution-and-Output","page":"Cloudy","title":"Solution and Output","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"Cloudy_example_eki.jl: The optimal parameter vector determined by the ensemble Kalman inversion is the ensemble mean of the particles after the last iteration, which is printed to standard output. An output directory is created, where two files are stored: parameter_storage_eki.jld2 and data_storage_eki.jld2, which contain all parameters and model output from the ensemble Kalman iterations, respectively (both as DataContainers.DataContainer objects). In addition, an animation is produced that shows the evolution of the ensemble of particles over subsequent iterations of the optimization, both in the computational (unconstrained) and physical (constrained) spaces.\nCloudy_example_uki.jl: In addition to a point estimate of the optimal parameter (which is again given by the ensemble mean of the last iteration and printed to standard output), unscented Kalman inversion also provides a covariance approximation of the posterior distribution. Together, the mean and covariance allow for the reconstruction of a Gaussian approximation of the posterior distribution. The evolution of this Gaussian approximation over subsequent iterations is shown as an animation over the computational (unconstrained) space. All parameters as well as the model output from the unscented Kalman inversion are stored in an output directory, as parameter_storage_uki.jld2 and data_storage_uki.jld2. ","category":"page"},{"location":"examples/Cloudy_example/#Playing-Around","page":"Cloudy","title":"Playing Around","text":"","category":"section"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"If you want to play around with the Cloudy examples, you can e.g. change the type or the parameters of the initial cloud droplet mass distribution (see Cloudy.ParticleDistributions for the available distributions), by modifying these lines:","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"ϕ_true = [N0_true, θ_true, k_true]\ndist_true = ParticleDistributions.GammaPrimitiveParticleDistribution(ϕ_true...)","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"(Don't forget to also change dist_type accordingly).","category":"page"},{"location":"examples/Cloudy_example/","page":"Cloudy","title":"Cloudy","text":"You can also experiment with different noise covariances (Γy), priors, vary the number of iterations (N_iter) or ensemble particles (N_ens), etc.","category":"page"},{"location":"API/SparseInversion/#Sparse-Ensemble-Kalman-Inversion","page":"SparseInversion","title":"Sparse Ensemble Kalman Inversion","text":"","category":"section"},{"location":"API/SparseInversion/","page":"SparseInversion","title":"SparseInversion","text":"CurrentModule = EnsembleKalmanProcesses","category":"page"},{"location":"API/SparseInversion/","page":"SparseInversion","title":"SparseInversion","text":"SparseInversion\nsparse_eki_update\nsparse_qp","category":"page"},{"location":"API/SparseInversion/#EnsembleKalmanProcesses.SparseInversion","page":"SparseInversion","title":"EnsembleKalmanProcesses.SparseInversion","text":"SparseInversion <: Process\n\nA sparse ensemble Kalman Inversion process\n\nFields\n\nγ::AbstractFloat\nupper limit of l1-norm\nthreshold_value::AbstractFloat\nthreshold below which the norm of parameters is pruned to zero\nuc_idx::Union{Colon, AbstractVector}\nindices of parameters included in the evaluation of l1-norm constraint\nreg::AbstractFloat\na small regularization value to enhance robustness of convex optimization\n\nConstructors\n\nSparseInversion(γ, threshold_value, uc_idx, reg)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:21.\n\nSparseInversion(γ)\n\ndefined at /home/runner/work/EnsembleKalmanProcesses.jl/EnsembleKalmanProcesses.jl/src/SparseEnsembleKalmanInversion.jl:31.\n\nSparseInversion()\n\n\n\n\n\n","category":"type"},{"location":"API/SparseInversion/#EnsembleKalmanProcesses.sparse_eki_update","page":"SparseInversion","title":"EnsembleKalmanProcesses.sparse_eki_update","text":" sparse_eki_update(\n ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},\n u::AbstractMatrix{FT},\n g::AbstractMatrix{FT},\n y::AbstractMatrix{FT},\n obs_noise_cov::Union{AbstractMatrix{CT}, UniformScaling{CT}},\n) where {FT <: Real, CT <: Real, IT}\n\nReturns the sparse updated parameter vectors given their current values and the corresponding forward model evaluations, using the inversion algorithm from eqns. (3.7) and (3.14) of Schneider et al. (2021).\n\nLocalization is applied following Tong and Morzfeld (2022).\n\n\n\n\n\n","category":"function"},{"location":"API/SparseInversion/#EnsembleKalmanProcesses.sparse_qp","page":"SparseInversion","title":"EnsembleKalmanProcesses.sparse_qp","text":"sparse_qp(\n ekp::EnsembleKalmanProcess{FT, IT, SparseInversion{FT}},\n v_j::Vector{FT},\n cov_vv_inv::AbstractMatrix{FT},\n H_u::SparseArrays.SparseMatrixCSC{FT},\n H_g::SparseArrays.SparseMatrixCSC{FT},\n y_j::Vector{FT};\n H_uc::SparseArrays.SparseMatrixCSC{FT} = H_u,\n) where {FT, IT}\n\nSolving quadratic programming problem with sparsity constraint.\n\n\n\n\n\n","category":"function"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"EditURL = \"../../../examples/SparseLossMinimization/loss_minimization_sparse_eki.jl\"","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Minimization-of-simple-loss-functions-with-sparse-EKI","page":"Sparse Minimization Loss","title":"Minimization of simple loss functions with sparse EKI","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"First we load the required packages.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"using Distributions, LinearAlgebra, Random, Plots\n\nusing EnsembleKalmanProcesses\nusing EnsembleKalmanProcesses.ParameterDistributions\nconst EKP = EnsembleKalmanProcesses","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Loss-function-with-single-minimum","page":"Sparse Minimization Loss","title":"Loss function with single minimum","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"Here, we minimize the loss function","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"G₁(u) = u - u_* ","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"where u is a 2-vector of parameters and u_* is given; here u_* = (1 0).","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"u★ = [1, 0]\nG₁(u) = [sqrt((u[1] - u★[1])^2 + (u[2] - u★[2])^2)]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We set the seed for pseudo-random number generator for reproducibility.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"rng_seed = 41\nrng = Random.seed!(Random.GLOBAL_RNG, rng_seed)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We set a stabilization level, which can aid the algorithm convergence","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"dim_output = 1\nstabilization_level = 1e-3\nΓ_stabilization = stabilization_level * Matrix(I, dim_output, dim_output)","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"The functional is positive so to minimize it we may set the target to be 0,","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"G_target = [0]\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Prior-distributions","page":"Sparse Minimization Loss","title":"Prior distributions","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"As we work with a Bayesian method, we define a prior. This will behave like an \"initial guess\" for the likely region of parameter space we expect the solution to live in. Here we define Normal(02^2) distributions with no constraints","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"prior_u1 = constrained_gaussian(\"u1\", 0, 2, -Inf, Inf)\nprior_u2 = constrained_gaussian(\"u1\", 0, 2, -Inf, Inf)\nprior = combine_distributions([prior_u1, prior_u2])\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"note: Note\nIn this example there are no constraints, therefore no parameter transformations.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/#Calibration","page":"Sparse Minimization Loss","title":"Calibration","text":"","category":"section"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We choose the number of ensemble members and the number of iterations of the algorithm","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"N_ensemble = 20\nN_iterations = 10\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"The initial ensemble is constructed by sampling the prior","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"initial_ensemble = EKP.construct_initial_ensemble(rng, prior, N_ensemble)","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"Sparse EKI parameters","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"γ = 1.0\nthreshold_value = 1e-2\nreg = 1e-3\nuc_idx = [1, 2]\n\nprocess = SparseInversion(γ, threshold_value, uc_idx, reg)","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"We then initialize the Ensemble Kalman Process algorithm, with the initial ensemble, the target, the stabilization and the process type (for sparse EKI this is SparseInversion).","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"ensemble_kalman_process = EKP.EnsembleKalmanProcess(initial_ensemble, G_target, Γ_stabilization, process)\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"Then we calibrate by (i) obtaining the parameters, (ii) calculate the loss function on the parameters (and concatenate), and last (iii) generate a new set of parameters using the model outputs:","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"for i in 1:N_iterations\n params_i = get_u_final(ensemble_kalman_process)\n\n g_ens = hcat([G₁(params_i[:, i]) for i in 1:N_ensemble]...)\n\n EKP.update_ensemble!(ensemble_kalman_process, g_ens)\nend","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"and visualize the results:","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"u_init = get_u_prior(ensemble_kalman_process)\n\nanim_unique_minimum = @animate for i in 1:N_iterations\n u_i = get_u(ensemble_kalman_process, i)\n\n plot(\n [u★[1]],\n [u★[2]],\n seriestype = :scatter,\n markershape = :star5,\n markersize = 11,\n markercolor = :red,\n label = \"optimum u⋆\",\n )\n\n plot!(\n u_i[1, :],\n u_i[2, :],\n seriestype = :scatter,\n xlims = extrema(u_init[1, :]),\n ylims = extrema(u_init[2, :]),\n xlabel = \"u₁\",\n ylabel = \"u₂\",\n markersize = 5,\n markeralpha = 0.6,\n markercolor = :blue,\n label = \"particles\",\n title = \"EKI iteration = \" * string(i),\n )\nend\nnothing # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"The results show that the minimizer of G_1 is u=u_*.","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"gif(anim_unique_minimum, \"unique_minimum_sparse.gif\", fps = 1) # hide","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"","category":"page"},{"location":"literated/loss_minimization_sparse_eki/","page":"Sparse Minimization Loss","title":"Sparse Minimization Loss","text":"This page was generated using Literate.jl.","category":"page"},{"location":"#EnsembleKalmanProcesses","page":"Home","title":"EnsembleKalmanProcesses","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"EnsembleKalmanProcesses.jl (EKP) is a library of derivative-free Bayesian optimization techniques based on ensemble Kalman Filters, a well known family of approximate filters used for data assimilation. The tools in this library enable fitting parameters found in expensive black-box computer codes without the need for adjoints or derivatives. This property makes them particularly useful when calibrating non-deterministic models, or when the training data are noisy.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Currently, the following methods are implemented in the library:","category":"page"},{"location":"","page":"Home","title":"Home","text":"Ensemble Kalman Inversion (EKI) - The traditional optimization technique based on the Ensemble Kalman Filter EnKF (Iglesias, Law, Stuart, 2013),\nEnsemble Kalman Sampler (EKS) - also obtains a Gaussian Approximation of the posterior distribution, through a Monte Carlo integration (Garbuno-Inigo, Hoffmann, Li, Stuart, 2020),\nUnscented Kalman Inversion (UKI) - also obtains a Gaussian Approximation of the posterior distribution, through a quadrature based integration approach (Huang, Schneider, Stuart, 2022),\nSparsity-inducing Ensemble Kalman Inversion (SEKI) - Additionally adds approximate L^0 and L^1 penalization to the EKI (Schneider, Stuart, Wu, 2020).","category":"page"},{"location":"","page":"Home","title":"Home","text":"Module Purpose\nEnsembleKalmanProcesses.jl Collection of all tools\nEnsembleKalmanProcess.jl Implementations of EKI, EKS, UKI, and SEKI\nObservations.jl Structure to hold observational data\nParameterDistributions.jl Structures to hold prior and posterior distributions\nDataContainers.jl Structure to hold model parameters and outputs\nLocalizers.jl Covariance localization kernels","category":"page"},{"location":"#Learning-the-amplitude-and-vertical-shift-of-a-sine-curve","page":"Home","title":"Learning the amplitude and vertical shift of a sine curve","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"(Image: Ensemble of parameter estimates by iteration)","category":"page"},{"location":"","page":"Home","title":"Home","text":"See full example for the code.","category":"page"},{"location":"#Authors","page":"Home","title":"Authors","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"EnsembleKalmanProcesses.jl is being developed by the Climate Modeling Alliance. The main developers are Oliver R. A. Dunbar and Ignacio Lopez-Gomez.","category":"page"},{"location":"parallel_hpc/#parallel-hpc","page":"Parallelism and HPC","title":"Parallelism and High Performance Computing (HPC)","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"One benefit of ensemble methods is their ability to be parallelized. The parallellism occurs outside of the EKP update, and so is not present in the source code. On this page we provide suggestions for parallelization for two types of problems:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Run a parallel loop or map within your current Julia session.\nRun a parallel loop through a read/write file interface and workload manager. We provide some utilities to read/write files in a TOML format.","category":"page"},{"location":"parallel_hpc/#Case-1:-Parallel-code-within-Julia","page":"Parallelism and HPC","title":"Case 1: Parallel code within Julia","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Let's look at the simple example for the Lorenz 96 dynamical system. In particular we'll focus on the evaluations of the Lorenz 96 solver explicitly written in GModel.jl that contains the following loop over the N_ens-sized ensemble:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"function run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = zeros(nd, N_ens)\n for i in 1:N_ens\n # run the model with the current parameters, i.e., map θ to G(θ)\n g_ens[:, i] = lorenz_forward(settings, lorenz_params[i])\n end\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Each ensemble member i runs the Lorenz 96 model with settings configuration, and model parameters lorenz_params[i]. The runs do not interact with each other, and the user has several options to parallelize.","category":"page"},{"location":"parallel_hpc/#Running-examples:","page":"Parallelism and HPC","title":"Running examples:","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"All of the following example cases are covered in distributed_Lorenz_example.jl. At the top of file uncomment one of the following options","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"case = multithread \ncase = pmap \ncase = distfor ","category":"page"},{"location":"parallel_hpc/#Multithreading,-@threads","page":"Parallelism and HPC","title":"Multithreading, @threads","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"To parallelize with multithreading, julia must call the file with a prespecified number of threads. For example, for 4 threads, ","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"$ julia --project -t 4 distributed_Lorenz_example.jl","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"We exploit the multithreading over N_ens ensemble members in this example with the following loop in GModel_multithread.jl:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"function run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = zeros(nd, N_ens)\n Threads.@threads for i in 1:N_ens\n # run the model with the current parameters, i.e., map θ to G(θ)\n g_ens[:, i] = lorenz_forward(settings, lorenz_params[i])\n end\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"You can read more about multi-threading here.","category":"page"},{"location":"parallel_hpc/#Parallel-map,-pmap","page":"Parallelism and HPC","title":"Parallel map, pmap","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"When using multiple processes, the Julia environment must first be loaded on each worker processor. We include these lines in the main file","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\naddprocs(4; exeflags = \"--project\")","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"And we would call the file is called by","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"$ julia --project distributed_Lorenz_example","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"This ensures that we obtain 4 worker processes that are loaded with julia's current environment specified by --project (unlike when calling julia --project -p 4). We use pmap to apply a function to each element of the list (i.e the ensemble member configurations). For example, see the following code from GModel_pmap.jl,","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\nfunction run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = zeros(nd, N_ens)\n g_ens[:, :] = vcat(pmap(x -> lorenz_forward(settings, x), lorenz_params)...)\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"If pmap is called within a module, that module will also need to be loaded on all workers. For this we use the macro @everywhere module XYZ.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"You can read more about pmap here.","category":"page"},{"location":"parallel_hpc/#Distributed-loop,-@distributed-for","page":"Parallelism and HPC","title":"Distributed loop, @distributed for","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"When using multiple processes, the Julia environment must also be loaded on each worker processor. We include these lines in the main file","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\naddprocs(4; exeflags = \"--project\")","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"And we would call the file is called by","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"$ julia --project distributed_Lorenz_example","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"When using distributed loops, it is necessary to be able to write to shared memory. To do this we use the SharedArrays package. For example, see the following distributed loop in GModel_distfor ","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"using Distributed\nusing SharedArrays\nfunction run_ensembles(settings, lorenz_params, nd, N_ens)\n g_ens = SharedArray{Float64}(nd, N_ens)\n @sync @distributed for i in 1:N_ens\n # run the model with the current parameters, i.e., map θ to G(θ)\n g_ens[:, i] = lorenz_forward(settings, lorenz_params[i])\n end\n return g_ens\nend","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"@sync forces the code to wait until all processes in the @distributed for loop are complete before continuing.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"If @distributed for is used within another module, that module will also need to be loaded on each worker processor. For this we use the macro @everywhere module XYZ.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"note: Note\n@distributed for is most performant when there is a large ensemble, N_ens, and the forward map is computationally cheap. Otherwise, pmap is usually the preferred choice.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"You can read more about @distributed here","category":"page"},{"location":"parallel_hpc/#Case-2:-HPC-interface","page":"Parallelism and HPC","title":"Case 2: HPC interface","text":"","category":"section"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Some applications involve interfacing with non-Julia code or using HPC workload managers. In these cases we suggest using an alternative workflow where one interleaves scripts that launch EKP updates and scripts that runs the model. One possible implementation is the following loop","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Step 0(a). Write an ensemble of parameter files parameters_0_i for i = 1:N_ens, with each parameter file containing a sample from the prior distribution.\nStep 0(b). Construct EKP EKP object and save in jld2 format e.g. ekpobject.jld2.\nfor n = 1,..., N_it, do:\nStep n(a). Run N_ens forward models, with forward model i running with the corresponding parameter file parameters_{n-1}_i. Write processed output data to file data_{n-1}_i.\nStep n(b). Run the ensemble update, by loading both ekpobject.jld2 and reading in the parameter files data_{n-1}_i for i = 1:N_ens. Perform the EKP update step. Write new parameter files parameters_n_i for i = 1:N_ens. Save the ensemble object in ekpobject.jld2\niterate n -> n+1.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"In HPC interfacing example: ClimateMachine we implement a similar loop to interface with a SLURM workload manager for HPC. Here, sbatch scripts are used to run each component of the calibration procedure. The outer loop over the EKP iterations lives in the overarching sbatch script, and for each iteration, the inner loop are realised as \"arrays\" of slurm jobs (1, ..., N_ens), launched for each ensemble member. The code excerpt below, taken from ekp_calibration.sbatch for details), illustrates this procedure:","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"# First call to calibrate.jl will create the ensemble files from the priors\nid_init_ens=$(sbatch --parsable ekp_init_calibration.sbatch)\nfor it in $(seq 1 1 $n_it)\ndo\n# Parallel runs of forward model\nif [ \"$it\" = \"1\" ]; then\n id_ens_array=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_init_ens --array=1-$n ekp_single_cm_run.sbatch $it)\nelse\n id_ens_array=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_ek_upd --array=1-$n ekp_single_cm_run.sbatch $it)\nfi\nid_ek_upd=$(sbatch --parsable --kill-on-invalid-dep=yes --dependency=afterok:$id_ens_array --export=n=$n ekp_cont_calibration.sbatch $it)\ndone","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"Here a dependency tree is set up in SLURM, which iterates calls to the scripts ekp_single_cm_run.sbatch (which runs the forward model on HPC) and ekp_cont_calibration.sbatch (which performs an EKI update). We find this a smooth workflow that uses HPC resources well, and can likely be set up on other workload managers.","category":"page"},{"location":"parallel_hpc/","page":"Parallelism and HPC","title":"Parallelism and HPC","text":"For more details see the code and docs for the HPC interfacing example: ClimateMachine.","category":"page"},{"location":"API/DataContainers/#DataContainers","page":"DataContainers","title":"DataContainers","text":"","category":"section"},{"location":"API/DataContainers/","page":"DataContainers","title":"DataContainers","text":"CurrentModule = EnsembleKalmanProcesses.DataContainers","category":"page"},{"location":"API/DataContainers/","page":"DataContainers","title":"DataContainers","text":"DataContainer\nPairedDataContainer\nsize","category":"page"},{"location":"API/DataContainers/#EnsembleKalmanProcesses.DataContainers.DataContainer","page":"DataContainers","title":"EnsembleKalmanProcesses.DataContainers.DataContainer","text":"DataContainer{FT <: Real}\n\nContainer to store data samples as columns in an array.\n\n\n\n\n\n","category":"type"},{"location":"API/DataContainers/#EnsembleKalmanProcesses.DataContainers.PairedDataContainer","page":"DataContainers","title":"EnsembleKalmanProcesses.DataContainers.PairedDataContainer","text":"PairedDataContainer{FT <: Real}\n\nStores input - output pairs as data containers, there must be an equal number of inputs and outputs.\n\n\n\n\n\n","category":"type"},{"location":"API/DataContainers/#Base.size","page":"DataContainers","title":"Base.size","text":"size(c<:ConstraintType)\n\nA constraint has size 1.\n\n\n\n\n\nsize(dc::DataContainer, idx::IT) where {IT <: Integer}\n\nReturns the size of the stored data. If idx provided, it returns the size along dimension idx.\n\n\n\n\n\nsize(pdc::PairedDataContainer, idx::IT) where {IT <: Integer}\n\nReturns the sizes of the inputs and ouputs along dimension idx (if provided).\n\n\n\n\n\n","category":"function"}] } diff --git a/dev/unscented_kalman_inversion/index.html b/dev/unscented_kalman_inversion/index.html index 9757b5377..49904b992 100644 --- a/dev/unscented_kalman_inversion/index.html +++ b/dev/unscented_kalman_inversion/index.html @@ -66,4 +66,4 @@ failure_handler_method = SampleSuccGauss())
Forward model requirements when using FailureHandlers

The user must determine if a model run has "failed", and replace the output $\mathcal{G}(\theta)$ with NaN. The FailureHandler takes care of the rest.

A description of the algorithmic modification is included below.

SampleSuccGauss modification

The SampleSuccGauss() modification is based on performing the UKI quadratures over the successful sigma points. Consider the set of off-center sigma points $\{\hat{\theta}\} = \{\hat{\theta}_s\} \cup \{\hat{\theta}_f\}$ where $\hat{\theta}_{s}^{(j)}$, $j=1, \dots, J_s$ are successful members and $\hat{\theta}_{f}^{(k)}$ are not. For ease of notation, consider an ordering of $\{\hat{\theta}\}$ such that $\{\hat{\theta}_s\}$ are its first $J_s$ elements, and note that we deal with the central point $\hat{\theta}^{(0)}$ separately. We estimate the covariances $\mathrm{Cov}_q(\mathcal{G}_n, \mathcal{G}_n)$ and $\mathrm{Cov}_q(\theta_{n}, \mathcal{G}_n)$ from the successful ensemble,

\[ \tag{1} \mathrm{Cov}_q(\theta_n, \mathcal{G}_n) \approx \sum_{j=1}^{J_s}w_{s,j} (\hat{\theta}_{s, n}^{(j)} - \bar{\theta}_{s,n})(\mathcal{G}(\hat{\theta}_{s, n}^{(j)}) - \bar{\mathcal{G}}_{s,n})^T,\]

\[ \tag{2} \mathrm{Cov}_q(\mathcal{G}_n, \mathcal{G}_n) \approx \sum_{j=1}^{J_s}w_{s,j} (\mathcal{G}(\hat{\theta}_{s, n}^{(j)}) - \bar{\mathcal{G}}_{s,n})(\mathcal{G}(\hat{\theta}_{s, n}^{(j)}) - \bar{\mathcal{G}}_{s,n})^T,\]

where the weights at each successful sigma point are scaled up, to preserve the sum of weights,

\[ w_{s,j} = \left(\dfrac{\sum_{i=1}^{2p} w_i}{\sum_{k=1}^{J_s} w_k}\right)w_j.\]

In equations (1) and (2), the means $\bar{\theta}_{s,n}$ and $\bar{\mathcal{G}}_{s,n}$ must be modified from the original formulation if the central point $\hat{\theta}^{(0)}=m_n$ results in model failure. If this is the case, then an average is taken across the other (successful) ensemble members

\[ \bar{\theta}_{s,n} = \dfrac{1}{J_s}\sum_{j=1}^{J_s}\hat{\theta}_{s, n}^{(j)}, \qquad \bar{\mathcal{G}}_{s,n} = -\dfrac{1}{J_s}\sum_{j=1}^{J_s}\mathcal{G}(\hat{\theta}_{s, n}^{(j)}).\]

+\dfrac{1}{J_s}\sum_{j=1}^{J_s}\mathcal{G}(\hat{\theta}_{s, n}^{(j)}).\]