@@ -8,7 +8,11 @@ import EnsembleKalmanProcesses.TOMLInterface as TI
88
99export get_prior, initialize, update_ensemble, save_G_ensemble
1010export 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)
309313end
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