@@ -29,14 +29,10 @@ Base.@kwdef struct NektarDriftwaveModelParameters{S <: Real, T <: Real}
29
29
nektar_bin_directory:: String = " "
30
30
" Path to directory containing DriftWaveSolver binary"
31
31
driftwave_solver_bin_directory:: String = " "
32
- " Hasegawa-Wakatani system parameter α"
32
+ " Hasegawa-Wakatani system parameter α - adiabiacity operator "
33
33
alpha:: S = 2.
34
- " Hasegawa-Wakatani system parameter κ"
34
+ " Hasegawa-Wakatani system parameter κ - background density gradient scale-length "
35
35
kappa:: S = 1.
36
- " Lengthscale parameter for bump function used for initial field means"
37
- s:: S = 2.
38
- " Lengthscale parameter for state noise in dynamics and initialisation"
39
- lambda:: S = 0.1
40
36
" Number of quadrilateral elements along each axis in mesh"
41
37
mesh_dims:: Vector{Int} = [32 , 32 ]
42
38
" Size (extents) of rectangular spatial domain mesh is defined on"
@@ -52,13 +48,19 @@ Base.@kwdef struct NektarDriftwaveModelParameters{S <: Real, T <: Real}
52
48
collect, vec (collect (Iterators. product (- 10. :10. :10. , - 10. :10. :10. )))
53
49
)
54
50
" Which of field variables are observed (subset of {phi, zeta, n})"
55
- observed_variables:: Vector{String} = [" phi" ]
56
- " Output scale parameter for initial state field Gaussian process"
57
- initial_state_scale:: Union{S, Vector{S}} = 0.05
58
- " Output scale parameter for additive state noise fields Gaussian process"
59
- state_noise_scale:: Union{S, Vector{S}} = 0.05
51
+ observed_variables:: Vector{String} = [" zeta" ]
60
52
" Scale parameter (standard deviation) of independent Gaussian noise in observations"
61
- observation_noise_std:: Union{T, Vector{T}} = 0.1
53
+ observation_noise_std:: T = 0.1
54
+ " Length scale parameter for Gaussian random fields used for state noise and initialisation"
55
+ state_grf_length_scale:: S = 1.
56
+ " Positive integer smoothness parameter for Gaussian random fields used for state noise and initialisation"
57
+ state_grf_smoothness:: Int = 2
58
+ " Output scale parameter for initial state Gaussian random field"
59
+ initial_state_grf_output_scale:: S = 0.05
60
+ " Output scale parameter for additive state noise Gaussian random field"
61
+ state_noise_grf_output_scale:: S = 0.05
62
+ " Length scale parameter for bump functions used for initial state field means"
63
+ initial_state_mean_length_scale:: S = 2.
62
64
end
63
65
64
66
function get_params (
@@ -305,7 +307,6 @@ function make_driftwave_conditions_file(output_path, previous_state_path, parame
305
307
parameters= (;
306
308
NumSteps = parameters. num_steps_per_observation_time,
307
309
TimeStep = parameters. time_step,
308
- s = parameters. s,
309
310
kappa = parameters. kappa,
310
311
alpha = parameters. alpha,
311
312
IO_InfoSteps = 0 ,
@@ -321,26 +322,21 @@ function make_driftwave_conditions_file(output_path, previous_state_path, parame
321
322
)
322
323
end
323
324
324
- function make_grf_conditions_file (output_path, parameters)
325
+ function make_helmholtz_conditions_file (output_path, forcing_field_path , parameters)
325
326
variables = [" u" ]
327
+ forcing_field_definition = (
328
+ isnothing (forcing_field_path)
329
+ ? ExpressionFieldDefinition (only (variables), " awgn(1)" )
330
+ : FileFieldDefinition (only (variables), forcing_field_path)
331
+ )
326
332
make_nektar_conditions_file (
327
333
output_path,
328
334
variables= variables,
329
335
num_modes= parameters. num_modes,
330
- solver_properties= (;
331
- EQTYPE = " Helmholtz" ,
332
- Projection = " DisContinuous" ,
333
- ),
334
- parameters= (;
335
- lambda = parameters. lambda,
336
- ),
336
+ solver_properties= (; EQTYPE = " Helmholtz" , Projection = " Continuous" ),
337
+ parameters= (; lambda = 1 / parameters. state_grf_length_scale^ 2 ),
337
338
boundary_conditions= periodic_boundary_conditions (variables),
338
- functions= [
339
- FieldFunction (
340
- " Forcing" ,
341
- [ExpressionFieldDefinition (join (variables, " ," ), " awgn(1)" )]
342
- )
343
- ]
339
+ functions= [FieldFunction (" Forcing" , [forcing_field_definition])]
344
340
)
345
341
end
346
342
@@ -351,16 +347,12 @@ function make_poisson_conditions_file(output_path, forcing_field_path, parameter
351
347
output_path,
352
348
variables= variables,
353
349
num_modes= parameters. num_modes,
354
- solver_properties= (;
355
- EQTYPE = " Poisson" ,
356
- Projection = " Continuous" ,
357
- ),
350
+ solver_properties= (; EQTYPE = " Poisson" , Projection = " Continuous" ),
358
351
parameters= (;),
359
352
boundary_conditions= periodic_boundary_conditions (variables),
360
353
functions= [
361
354
FieldFunction (
362
- " Forcing" ,
363
- [FileFieldDefinition (join (variables, " ," ), forcing_field_path)]
355
+ " Forcing" , [FileFieldDefinition (only (variables), forcing_field_path)]
364
356
)
365
357
]
366
358
)
@@ -385,13 +377,15 @@ end
385
377
struct NektarConditionsFilePaths
386
378
driftwave:: String
387
379
grf:: String
380
+ grf_recursion:: String
388
381
poisson:: String
389
382
end
390
383
391
384
function NektarConditionsFilePaths (parent_directory:: String )
392
385
return NektarConditionsFilePaths (
393
386
joinpath (parent_directory, " driftwave.xml" ),
394
387
joinpath (parent_directory, " grf.xml" ),
388
+ joinpath (parent_directory, " grf_recursion.xml" ),
395
389
joinpath (parent_directory, " poisson.xml" )
396
390
)
397
391
end
@@ -422,14 +416,26 @@ end
422
416
function generate_gaussian_random_field_file (model, task_index, variable, noise_scale, mean_expression= nothing )
423
417
conditions_file_paths = model. task_conditions_file_paths[task_index]
424
418
grf_field_file_path = get_field_file_path (conditions_file_paths. grf)
419
+ grf_recursion_field_file_path = get_field_file_path (conditions_file_paths. grf_recursion)
425
420
variable_field_path = joinpath (model. task_working_directories[task_index], " $(variable) .fld" )
421
+ # Whittle-Matérn Gaussian random field variance for spatial dimension 2 is
422
+ # Γ(ν) / (Γ(ν + 1) * κ^2ν * 4π) = 1 / (ν * κ^2ν * 4π)
423
+ # Therefore multiply noise_scale by sqrt(ν * κ^2ν * 4π) so that noise_scale = 1
424
+ # corresponds to unit variance
425
+ ν = model. parameters. state_grf_smoothness * 2 - 1
426
+ κ = 1 / model. parameters. state_grf_length_scale
427
+ noise_scale *= sqrt (ν * κ^ 2 ν * 4 π)
426
428
if isnothing (mean_expression)
427
429
field_expression_string = " $(noise_scale) * u"
428
430
else
429
431
field_expression_string = " $(mean_expression) + $(noise_scale) * u"
430
432
end
431
433
cd (model. task_working_directories[task_index]) do
432
434
run (` $(model. executable_paths. adr_solver) -f -i Hdf5 $(conditions_file_paths. grf) $(model. mesh_file_paths. no_expansions) ` )
435
+ for i in 1 : (model. parameters. state_grf_smoothness - 1 )
436
+ run (` $(model. executable_paths. adr_solver) -f -i Hdf5 $(conditions_file_paths. grf_recursion) $(model. mesh_file_paths. no_expansions) ` )
437
+ mv (grf_recursion_field_file_path, grf_field_file_path; force= true )
438
+ end
433
439
run (` $(model. executable_paths. field_convert) -f -m fieldfromstring:fieldstr="$(field_expression_string) ":fieldname="$(variable) " $(model. mesh_file_paths. with_expansions) $(grf_field_file_path) $(variable_field_path) :fld:format=Hdf5` )
434
440
run (` $(model. executable_paths. field_convert) -f -m removefield:fieldname="u" $(model. mesh_file_paths. with_expansions) $(variable_field_path) $(variable_field_path) :fld:format=Hdf5` )
435
441
end
@@ -514,8 +520,10 @@ function init(
514
520
for (task_working_directory, conditions_file_paths) in zip (task_working_directories, task_conditions_file_paths)
515
521
mkdir (task_working_directory)
516
522
driftwave_field_file_path = get_field_file_path (conditions_file_paths. driftwave)
523
+ grf_field_file_path = get_field_file_path (conditions_file_paths. grf)
517
524
make_driftwave_conditions_file (conditions_file_paths. driftwave, driftwave_field_file_path, parameters)
518
- make_grf_conditions_file (conditions_file_paths. grf, parameters)
525
+ make_helmholtz_conditions_file (conditions_file_paths. grf, nothing , parameters)
526
+ make_helmholtz_conditions_file (conditions_file_paths. grf_recursion, grf_field_file_path, parameters)
519
527
make_poisson_conditions_file (conditions_file_paths. poisson, " $(driftwave_field_file_path) :zeta" , parameters)
520
528
end
521
529
observation_dimension = length (parameters. observed_points)
@@ -552,13 +560,14 @@ function ParticleDA.sample_initial_state!(
552
560
) where {S, T}
553
561
conditions_file_paths = model. task_conditions_file_paths[task_index]
554
562
driftwave_field_file_path = get_field_file_path (conditions_file_paths. driftwave)
563
+ s = model. parameters. initial_state_mean_length_scale
555
564
variable_mean_expressions = [
556
- " zeta" => " 4*exp((-x*x-y*y)/($(model . parameters . s^ 2 ) ))*(-$(model . parameters . s^ 2 ) +x*x+y*y)/$(model . parameters . s^ 4 ) " ,
557
- " n" => " exp((-x*x-y*y)/$(model . parameters . s^ 2 ) )" ,
565
+ " zeta" => " 4*exp((-x*x-y*y)/($(s^ 2 ) ))*(-$(s^ 2 ) +x*x+y*y)/$(s^ 4 ) " ,
566
+ " n" => " exp((-x*x-y*y)/$(s^ 2 ) )" ,
558
567
]
559
568
variable_field_file_paths = [
560
569
generate_gaussian_random_field_file (
561
- model, task_index, variable, model. parameters. initial_state_scale , mean_expression
570
+ model, task_index, variable, model. parameters. initial_state_grf_output_scale , mean_expression
562
571
)
563
572
for (variable, mean_expression) in variable_mean_expressions
564
573
]
@@ -594,7 +603,7 @@ function ParticleDA.update_state_stochastic!(
594
603
write_state_to_field_file (driftwave_field_file_path, state)
595
604
variable_field_file_paths = [
596
605
generate_gaussian_random_field_file (
597
- model, task_index, variable, model. parameters. state_noise_scale
606
+ model, task_index, variable, model. parameters. state_noise_grf_output_scale
598
607
)
599
608
for variable in [" zeta" , " n" ]
600
609
]
0 commit comments