Skip to content

Commit 856404f

Browse files
committed
Add run_initial_ensemble
1 parent 3c73712 commit 856404f

File tree

1 file changed

+91
-1
lines changed

1 file changed

+91
-1
lines changed

src/ekp_interface.jl

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import EnsembleKalmanProcesses.TOMLInterface as TI
88

99
export get_prior, initialize, update_ensemble, save_G_ensemble
1010
export path_to_ensemble_member,
11-
path_to_model_log, path_to_iteration, parameter_path, load_latest_ekp
11+
path_to_model_log,
12+
path_to_iteration,
13+
parameter_path,
14+
load_latest_ekp,
15+
run_initial_ensemble
1216

1317
"""
1418
load_ekp_struct(output_dir, iteration)
@@ -308,6 +312,92 @@ function save_eki_and_parameters(eki, output_dir, iteration, prior)
308312
JLD2.save_object(ekp_path(output_dir, iteration), eki)
309313
end
310314

315+
"""
316+
run_initial_ensemble(
317+
backend::AbstractBackend,
318+
process::EKP.Process,
319+
prior::PD.ParameterDistribution,
320+
output_dir;
321+
ensemble_size = 0,
322+
rng = MersenneTwister(1234),
323+
run_forward_models_kwargs = (),
324+
)
325+
326+
Run the initial ensemble without needing the `EKP.EnsembleKalmanProcess`
327+
object and return the unconstrained parameters of the ensemble.
328+
329+
This is useful if the observations depend on the grid resolution of the
330+
simulation data as the first ensemble can be ran, the observations can be
331+
generated, and the `EKP.EnsembleKalmanProcess` object can be created afterward.
332+
333+
Depending on the `process`, the ensemble size will automatically be determined
334+
(e.g. `EKP.Unscented` or `EKP.TransformUnscented`).
335+
336+
Any keyword arguments that need to be passed to run the forward models can be
337+
passed to `run_forward_models_kwargs`. These keyword arguments are the same as
338+
the keyword arguments passed to `ClimaCalibrate.calibrate`.
339+
340+
!!! warning "Passing initial ensemble to EKP constructor"
341+
If the process is `EKP.Unscented` or `EKP.TransformUnscented`, you should
342+
not pass it to the `EnsembleKalmanProcess` constructor. Otherwise, you
343+
should pass the initial ensemble to the `EnsembleKalmanProcess` constructor.
344+
If you do not, the calibration results may be incorrect.
345+
"""
346+
function run_initial_ensemble( # TODO: Maybe move this to backends?
347+
backend,
348+
process::EKP.Process,
349+
prior::PD.ParameterDistribution,
350+
output_dir;
351+
ensemble_size = 0,
352+
rng = Random.MersenneTwister(1234),
353+
run_forward_models_kwargs = (),
354+
)
355+
# Cannot use last_completed_iteration because the JLD2 files storing the
356+
# G ensemble object and the ekp objects will never exist when calling this
357+
# function
358+
iter0_path = joinpath(output_dir, "iteration_000")
359+
if isdir(iter0_path)
360+
@info "Detected first iteration. Not running the initial ensemble. If this is not the case, then delete the directory $iter0_path."
361+
end
362+
363+
initial_ensemble = _construct_intial_unconstrained_ensemble(
364+
process,
365+
prior,
366+
ensemble_size = ensemble_size,
367+
rng = rng,
368+
)
369+
370+
# The size of initial_ensemble is (number of parameters, ensemble members)
371+
# For some processes, the ensemble_size is ignored
372+
ensemble_size = last(size(initial_ensemble))
373+
374+
param_dict = get_param_dict(prior)
375+
TI.save_parameter_ensemble(
376+
initial_ensemble,
377+
prior,
378+
param_dict,
379+
output_dir,
380+
DEFAULT_PARAMETER_FILE,
381+
0,
382+
)
383+
384+
# Cannot save eki object because the goal of this function is to be able
385+
# to run the first ensemble without the eki object
386+
JLD2.save_object(
387+
joinpath(path_to_iteration(output_dir, 0), "prior.jld2"),
388+
prior,
389+
)
390+
391+
run_forward_models(
392+
backend,
393+
0,
394+
ensemble_size;
395+
output_dir = output_dir,
396+
run_forward_models_kwargs...,
397+
)
398+
return initial_ensemble
399+
end
400+
311401
"""
312402
_construct_intial_unconstrained_ensemble(
313403
process::EKP.Process,

0 commit comments

Comments
 (0)