Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
a8f228d
First commit of the "Get'EM Back" project!
Antoinehoff Oct 11, 2025
007a639
Merge remote-tracking branch 'origin/main' into get_em_back
Antoinehoff Oct 11, 2025
1291837
fix merge conflicts
Antoinehoff Oct 11, 2025
033255e
rename apardot output file name from "dapartdt" to "apardot"
Antoinehoff Oct 14, 2025
6cdedc0
add BC for ampere and ohm laws, fix the acquisition of apar and apard…
Antoinehoff Oct 14, 2025
0cf7fa4
typo in m0_gyroavg (.marr stayed)
Antoinehoff Oct 14, 2025
509c55b
fix host array alloc and add a boolean to check if the field is em in…
Antoinehoff Oct 14, 2025
355f6f9
add diagnostic for integrated Apar energy.
Antoinehoff Oct 15, 2025
ec3574b
Merge branch 'get_em_back' of https://github.com/ammarhakim/gkeyll in…
Antoinehoff Oct 15, 2025
d426e40
remove unused arrays
Antoinehoff Oct 15, 2025
255ac96
bufix: move the apar enery dynvec inside the if em statement.
Antoinehoff Oct 15, 2025
3be111e
kSq in the Ohm's law fem_poisson_perp solver is now updated by releas…
Antoinehoff Oct 15, 2025
5819a15
need to pass bc in the structure to do the release remake poisson per…
Antoinehoff Oct 15, 2025
952e1ee
Add 1x solvers for EM, refactor a few arrays, remove unused ones, add…
Antoinehoff Oct 17, 2025
5a45f77
Unstable: Merge remote-tracking branch 'origin/main' into get_em_back
Antoinehoff Oct 17, 2025
e2dfc0c
still unstable version but compiles.
Antoinehoff Oct 17, 2025
736260b
remove em from species and put it in the collisionless structure. Note:
Antoinehoff Oct 17, 2025
1a6cce3
Separation of the "NO_BY" and ES/EM options. collisionless_id sets no…
Antoinehoff Oct 17, 2025
b0a64aa
adapt the regression tests that were using GKYL_GK_COLLISIONLESS_ES_N…
Antoinehoff Oct 17, 2025
6edf384
reduction of t_end of this rt to make it much faster to run (4sec aga…
Antoinehoff Oct 17, 2025
c955dc8
dummy commit to connect with DR #867
Antoinehoff Oct 21, 2025
cae1c9b
add smoothing of apardot add also gyro_apardot (to pass it to the spe…
Antoinehoff Oct 23, 2025
b469f26
add all the empty kernels.
Antoinehoff Oct 23, 2025
8631c32
I think we have every declaration of every add_em + no_by now 🤪
Antoinehoff Oct 23, 2025
06a2b88
reorganize how the kernel are declared, first all the electrostatic s…
Antoinehoff Oct 24, 2025
66f0ff3
the empty kernels to add EM are now connected to the GK updater. The …
Antoinehoff Oct 24, 2025
ef755a8
Merge remote-tracking branch 'origin/main' into get_em_back
Antoinehoff Oct 24, 2025
3504b47
fix a bug introduced by the merge
Antoinehoff Oct 24, 2025
4f6805f
bugfix: m0 moment of species was allocated twice
Antoinehoff Oct 24, 2025
26e1383
add empty dg_gk em kernels
Antoinehoff Oct 27, 2025
bf31f29
replace phi and dualcurlbhatoverB by apar and apardot
Antoinehoff Oct 27, 2025
3fe8d4e
this is a chunky commit but it looks like it works in the electrostat…
Antoinehoff Nov 5, 2025
0a145a3
Merge remote-tracking branch 'origin/main' into get_em_back 😮‍💨
Antoinehoff Nov 5, 2025
70bcd7e
microfix of a bug that occured during the merge of main
Antoinehoff Nov 5, 2025
fcf2904
manualy port the collisionless_id and use it to decide if we add apar…
Antoinehoff Nov 6, 2025
5df88fc
remove unused zero surf vpar kernel and adjust logic between EM and E…
Antoinehoff Nov 6, 2025
37799cb
Simplification of the field enum table. We do not set if we have ES o…
Antoinehoff Nov 6, 2025
4435311
Add a field_id to activate EM effects regardless of a possible EM spe…
Antoinehoff Nov 6, 2025
5989b56
need to add a EM_IWL field_id too
Antoinehoff Nov 6, 2025
9e35f23
forgot to connect ampere bc input with the field initialization.
Antoinehoff Nov 6, 2025
46ccfb5
Split the collisionless flux kernels between electrostatic (es) and e…
Antoinehoff Nov 6, 2025
bc0b6d6
restore the config and mkdeps
Antoinehoff Nov 6, 2025
07f4f6b
Merge remote-tracking branch 'origin/main' into get_em_back
Antoinehoff Nov 7, 2025
7eb79c3
Clean a bit the interface with return 0 kernels
Antoinehoff Nov 7, 2025
314530e
fix an error were apardot was expanded on bP and not bC
Antoinehoff Nov 7, 2025
a37c075
the d3d rt gk 2x2v test is running with the EM activated now 🥁 It doe…
Antoinehoff Nov 7, 2025
3ad12af
Merge remote-tracking branch 'origin/main' into get_em_back
Antoinehoff Nov 7, 2025
99e785f
always init m1 moment because we want to use it even if we do not set…
Antoinehoff Nov 7, 2025
a6e7cfb
fix the output of Apar and Apardot, we still have to figure how to ha…
Antoinehoff Nov 8, 2025
a644c6f
Rstore the GKYL_GK_FIELD_ES_IWL enum because GKYL_GK_FIELD_ES is not …
Antoinehoff Nov 10, 2025
e1009f9
Include the new GKYL_GK_FIELD_ES_IWL to the logic in field.c and upda…
Antoinehoff Nov 10, 2025
1fd7b56
add a new regression test for alfven wave that tries to imitate the g…
Antoinehoff Nov 11, 2025
2ad20e5
this commit is shady but it has ideas on how to step Apar correctly
Antoinehoff Nov 12, 2025
0892043
a 1/J factor was missing in the kernel, the e_3mag is now computed us…
Antoinehoff Nov 13, 2025
99a4183
Merge branch 'get_em_back' of https://github.com/ammarhakim/gkeyll in…
Antoinehoff Nov 13, 2025
ef81b69
introduce apar_curr which is the current RK stage version of apar and…
Antoinehoff Nov 13, 2025
846f63f
typo in the new signature of the euler stepping method
Antoinehoff Nov 13, 2025
5293f64
remove a debugging clear line
Antoinehoff Nov 13, 2025
b49ebf8
The kinetic alfven wave test is almost working but the frequency of t…
Antoinehoff Nov 14, 2025
38ffe42
the alfven test is still producing the wrong physics but it can do it…
Antoinehoff Nov 14, 2025
5b8708d
It is always one typo away 🤪 alfven rt test now retrieves the correct…
Antoinehoff Nov 14, 2025
7b2bae3
The weak division memory was not released properly for Ohm's law in 1x
Antoinehoff Dec 1, 2025
be8cb11
put the correct q profile (it was the PT discharge not the NT one bef…
Antoinehoff Dec 2, 2025
4490d73
a 1/2 factor is missing in the computation of the electrostatic energ…
Antoinehoff Dec 2, 2025
3f3a56b
add diagnostics for energy stored in Aparallel and its time derivativ…
Antoinehoff Dec 2, 2025
5f1f9da
We accumulate the helmholtz constant for the Ohm solve just before so…
Antoinehoff Dec 8, 2025
ea23578
apar_curr is now allocated as a normal gkyl array and we copy the cur…
Antoinehoff Dec 8, 2025
3346a44
clean unused code. This code can retrieve the frequencies measured in…
Antoinehoff Dec 8, 2025
04b132a
update alfven wave reg test. This commit is multi GPU compute-sanitiz…
Antoinehoff Dec 8, 2025
331ec9f
reduction of the rt alfven 1x2v frame number to 1
Antoinehoff Dec 8, 2025
1d15fd8
Reorganize the allocation for cdim>1 and use gk_field_copy_range to u…
Antoinehoff Dec 8, 2025
4d65045
Bug fix: the new metric variables used in 2x2v EM kernels were not se…
Antoinehoff Dec 9, 2025
0e511ca
indent correctly some lines for readability (I know this is already r…
Antoinehoff Dec 9, 2025
12f34ff
ampere bc are now overwritten by periodicity as for the es field.
Antoinehoff Dec 9, 2025
52ee2a0
the definition of the lapWeightAmpere was not compatible with higher …
Antoinehoff Dec 10, 2025
31218d9
add regression test for alfven wave 2x2v
Antoinehoff Dec 10, 2025
72d304f
This version does not work -- Merge remote-tracking branch 'origin/ma…
Antoinehoff Dec 19, 2025
1bb5cee
The EM terms are now implemented with the latest gk field refactor. 1…
Antoinehoff Dec 22, 2025
ef3930d
Merge remote-tracking branch 'origin/main' into get_em_back
Antoinehoff Dec 22, 2025
3d1ecbd
EM function pointers were not activated correctly in gk_field_1x afte…
Antoinehoff Dec 22, 2025
0189c18
caught a sign error in the setting of Ohm's law for 2x2v
Antoinehoff Dec 22, 2025
abe304b
update alfven 2x2v regression test
Antoinehoff Dec 22, 2025
b911193
EM frames wirting disapeared during the merge with main
Antoinehoff Dec 22, 2025
b3dccac
remove unused global current density array release in gk_field_fem_re…
Antoinehoff Dec 23, 2025
4bde80a
🐛🪤 found a bug where apar was passed instead of apardot in the collis…
Antoinehoff Dec 24, 2025
f18632c
update documentation for gkyl_gk_collisionless_flux_new to clarify th…
Antoinehoff Dec 24, 2025
545b397
create function to pointer to enable or not the twist-and-shift appli…
Antoinehoff Dec 26, 2025
a3beade
put back the new multiplier for CFL rate in gk_species_get_cfl_dynami…
Antoinehoff Dec 26, 2025
c4724b6
remove unused gkcls->apar and apardot arrays.
Antoinehoff Dec 26, 2025
f96b303
remove the "es" in the electrostatic kernel naming to ease comparison…
Antoinehoff Dec 26, 2025
66b6702
finish the removal of GKYL_GK_COLLISIONLESS_ES_NO_BY and replace by a…
Antoinehoff Dec 26, 2025
2f312d6
remove one indentation to reduce the number of changed lines and ease…
Antoinehoff Dec 26, 2025
4b30097
Add em extension to the naming of the copy and combine field method t…
Antoinehoff Dec 26, 2025
90d7150
Remove unused apar_fem array
Antoinehoff Dec 26, 2025
0a1fbad
correct logic for IWL EM
Antoinehoff Dec 26, 2025
b048256
make sure that apar is acquired also when there is no collisionless t…
Antoinehoff Dec 26, 2025
652c4b7
remove obsolete comment
Antoinehoff Dec 26, 2025
de94c1e
🔥🐛🔥 the 2x2v flux surf y kernels were chosen in the 3x2v case....
Antoinehoff Dec 26, 2025
1addd80
I don't know if it's needed but I find it scary to manipulate unalloc…
Antoinehoff Dec 26, 2025
5eb7799
Remove unused variable declaration in the electrostatic case.
Antoinehoff Dec 26, 2025
a5236a4
We now smooth aparout which is apardot used to setp apar so that apar…
Antoinehoff Dec 29, 2025
7eec0e6
the smoothing of apar here is a bad idea as it messes up with the 1x …
Antoinehoff Dec 29, 2025
bf10790
Add the 3x2v alfven regression test
Antoinehoff Feb 9, 2026
41d8875
Remove empty lines
Antoinehoff Feb 10, 2026
8528c0b
update calculation of alphavpar in the 1x1v case according to the lat…
Antoinehoff Feb 10, 2026
2c4a660
indentation fix
Antoinehoff Feb 10, 2026
00f1192
Benign bug fix. The conditions on colless_type was badly written. Thi…
Antoinehoff Feb 11, 2026
6ead1c6
Following the last commit, add extra parenthesis in logic to ensure t…
Antoinehoff Feb 11, 2026
7b819c0
remove unused kernel
Antoinehoff Feb 12, 2026
ac10eb7
remove unused return zero vpar kernel and handle improve spacing
Antoinehoff Feb 12, 2026
0c48925
small bug fix of the collisionless type
Antoinehoff Feb 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions core/zero/gkyl_eqn_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@ enum gkyl_eqn_type {

// Identifiers for specific gyrokinetic field object types.
enum gkyl_gkfield_id {
GKYL_GK_FIELD_ES = 0, // Electrostatic GK. This is default.
GKYL_GK_FIELD = 0, // This is default.
GKYL_GK_FIELD_BOLTZMANN = 1, // GK Boltzmann, isothermal electrons, phi = phi_sheath + (T_e/e)*ln(n_i/n_is).
GKYL_GK_FIELD_ADIABATIC = 2, // GK field with an adiabatic species.
GKYL_GK_FIELD_ES_IWL = 3, // Inner-wall limited ES.
GKYL_GK_FIELD_EM = 4, // Electromagnetic GK.
GKYL_GK_FIELD_IWL = 3, // Inner-wall limited.
GKYL_GK_FIELD_ES = 4, // Electrostatic field.
GKYL_GK_FIELD_ES_IWL = 5, // Electromagnetic field with inner-wall limited BCs.
GKYL_GK_FIELD_EM = 6, // To force electromagnetic field solve (even if no species is EM).
GKYL_GK_FIELD_EM_IWL = 7, // As above but for IWL.
};

// Identifiers for specific field object types.
Expand Down Expand Up @@ -177,7 +180,6 @@ enum gkyl_gk_anomalous_diff_id {
enum gkyl_gk_collisionless_type {
GKYL_GK_COLLISIONLESS_NONE = 0, // Turns off collisionless terms.
GKYL_GK_COLLISIONLESS_ES, // Electrostatic.
GKYL_GK_COLLISIONLESS_ES_NO_BY, // Electrostatic, w/o toroidal field (b_y=0).
GKYL_GK_COLLISIONLESS_EM_BPERP, // Electromagnetic with B_perp fluctuations.
GKYL_GK_COLLISIONLESS_EM_BPAR, // Electromagnetic with B_par fluctuations.
GKYL_GK_COLLISIONLESS_EM, // Electromagnetic with B_perp and B_par fluctuations.
Expand Down
275 changes: 272 additions & 3 deletions gyrokinetic/apps/gk_field.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,19 @@ gk_field_calc_energy_dt_active(gkyl_gyrokinetic_app *app, const struct gk_field
app->stat.phidot_tm += gkyl_time_diff_now_sec(wst);
}

static void
gk_field_calc_apar_energy_dt_active(gkyl_gyrokinetic_app *app, const struct gk_field *field, double dt, double *energy_reduced)
{
struct timespec wst = gkyl_wall_clock();
gkyl_array_integrate_advance(field->calc_em_energy, field->apar,
1.0/dt, field->apar_energy_fac, &app->local, &app->local, energy_reduced);
app->stat.phidot_tm += gkyl_time_diff_now_sec(wst);
}

static void
gk_field_calc_energy_dt_none(gkyl_gyrokinetic_app *app, const struct gk_field *field, double dt, double *energy_reduced)
{
// Do nothing.
}

static void
Expand Down Expand Up @@ -122,6 +132,67 @@ gk_field_calc_energy_enabled(struct gkyl_gyrokinetic_app *app, const struct gk_f

gkyl_dynvec_append(field->integ_energy_dot, tm, energy_dot_global);
}

if (field->is_em) {
// Calculate Aparallel energy.
gkyl_array_integrate_advance(field->calc_em_energy, field->apar,
1.0, field->apar_energy_fac, &app->local, &app->local, field->em_energy_red);

gkyl_comm_allreduce(app->comm, GKYL_DOUBLE, GKYL_SUM, 1, field->em_energy_red, field->em_energy_red_global);

double energy_global[1] = { 0.0 };
if (app->use_gpu)
gkyl_cu_memcpy(energy_global, field->em_energy_red_global, sizeof(double[1]), GKYL_CU_MEMCPY_D2H);
else
energy_global[0] = field->em_energy_red_global[0];

if (app->cdim == 1)
energy_global[0] *= field->apar_energy_fac_1d;

gkyl_dynvec_append(field->integ_apar_energy, tm, energy_global);

// Calculate d(Aparallel)/dt energy.
gkyl_array_integrate_advance(field->calc_em_energy, field->apardot,
1.0, field->apar_energy_fac, &app->local, &app->local, field->em_energy_red);

gkyl_comm_allreduce(app->comm, GKYL_DOUBLE, GKYL_SUM, 1, field->em_energy_red, field->em_energy_red_global);

double energy_dot_global[1] = { 0.0 };
if (app->use_gpu)
gkyl_cu_memcpy(energy_dot_global, field->em_energy_red_global, sizeof(double[1]), GKYL_CU_MEMCPY_D2H);
else
energy_dot_global[0] = field->em_energy_red_global[0];

// if (app->cdim == 1)
// energy_dot_global[0] *= field->apar_energy_fac_1d;

gkyl_dynvec_append(field->integ_apardot_energy, tm, energy_dot_global);

if (field->info.time_rate_diagnostics) {
gkyl_comm_allreduce(app->comm, GKYL_DOUBLE, GKYL_SUM, 1, field->apar_energy_red_old, field->em_energy_red_global);
double energy_dot_global_old[1] = { 0.0 };
if (app->use_gpu)
gkyl_cu_memcpy(energy_dot_global_old, field->em_energy_red_global, sizeof(double[1]), GKYL_CU_MEMCPY_D2H);
else
energy_dot_global_old[0] = field->em_energy_red_global[0];
if (app->cdim == 1)
energy_dot_global_old[0] *= field->apar_energy_fac_1d;

gkyl_comm_allreduce(app->comm, GKYL_DOUBLE, GKYL_SUM, 1, field->apar_energy_red_new, field->em_energy_red_global);
double energy_dot_global_new[1] = { 0.0 };
if (app->use_gpu)
gkyl_cu_memcpy(energy_dot_global_new, field->em_energy_red_global, sizeof(double[1]), GKYL_CU_MEMCPY_D2H);
else
energy_dot_global_new[0] = field->em_energy_red_global[0];
if (app->cdim == 1)
energy_dot_global_new[0] *= field->apar_energy_fac_1d;

double energy_dot_global[1] = { 0.0 };
energy_dot_global[0] = energy_dot_global_new[0] - energy_dot_global_old[0];

gkyl_dynvec_append(field->integ_apar_energy_dot, tm, energy_dot_global);
}
}
}

static void
Expand All @@ -130,6 +201,52 @@ gk_field_calc_energy_disabled(struct gkyl_gyrokinetic_app *app, const struct gk_
// Do nothing.
}

static void
gk_field_combine_enabled(struct gkyl_array *out, double c1,
const struct gkyl_array *arr1, double c2, const struct gkyl_array *arr2,
const struct gkyl_range *rng)
{
gkyl_array_accumulate_range(gkyl_array_set_range(out, c1, arr1, rng),
c2, arr2, rng);
}

static void
gk_field_combine_disabled(struct gkyl_array *out, double c1,
const struct gkyl_array *arr1, double c2, const struct gkyl_array *arr2,
const struct gkyl_range *rng)
{
// Do nothing.
}

static void
gk_field_step_apar_enabled(gkyl_gyrokinetic_app *app, struct gk_field *field, struct gkyl_array* out, double dt,
const struct gkyl_array* inp)
{
// Apar^{n+1} = Apar^{n} + dt*dApar/dt
gkyl_array_accumulate(gkyl_array_scale(out, dt), 1.0, inp);
}

static void
gk_field_step_apar_disabled(gkyl_gyrokinetic_app *app, struct gk_field *field, struct gkyl_array* out, double dt,
const struct gkyl_array* inp)
{
// Do nothing.
}

static void
gk_field_copy_range_enabled(struct gkyl_array *out,
const struct gkyl_array *inp, const struct gkyl_range *range)
{
gkyl_array_copy_range(out, inp, range);
}

static void
gk_field_copy_range_disabled(struct gkyl_array *out,
const struct gkyl_array *inp, const struct gkyl_range *range)
{
// Do nothing.
}

static void
gk_field_time_rate_diags_new(struct gkyl_gyrokinetic_app *app, struct gk_field *f)
{
Expand All @@ -147,6 +264,22 @@ gk_field_time_rate_diags_new(struct gkyl_gyrokinetic_app *app, struct gk_field *
}
f->integ_energy_dot = gkyl_dynvec_new(GKYL_DOUBLE, 1);
f->is_first_energy_dot_write_call = true;
if (f->is_em){
f->calc_apar_energy_dt_func = gk_field_calc_apar_energy_dt_active;
if (app->use_gpu) {
f->apar_energy_red_new = gkyl_cu_malloc(sizeof(double[1]));
f->apar_energy_red_old = gkyl_cu_malloc(sizeof(double[1]));
gkyl_cu_memset(f->apar_energy_red_new, 0, sizeof(double[1]));
gkyl_cu_memset(f->apar_energy_red_old, 0, sizeof(double[1]));
} else {
f->apar_energy_red_new = gkyl_malloc(sizeof(double[1]));
f->apar_energy_red_old = gkyl_malloc(sizeof(double[1]));
memset(f->apar_energy_red_new, 0, sizeof(double[1]));
memset(f->apar_energy_red_old, 0, sizeof(double[1]));
}
f->integ_apar_energy_dot = gkyl_dynvec_new(GKYL_DOUBLE, 1);
}
f->is_first_apar_energy_dot_write_call = true;
}

static void
Expand All @@ -165,15 +298,22 @@ gk_field_energy_new(struct gkyl_gyrokinetic_app *app, struct gk_field *f)
f->is_first_energy_write_call = true;

f->calc_energy_func = gk_field_calc_energy_enabled;

f->calc_energy_dt_func = gk_field_calc_energy_dt_none;

if (f->info.time_rate_diagnostics) {
f->calc_apar_energy_dt_func = gk_field_calc_energy_dt_none;
if (f->info.time_rate_diagnostics)
gk_field_time_rate_diags_new(app, f);
}

// Factors for ES energy.
f->es_energy_fac = mkarr(app->use_gpu, (2*(app->cdim/3)+1)*app->basis.num_basis, app->local_ext.volume);
f->es_energy_fac_1d = 0.0;

if (f->is_em) {
f->integ_apar_energy = gkyl_dynvec_new(GKYL_DOUBLE, 1);
f->integ_apardot_energy = gkyl_dynvec_new(GKYL_DOUBLE, 1);
f->apar_energy_fac = mkarr(app->use_gpu, (2*(app->cdim/3)+1)*app->basis.num_basis, app->local_ext.volume);
f->apar_energy_fac_1d = 0;
}
}

static void
Expand All @@ -188,6 +328,16 @@ gk_field_time_rate_diags_release(const struct gkyl_gyrokinetic_app *app, struct
gkyl_free(f->em_energy_red_old);
}
gkyl_dynvec_release(f->integ_energy_dot);
if (f->is_em) {
if (app->use_gpu) {
gkyl_cu_free(f->apar_energy_red_new);
gkyl_cu_free(f->apar_energy_red_old);
} else {
gkyl_free(f->apar_energy_red_new);
gkyl_free(f->apar_energy_red_old);
}
gkyl_dynvec_release(f->integ_apar_energy_dot);
}
}

static void
Expand All @@ -208,6 +358,12 @@ gk_field_energy_release(const struct gkyl_gyrokinetic_app *app, struct gk_field
}

gkyl_array_release(f->es_energy_fac);

if (f->is_em) {
gkyl_dynvec_release(f->integ_apar_energy);
gkyl_dynvec_release(f->integ_apardot_energy);
gkyl_array_release(f->apar_energy_fac);
}
}

// Related to enforcing parallel Vlasov boundary conditions
Expand All @@ -226,6 +382,25 @@ gk_field_new(struct gkyl_gk *gk, struct gkyl_gyrokinetic_app *app)
f->info = gk->field;

f->gkfield_id = f->info.gkfield_id ? f->info.gkfield_id : GKYL_GK_FIELD_ES;

f->is_em = f->info.gkfield_id == GKYL_GK_FIELD_EM || f->info.gkfield_id == GKYL_GK_FIELD_EM_IWL;
// Ensure that if any species is electromagnetic, the field is electromagnetic.
for (int i=0; i<app->num_species; ++i) {
struct gk_species *s = &app->species[i];
f->is_em = f->is_em || (s->info.collisionless.type == GKYL_GK_COLLISIONLESS_EM) ||
(s->info.collisionless.type == GKYL_GK_COLLISIONLESS_EM_BPERP) ||
(s->info.collisionless.type == GKYL_GK_COLLISIONLESS_EM_BPAR);
}
if (f->is_em) {
assert(f->info.mu0 > 0.0);
f->step_apar = gk_field_step_apar_enabled;
f->em_combine_func = gk_field_combine_enabled;
f->em_copy_func = gk_field_copy_range_enabled;
} else {
f->step_apar = gk_field_step_apar_disabled;
f->em_combine_func = gk_field_combine_disabled;
f->em_copy_func = gk_field_copy_range_disabled;
}

f->calc_init_field = !f->info.zero_init_field;
f->update_field = !f->info.is_static;
Expand Down Expand Up @@ -269,6 +444,46 @@ gk_field_rhs(gkyl_gyrokinetic_app *app, struct gk_field *field)
app->stat.field_phi_solve_tm += gkyl_time_diff_now_sec(wst);
}

void
gk_field_em_rhs(gkyl_gyrokinetic_app *app, struct gk_field *field, const struct gkyl_array *f_in[], struct gkyl_array *rhs_in[])
{
// Compute Apardot through Ohm's law.
struct timespec wst = gkyl_wall_clock();
field->em_rhs_func(app, field, f_in, rhs_in);
app->stat.field_tm += gkyl_time_diff_now_sec(wst);
}

void gk_field_calc_apar_ic(gkyl_gyrokinetic_app *app, struct gk_field *field)
{
struct timespec wst = gkyl_wall_clock();
field->ampere_solve(app, field);
// Smooth Apar after solving Ampere's law.
gk_field_fem_projection_par(app, field, field->apar, field->apar);
app->stat.field_apar_solve_tm += gkyl_time_diff_now_sec(wst);
}

void gk_field_step_apar(gkyl_gyrokinetic_app *app, struct gk_field *field, struct gkyl_array* out, double a, const struct gkyl_array* inp)
{
struct timespec wst = gkyl_wall_clock();
field->step_apar(app, field, out, a, inp);
app->stat.field_apar_solve_tm += gkyl_time_diff_now_sec(wst);
}

void
gk_field_em_combine(struct gk_field *field, struct gkyl_array *out, double c1,
const struct gkyl_array *arr1, double c2, const struct gkyl_array *arr2,
const struct gkyl_range *rng)
{
field->em_combine_func(out, c1, arr1, c2, arr2, rng);
}

void
gk_field_em_copy_range(struct gk_field *field, struct gkyl_array *out,
const struct gkyl_array *inp, const struct gkyl_range *range)
{
field->em_copy_func(out, inp, range);
}

void
gk_field_calc_energy(gkyl_gyrokinetic_app *app, double tm, const struct gk_field *field)
{
Expand All @@ -283,6 +498,12 @@ gk_field_calc_energy_dt(gkyl_gyrokinetic_app *app, const struct gk_field *field,
field->calc_energy_dt_func(app, field, dt, energy_reduced);
}

void
gk_field_calc_apar_energy_dt(gkyl_gyrokinetic_app *app, const struct gk_field *field, double dt, double *energy_reduced)
{
field->calc_apar_energy_dt_func(app, field, dt, energy_reduced);
}

void gk_field_accumulate_rho_c_adiabatic(gkyl_gyrokinetic_app *app, struct gk_field *field, struct gk_species *s, struct gkyl_array **bflux)
{
// Gyroaverage the density if needed.
Expand Down Expand Up @@ -316,6 +537,54 @@ gk_field_accumulate_rho_c(gkyl_gyrokinetic_app *app, struct gk_field *field,
app->stat.field_phi_rhs_tm += gkyl_time_diff_now_sec(wst);
}

void
gk_field_accumulate_current_dens(gkyl_gyrokinetic_app *app, struct gk_field *field,
const struct gkyl_array *fin[])
{
struct timespec wst = gkyl_wall_clock();
gkyl_array_clear(field->currentDens, 0.0);
for (int i=0; i<app->num_species; ++i) {
struct gk_species *s = &app->species[i];
gk_species_moment_calc(&s->m1, s->local, app->local, fin[i]);
gkyl_array_accumulate_range(field->currentDens, s->info.charge, s->m1.marr, &app->local);
}
app->stat.field_apar_rhs_tm += gkyl_time_diff_now_sec(wst);
}

void
gk_field_accumulate_current_dens_dot(gkyl_gyrokinetic_app *app, struct gk_field *field,
struct gkyl_array *rhs_in[])
{
struct timespec wst = gkyl_wall_clock();
gkyl_array_clear(field->currentDensdot, 0.0);
for (int i=0; i<app->num_species; ++i) {
struct gk_species *s = &app->species[i];

gk_species_moment_calc(&s->m1, s->local, app->local, rhs_in[i]);

gkyl_array_accumulate_range(field->currentDensdot, s->info.charge, s->m1.marr, &app->local);
}
app->stat.field_apar_rhs_tm += gkyl_time_diff_now_sec(wst);
}

void
gk_field_accumulate_ohms_kSq(gkyl_gyrokinetic_app *app, struct gk_field *field,
const struct gkyl_array *fin[])
{
struct timespec wst = gkyl_wall_clock();
gkyl_array_clear(field->dApartdtSlvr_kSq, 0.0);
for (int i=0; i<app->num_species; ++i) {
struct gk_species *s = &app->species[i];
gk_species_moment_calc(&s->m0, s->local, app->local, fin[i]);
// Gyroaverage the density if needed.
s->gyroaverage(app, s, s->m0.marr, s->m0_gyroavg);
// Use m0 to update also update the kSq matrix for the Ohm's law solver.
double fac = -s->info.charge*s->info.charge/s->info.mass;
gkyl_array_accumulate_range(field->dApartdtSlvr_kSq, fac, s->m0_gyroavg, &app->local);
}
app->stat.field_apar_rhs_tm += gkyl_time_diff_now_sec(wst);
}

void
gk_field_fem_projection_par(gkyl_gyrokinetic_app *app, struct gk_field *field, struct gkyl_array *arr_dg, struct gkyl_array *arr_fem)
{
Expand Down
Loading