From 7a87e593c0af73963b820b3de3a9f28adccafb2f Mon Sep 17 00:00:00 2001
From: Antoine Hoffmann <antoine.hoffmann@epfl.ch>
Date: Wed, 20 Jul 2022 10:09:51 +0200
Subject: [PATCH] added EM effects (psi and ampere), not verified

---
 Makefile                   |  60 ++++++++-------
 matlab/setup.m             |   1 +
 matlab/write_fort90.m      |   5 +-
 src/array_mod.F90          |   4 +-
 src/diagnose.F90           |   2 +
 src/fields_mod.F90         |   3 +
 src/ghosts_mod.F90         |  82 +++++++++++++++++++--
 src/grid_mod.F90           |  46 ++++++++----
 src/inital.F90             |  42 +++++------
 src/memory.F90             |   8 ++
 src/model_mod.F90          |  17 ++++-
 src/moments_eq_rhs_mod.F90 |  39 +++++++---
 src/numerics_mod.F90       |  97 +++++++++++++++++++++++-
 src/poisson.F90            |  78 --------------------
 src/processing_mod.F90     |  11 ++-
 src/solve_EM_fields.F90    | 147 +++++++++++++++++++++++++++++++++++++
 src/stepon.F90             |  16 ++--
 wk/analysis_HeLaZ.m        |  26 +++----
 wk/analysis_gene.m         |   8 +-
 wk/header_3D_results.m     |  12 ++-
 wk/quick_run.m             |  27 +++----
 21 files changed, 523 insertions(+), 208 deletions(-)
 delete mode 100644 src/poisson.F90
 create mode 100644 src/solve_EM_fields.F90

diff --git a/Makefile b/Makefile
index 80ae8671..9112278d 100644
--- a/Makefile
+++ b/Makefile
@@ -61,16 +61,18 @@ mvmod:
 
 $(OBJDIR)/diagnose.o : src/srcinfo.h
 
-FOBJ=$(OBJDIR)/advance_field.o $(OBJDIR)/array_mod.o $(OBJDIR)/auxval.o $(OBJDIR)/basic_mod.o \
-$(OBJDIR)/coeff_mod.o $(OBJDIR)/closure_mod.o $(OBJDIR)/collision_mod.o \
-$(OBJDIR)/nonlinear_mod.o $(OBJDIR)/control.o $(OBJDIR)/fourier_mod.o \
-$(OBJDIR)/diagnose.o $(OBJDIR)/diagnostics_par_mod.o $(OBJDIR)/endrun.o $(OBJDIR)/fields_mod.o \
-$(OBJDIR)/inital.o $(OBJDIR)/initial_par_mod.o $(OBJDIR)/geometry_mod.o \
-$(OBJDIR)/main.o $(OBJDIR)/memory.o $(OBJDIR)/model_mod.o $(OBJDIR)/moments_eq_rhs_mod.o \
-$(OBJDIR)/numerics_mod.o $(OBJDIR)/poisson.o $(OBJDIR)/ppexit.o $(OBJDIR)/ppinit.o $(OBJDIR)/prec_const_mod.o \
-$(OBJDIR)/parallel_mod.o $(OBJDIR)/processing_mod.o $(OBJDIR)/readinputs.o $(OBJDIR)/ghosts_mod.o $(OBJDIR)/grid_mod.o \
-$(OBJDIR)/restarts_mod.o $(OBJDIR)/stepon.o $(OBJDIR)/tesend.o $(OBJDIR)/time_integration_mod.o \
-$(OBJDIR)/utility_mod.o
+FOBJ=$(OBJDIR)/advance_field.o $(OBJDIR)/array_mod.o $(OBJDIR)/auxval.o \
+$(OBJDIR)/basic_mod.o $(OBJDIR)/coeff_mod.o $(OBJDIR)/closure_mod.o \
+$(OBJDIR)/collision_mod.o $(OBJDIR)/nonlinear_mod.o $(OBJDIR)/control.o \
+$(OBJDIR)/diagnose.o $(OBJDIR)/diagnostics_par_mod.o $(OBJDIR)/endrun.o \
+$(OBJDIR)/fields_mod.o $(OBJDIR)/fourier_mod.o $(OBJDIR)/geometry_mod.o \
+$(OBJDIR)/ghosts_mod.o $(OBJDIR)/grid_mod.o $(OBJDIR)/inital.o \
+$(OBJDIR)/initial_par_mod.o $(OBJDIR)/main.o $(OBJDIR)/memory.o \
+$(OBJDIR)/model_mod.o $(OBJDIR)/moments_eq_rhs_mod.o $(OBJDIR)/numerics_mod.o \
+$(OBJDIR)/parallel_mod.o  $(OBJDIR)/ppexit.o $(OBJDIR)/ppinit.o \
+$(OBJDIR)/prec_const_mod.o $(OBJDIR)/processing_mod.o $(OBJDIR)/readinputs.o \
+$(OBJDIR)/restarts_mod.o $(OBJDIR)/solve_EM_fields.o $(OBJDIR)/stepon.o \
+$(OBJDIR)/tesend.o $(OBJDIR)/time_integration_mod.o $(OBJDIR)/utility_mod.o
 
  $(EXEC): $(FOBJ)
 	$(F90) $(LDFLAGS) $(OBJDIR)/*.o $(EXTMOD) $(EXTINC) $(EXTLIBS) -o $@
@@ -82,7 +84,7 @@ $(OBJDIR)/utility_mod.o
 	$(F90) $(LDFLAGS) $(OBJDIR)/*.o $(EXTMOD) $(EXTINC) $(EXTLIBS) -o $@
 
  $(OBJDIR)/advance_field.o : src/advance_field.F90 $(OBJDIR)/grid_mod.o $(OBJDIR)/array_mod.o \
-   $(OBJDIR)/initial_par_mod.o $(OBJDIR)/prec_const_mod.o $(OBJDIR)/time_integration_mod.o \
+	 $(OBJDIR)/initial_par_mod.o $(OBJDIR)/prec_const_mod.o $(OBJDIR)/time_integration_mod.o \
 	 $(OBJDIR)/basic_mod.o $(OBJDIR)/fields_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/advance_field.F90 -o $@
 
@@ -114,11 +116,6 @@ $(OBJDIR)/utility_mod.o
 	 $(OBJDIR)/time_integration_mod.o $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/collision_mod.F90 -o $@
 
- $(OBJDIR)/nonlinear_mod.o : src/nonlinear_mod.F90 $(OBJDIR)/array_mod.o $(OBJDIR)/basic_mod.o \
-   $(OBJDIR)/fourier_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/grid_mod.o $(OBJDIR)/model_mod.o\
-	 $(OBJDIR)/prec_const_mod.o $(OBJDIR)/time_integration_mod.o
-	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/nonlinear_mod.F90 -o $@
-
  $(OBJDIR)/control.o : src/control.F90 $(OBJDIR)/auxval.o $(OBJDIR)/geometry_mod.o \
    $(OBJDIR)/prec_const_mod.o $(OBJDIR)/basic_mod.o $(OBJDIR)/ppexit.o $(OBJDIR)/ppinit.o \
 	 $(OBJDIR)/readinputs.o $(OBJDIR)/tesend.o
@@ -149,7 +146,7 @@ $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/geometry_mod.F90 -o $@
 
  $(OBJDIR)/ghosts_mod.o : src/ghosts_mod.F90 $(OBJDIR)/basic_mod.o $(OBJDIR)/fields_mod.o \
-   $(OBJDIR)/grid_mod.o $(OBJDIR)/ppinit.o  $(OBJDIR)/time_integration_mod.o
+   $(OBJDIR)/grid_mod.o $(OBJDIR)/geometry_mod.o $(OBJDIR)/ppinit.o  $(OBJDIR)/time_integration_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/ghosts_mod.F90 -o $@
 
  $(OBJDIR)/grid_mod.o : src/grid_mod.F90 $(OBJDIR)/basic_mod.o $(OBJDIR)/model_mod.o\
@@ -157,7 +154,9 @@ $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/grid_mod.F90 -o $@
 
  $(OBJDIR)/inital.o : src/inital.F90 $(OBJDIR)/array_mod.o $(OBJDIR)/basic_mod.o \
-   $(OBJDIR)/fields_mod.o $(OBJDIR)/initial_par_mod.o $(OBJDIR)/model_mod.o $(OBJDIR)/numerics_mod.o $(OBJDIR)/poisson.o $(OBJDIR)/prec_const_mod.o $(OBJDIR)/ghosts_mod.o $(OBJDIR)/grid_mod.o $(OBJDIR)/restarts_mod.o $(OBJDIR)/time_integration_mod.o $(OBJDIR)/utility_mod.o
+   $(OBJDIR)/fields_mod.o $(OBJDIR)/initial_par_mod.o $(OBJDIR)/model_mod.o $(OBJDIR)/numerics_mod.o \
+	 $(OBJDIR)/solve_EM_fields.o $(OBJDIR)/prec_const_mod.o $(OBJDIR)/ghosts_mod.o $(OBJDIR)/grid_mod.o \
+	 $(OBJDIR)/restarts_mod.o $(OBJDIR)/time_integration_mod.o $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/inital.F90 -o $@
 
  $(OBJDIR)/initial_par_mod.o : src/initial_par_mod.F90 $(OBJDIR)/basic_mod.o \
@@ -176,18 +175,19 @@ $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/model_mod.F90 -o $@
 
  $(OBJDIR)/moments_eq_rhs_mod.o : src/moments_eq_rhs_mod.F90 $(OBJDIR)/array_mod.o \
-   $(OBJDIR)/calculus_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/prec_const_mod.o $(OBJDIR)/grid_mod.o $(OBJDIR)/model_mod.o $(OBJDIR)/time_integration_mod.o
+   $(OBJDIR)/calculus_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/prec_const_mod.o $(OBJDIR)/grid_mod.o \
+	 $(OBJDIR)/model_mod.o $(OBJDIR)/time_integration_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/moments_eq_rhs_mod.F90 -o $@
 
+ $(OBJDIR)/nonlinear_mod.o : src/nonlinear_mod.F90 $(OBJDIR)/array_mod.o $(OBJDIR)/basic_mod.o \
+	 $(OBJDIR)/fourier_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/grid_mod.o $(OBJDIR)/model_mod.o\
+	 $(OBJDIR)/prec_const_mod.o $(OBJDIR)/time_integration_mod.o
+	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/nonlinear_mod.F90 -o $@
+
  $(OBJDIR)/numerics_mod.o : src/numerics_mod.F90 $(OBJDIR)/prec_const_mod.o $(OBJDIR)/basic_mod.o \
   $(OBJDIR)/coeff_mod.o $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/numerics_mod.F90 -o $@
 
- $(OBJDIR)/poisson.o : src/poisson.F90 $(OBJDIR)/array_mod.o $(OBJDIR)/prec_const_mod.o \
-  $(OBJDIR)/grid_mod.o $(OBJDIR)/ghosts_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/array_mod.o \
-	$(OBJDIR)/time_integration_mod.o $(OBJDIR)/basic_mod.o $(OBJDIR)/parallel_mod.o
-	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/poisson.F90 -o $@
-
  $(OBJDIR)/parallel_mod.o : src/parallel_mod.F90 $(OBJDIR)/basic_mod.o $(OBJDIR)/prec_const_mod.o \
    $(OBJDIR)/grid_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/parallel_mod.F90 -o $@
@@ -213,11 +213,19 @@ $(OBJDIR)/utility_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/readinputs.F90 -o $@
 
  $(OBJDIR)/restarts_mod.o : src/restarts_mod.F90  $(OBJDIR)/diagnostics_par_mod.o \
-   $(OBJDIR)/grid_mod.o $(OBJDIR)/time_integration_mod.o
+	 $(OBJDIR)/grid_mod.o $(OBJDIR)/time_integration_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/restarts_mod.F90 -o $@
 
+ $(OBJDIR)/solve_EM_fields.o : src/solve_EM_fields.F90 $(OBJDIR)/array_mod.o $(OBJDIR)/prec_const_mod.o \
+	 $(OBJDIR)/grid_mod.o $(OBJDIR)/ghosts_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/array_mod.o \
+	 $(OBJDIR)/time_integration_mod.o $(OBJDIR)/basic_mod.o $(OBJDIR)/parallel_mod.o
+	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/solve_EM_fields.F90 -o $@
+
  $(OBJDIR)/stepon.o : src/stepon.F90 $(OBJDIR)/initial_par_mod.o $(OBJDIR)/prec_const_mod.o \
-   $(OBJDIR)/advance_field.o $(OBJDIR)/basic_mod.o $(OBJDIR)/nonlinear_mod.o $(OBJDIR)/grid_mod.o $(OBJDIR)/array_mod.o $(OBJDIR)/numerics_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/ghosts_mod.o $(OBJDIR)/moments_eq_rhs_mod.o $(OBJDIR)/poisson.o $(OBJDIR)/time_integration_mod.o $(OBJDIR)/utility_mod.o $(OBJDIR)/model_mod.o
+   $(OBJDIR)/advance_field.o $(OBJDIR)/basic_mod.o $(OBJDIR)/nonlinear_mod.o $(OBJDIR)/grid_mod.o \
+	 $(OBJDIR)/array_mod.o $(OBJDIR)/numerics_mod.o $(OBJDIR)/fields_mod.o $(OBJDIR)/ghosts_mod.o \
+	 $(OBJDIR)/moments_eq_rhs_mod.o $(OBJDIR)/solve_EM_fields.o $(OBJDIR)/time_integration_mod.o \
+	 $(OBJDIR)/utility_mod.o $(OBJDIR)/model_mod.o
 	$(F90) -c $(F90FLAGS) $(FPPFLAGS) $(EXTMOD) $(EXTINC) src/stepon.F90 -o $@
 
  $(OBJDIR)/tesend.o : src/tesend.F90 $(OBJDIR)/basic_mod.o $(OBJDIR)/prec_const_mod.o
diff --git a/matlab/setup.m b/matlab/setup.m
index 6288c1de..6228cac6 100644
--- a/matlab/setup.m
+++ b/matlab/setup.m
@@ -23,6 +23,7 @@ MODEL.NL_CLOS = NL_CLOS;
 MODEL.LINEARITY = ['''',LINEARITY,''''];
 MODEL.KIN_E   = KIN_E;
 if KIN_E; MODEL.KIN_E = '.true.'; else; MODEL.KIN_E = '.false.';end;
+MODEL.beta    = BETA;
 MODEL.mu_x    = MU_X;
 MODEL.mu_y    = MU_Y;
 MODEL.N_HD    = N_HD;
diff --git a/matlab/write_fort90.m b/matlab/write_fort90.m
index 17838bc3..90dee735 100644
--- a/matlab/write_fort90.m
+++ b/matlab/write_fort90.m
@@ -71,9 +71,10 @@ fprintf(fid,['  q_i     = ', num2str(MODEL.q_i),'\n']);
 fprintf(fid,['  K_n     = ', num2str(MODEL.K_n),'\n']);
 fprintf(fid,['  K_T     = ', num2str(MODEL.K_T),'\n']);
 fprintf(fid,['  K_E     = ', num2str(MODEL.K_E),'\n']);
-fprintf(fid,['  GradB     = ', num2str(MODEL.GradB),'\n']);
-fprintf(fid,['  CurvB     = ', num2str(MODEL.CurvB),'\n']);
+fprintf(fid,['  GradB   = ', num2str(MODEL.GradB),'\n']);
+fprintf(fid,['  CurvB   = ', num2str(MODEL.CurvB),'\n']);
 fprintf(fid,['  lambdaD = ', num2str(MODEL.lambdaD),'\n']);
+fprintf(fid,['  beta    = ', num2str(MODEL.beta),'\n']);
 fprintf(fid,'/\n');
 
 fprintf(fid,'&COLLISION_PAR\n');
diff --git a/src/array_mod.F90 b/src/array_mod.F90
index 2db05d5e..8cb3a2ef 100644
--- a/src/array_mod.F90
+++ b/src/array_mod.F90
@@ -56,13 +56,15 @@ MODULE array
   REAL(dp), DIMENSION(:,:), ALLOCATABLE :: zNipm1j, zNipm1jp1, zNipm1jm1            ! mirror lin coeff for adiab mom
   REAL(dp), DIMENSION(:,:), ALLOCATABLE :: xphij_e, xphijp1_e, xphijm1_e
   REAL(dp), DIMENSION(:,:), ALLOCATABLE :: xphij_i, xphijp1_i, xphijm1_i
-
+  REAL(dp), DIMENSION(:,:), ALLOCATABLE :: xpsij_e, xpsijp1_e, xpsijm1_e
+  REAL(dp), DIMENSION(:,:), ALLOCATABLE :: xpsij_i, xpsijp1_i, xpsijm1_i
   ! Kernel function evaluation (ij,ikx,iky,iz,odd/even p)
   REAL(dp), DIMENSION(:,:,:,:,:), ALLOCATABLE :: kernel_e
   REAL(dp), DIMENSION(:,:,:,:,:), ALLOCATABLE :: kernel_i
 
   ! Poisson operator (ikx,iky,iz)
   REAL(dp), DIMENSION(:,:,:), ALLOCATABLE :: inv_poisson_op
+  REAL(dp), DIMENSION(:,:,:), ALLOCATABLE :: inv_ampere_op
   REAL(dp), DIMENSION(:,:,:), ALLOCATABLE :: inv_pol_ion
   REAL(dp), DIMENSION(:,:,:), ALLOCATABLE :: HF_phi_correction_operator
 
diff --git a/src/diagnose.F90 b/src/diagnose.F90
index 50a0042b..5df1f8c0 100644
--- a/src/diagnose.F90
+++ b/src/diagnose.F90
@@ -209,6 +209,7 @@ SUBROUTINE diagnose_full(kstep)
      CALL creatd(fidres, rank, dims, "/data/var3d/cstep", "iteration number")
 
      IF (write_phi) CALL creatg(fidres, "/data/var3d/phi", "phi")
+     IF (write_phi) CALL creatg(fidres, "/data/var3d/psi", "psi")
 
      IF (write_Na00) THEN
       IF(KIN_E)&
@@ -405,6 +406,7 @@ SUBROUTINE diagnose_3d
   CALL attach(fidres,"/data/var3d/" , "frames", iframe3d)
 
   IF (write_phi) CALL write_field3d_kykxz(phi (ikys:ikye,ikxs:ikxe,izs:ize), 'phi')
+  IF (write_phi) CALL write_field3d_kykxz(psi (ikys:ikye,ikxs:ikxe,izs:ize), 'psi')
 
   IF (write_Na00) THEN
     IF(KIN_E)THEN
diff --git a/src/fields_mod.F90 b/src/fields_mod.F90
index eac8c04f..728b9fdb 100644
--- a/src/fields_mod.F90
+++ b/src/fields_mod.F90
@@ -12,4 +12,7 @@ MODULE fields
   ! Normalized electric potential: \hat{\phi} ! (kx,ky,z)
   COMPLEX(dp), DIMENSION(:,:,:), ALLOCATABLE :: phi
 
+!------------------Vector field part
+  COMPLEX(dp), DIMENSION(:,:,:), ALLOCATABLE :: psi
+
 END MODULE fields
diff --git a/src/ghosts_mod.F90 b/src/ghosts_mod.F90
index 2fa4bc65..1121680a 100644
--- a/src/ghosts_mod.F90
+++ b/src/ghosts_mod.F90
@@ -1,15 +1,14 @@
 module ghosts
 USE basic
-USE fields, ONLY : moments_e, moments_i, phi
 USE grid
 USE time_integration
-USE model, ONLY : KIN_E
+USE model, ONLY : KIN_E, beta
 USE geometry, ONLY : SHEARED, ikx_zBC_L, ikx_zBC_R
 IMPLICIT NONE
 
 INTEGER :: status(MPI_STATUS_SIZE), source, dest, count, ipg
 
-PUBLIC :: update_ghosts_moments, update_ghosts_phi
+PUBLIC :: update_ghosts_moments, update_ghosts_EM
 
 CONTAINS
 
@@ -31,15 +30,19 @@ SUBROUTINE update_ghosts_moments
   tc_ghost = tc_ghost + (t1_ghost - t0_ghost)
 END SUBROUTINE update_ghosts_moments
 
-SUBROUTINE update_ghosts_phi
+SUBROUTINE update_ghosts_EM
   CALL cpu_time(t0_ghost)
 
   IF(Nz .GT. 1) THEN
     CALL update_ghosts_z_phi
+
+    IF(beta .GT. 0._dp) &
+      CALL update_ghosts_z_psi
   ENDIF
 
   tc_ghost = tc_ghost + (t1_ghost - t0_ghost)
-END SUBROUTINE update_ghosts_phi
+END SUBROUTINE update_ghosts_EM
+
 
 !Communicate p+1, p+2 moments to left neighboor and p-1, p-2 moments to right one
 ! [a b|C D|e f] : proc n has moments a to f where a,b,e,f are ghosts
@@ -54,7 +57,7 @@ END SUBROUTINE update_ghosts_phi
 !                                                   ^  ^
 !Closure by zero truncation :                       0  0
 SUBROUTINE update_ghosts_p_e
-
+    USE fields, ONLY : moments_e
     IMPLICIT NONE
 
     count = (ijge_e-ijgs_e+1)*(ikye-ikys+1)*(ikxe-ikxs+1)*(izge-izgs+1)
@@ -82,7 +85,7 @@ END SUBROUTINE update_ghosts_p_e
 
 !Communicate p+1, p+2 moments to left neighboor and p-1, p-2 moments to right one
 SUBROUTINE update_ghosts_p_i
-
+  USE fields, ONLY : moments_i
     IMPLICIT NONE
 
     count = (ijge_i-ijgs_i+1)*(ikye-ikys+1)*(ikxe-ikxs+1)*(izge-izgs+1) ! Number of elements sent
@@ -121,6 +124,7 @@ END SUBROUTINE update_ghosts_p_i
 !Periodic:                                          0  1
 SUBROUTINE update_ghosts_z_e
   USE parallel, ONLY : buff_pjxy_zBC_e
+  USE fields, ONLY : moments_e
   IMPLICIT NONE
   INTEGER :: ikxBC_L, ikxBC_R
   IF(Nz .GT. 1) THEN
@@ -178,6 +182,7 @@ END SUBROUTINE update_ghosts_z_e
 
 SUBROUTINE update_ghosts_z_i
   USE parallel, ONLY : buff_pjxy_zBC_i
+  USE fields, ONLY : moments_i
   IMPLICIT NONE
   INTEGER :: ikxBC_L, ikxBC_R
   IF(Nz .GT. 1) THEN
@@ -235,6 +240,7 @@ END SUBROUTINE update_ghosts_z_i
 
 SUBROUTINE update_ghosts_z_phi
   USE parallel, ONLY : buff_xy_zBC
+  USE fields,   ONLY : phi
   IMPLICIT NONE
   INTEGER :: ikxBC_L, ikxBC_R
   CALL cpu_time(t1_ghost)
@@ -294,5 +300,67 @@ SUBROUTINE update_ghosts_z_phi
   tc_ghost = tc_ghost + (t1_ghost - t0_ghost)
 END SUBROUTINE update_ghosts_z_phi
 
+SUBROUTINE update_ghosts_z_psi
+  USE parallel, ONLY : buff_xy_zBC
+  USE fields, ONLY : psi
+  IMPLICIT NONE
+  INTEGER :: ikxBC_L, ikxBC_R
+  CALL cpu_time(t1_ghost)
+  IF(Nz .GT. 1) THEN
+    IF (num_procs_z .GT. 1) THEN
+      CALL MPI_BARRIER(MPI_COMM_WORLD,ierr)
+        count = (ikye-ikys+1) * (ikxe-ikxs+1)
+        !!!!!!!!!!! Send ghost to up neighbour !!!!!!!!!!!!!!!!!!!!!!
+        CALL mpi_sendrecv(     psi(:,:,ize  ), count, MPI_DOUBLE_COMPLEX, nbr_U, 30, & ! Send to Up the last
+                          buff_xy_zBC(:,:,-1), count, MPI_DOUBLE_COMPLEX, nbr_D, 30, & ! Receive from Down the first-1
+                          comm0, status, ierr)
+
+        CALL mpi_sendrecv(     psi(:,:,ize-1), count, MPI_DOUBLE_COMPLEX, nbr_U, 31, & ! Send to Up the last
+                          buff_xy_zBC(:,:,-2), count, MPI_DOUBLE_COMPLEX, nbr_D, 31, & ! Receive from Down the first-2
+                          comm0, status, ierr)
+
+        !!!!!!!!!!! Send ghost to down neighbour !!!!!!!!!!!!!!!!!!!!!!
+        CALL mpi_sendrecv(     psi(:,:,izs  ), count, MPI_DOUBLE_COMPLEX, nbr_D, 32, & ! Send to Down the first
+                          buff_xy_zBC(:,:,+1), count, MPI_DOUBLE_COMPLEX, nbr_U, 32, & ! Recieve from Up the last+1
+                          comm0, status, ierr)
+
+        CALL mpi_sendrecv(     psi(:,:,izs+1), count, MPI_DOUBLE_COMPLEX, nbr_D, 33, & ! Send to Down the first
+                          buff_xy_zBC(:,:,+2), count, MPI_DOUBLE_COMPLEX, nbr_U, 33, & ! Recieve from Up the last+2
+                          comm0, status, ierr)
+     ELSE
+       buff_xy_zBC(:,:,-1) = psi(:,:,ize  )
+       buff_xy_zBC(:,:,-2) = psi(:,:,ize-1)
+       buff_xy_zBC(:,:,+1) = psi(:,:,izs  )
+       buff_xy_zBC(:,:,+2) = psi(:,:,izs+1)
+     ENDIF
+    DO iky = ikys,ikye
+      DO ikx = ikxs,ikxe
+        ikxBC_L = ikx_zBC_L(iky,ikx);
+        IF (ikxBC_L .NE. -99) THEN ! Exchanging the modes that have a periodic pair (a)
+          ! first-1 gets last
+          psi(iky,ikx,izs-1) = buff_xy_zBC(iky,ikxBC_L,-1)
+          ! first-2 gets last-1
+          psi(iky,ikx,izs-2) = buff_xy_zBC(iky,ikxBC_L,-2)
+        ELSE
+          psi(iky,ikx,izs-1) = 0._dp
+          psi(iky,ikx,izs-2) = 0._dp
+        ENDIF
+        ikxBC_R = ikx_zBC_R(iky,ikx);
+        IF (ikxBC_R .NE. -99) THEN ! Exchanging the modes that have a periodic pair (a)
+          ! last+1 gets first
+          psi(iky,ikx,ize+1) = buff_xy_zBC(iky,ikxBC_R,+1)
+          ! last+2 gets first+1
+          psi(iky,ikx,ize+2) = buff_xy_zBC(iky,ikxBC_R,+2)
+        ELSE
+          psi(iky,ikx,ize+1) = 0._dp
+          psi(iky,ikx,ize+2) = 0._dp
+        ENDIF
+      ENDDO
+    ENDDO
+  ENDIF
+  CALL cpu_time(t1_ghost)
+  tc_ghost = tc_ghost + (t1_ghost - t0_ghost)
+END SUBROUTINE update_ghosts_z_psi
+
 
 END MODULE ghosts
diff --git a/src/grid_mod.F90 b/src/grid_mod.F90
index 2120042f..a31128d0 100644
--- a/src/grid_mod.F90
+++ b/src/grid_mod.F90
@@ -99,6 +99,7 @@ MODULE grid
   LOGICAL,  PUBLIC, PROTECTED ::  CONTAINS_ip0_e, CONTAINS_ip0_i
   LOGICAL,  PUBLIC, PROTECTED ::  CONTAINS_ip1_e, CONTAINS_ip1_i
   LOGICAL,  PUBLIC, PROTECTED ::  CONTAINS_ip2_e, CONTAINS_ip2_i
+  LOGICAL,  PUBLIC, PROTECTED ::  SOLVE_POISSON, SOLVE_AMPERE
   ! Usefull inverse numbers
   REAL(dp), PUBLIC, PROTECTED :: inv_Nx, inv_Ny, inv_Nz
 
@@ -125,25 +126,14 @@ CONTAINS
                     Nx,  Lx,  Ny,  Ly, Nz, Npol, SG
     READ(lu_in,grid)
 
+    IF(Nz .EQ. 1) & ! overwrite SG option if Nz = 1 for safety of use
+      SG      = .FALSE.
+
     !! Compute the maximal degree of full GF moments set
     !   i.e. : all moments N_a^pj s.t. p+2j<=d are simulated (see GF closure)
     dmaxe = min(pmaxe,2*jmaxe+1)
     dmaxi = min(pmaxi,2*jmaxi+1)
 
-    ! If no parallel dim (Nz=1), the moment hierarchy is separable between odds and even P
-    !! and since the energy is injected in P=0 and P=2 for density/temperature gradients
-    !! there is no need of simulating the odd p which will only be damped.
-    !! We define in this case a grid Parray = 0,2,4,...,Pmax i.e. deltap = 2 instead of 1
-    !! to spare computation
-    IF(Nz .EQ. 1) THEN
-      deltape = 2; deltapi = 2;
-      pp2     = 1; ! index p+2 is ip+1
-      SG      = .FALSE.
-    ELSE
-      deltape = 1; deltapi = 1;
-      pp2     = 2; ! index p+2 is ip+1
-    ENDIF
-
     ! Usefull precomputations
     inv_Nx = 1._dp/REAL(Nx,dp)
     inv_Ny = 1._dp/REAL(Ny,dp)
@@ -160,9 +150,24 @@ CONTAINS
 
   SUBROUTINE set_pgrid
     USE prec_const
+    USE model, ONLY: beta ! To know if we solve ampere or not and put odd  p moments
     IMPLICIT NONE
     INTEGER :: ip, istart, iend, in
 
+    ! If no parallel dim (Nz=1) and no EM effects (beta=0), the moment hierarchy
+    !! is separable between odds and even P and since the energy is injected in
+    !! P=0 and P=2 for density/temperature gradients there is no need of
+    !! simulating the odd p which will only be damped.
+    !! We define in this case a grid Parray = 0,2,4,...,Pmax i.e. deltap = 2
+    !! instead of 1 to spare computation
+    IF((Nz .EQ. 1) .AND. (beta .EQ. 0._dp)) THEN
+      deltape = 2; deltapi = 2;
+      pp2     = 1; ! index p+2 is ip+1
+    ELSE
+      deltape = 1; deltapi = 1;
+      pp2     = 2; ! index p+2 is ip+2
+    ENDIF
+
     ! Total number of Hermite polynomials we will evolve
     total_np_e = (Pmaxe/deltape) + 1
     total_np_i = (Pmaxi/deltapi) + 1
@@ -204,6 +209,8 @@ CONTAINS
     CONTAINS_ip0_i = .FALSE.
     CONTAINS_ip1_i = .FALSE.
     CONTAINS_ip2_i = .FALSE.
+    SOLVE_POISSON  = .FALSE.
+    SOLVE_AMPERE   = .FALSE.
     ALLOCATE(parray_e(ipgs_e:ipge_e))
     ALLOCATE(parray_i(ipgs_i:ipge_i))
     DO ip = ipgs_e,ipge_e
@@ -212,10 +219,12 @@ CONTAINS
       IF(parray_e(ip) .EQ. 0) THEN
         ip0_e          = ip
         CONTAINS_ip0_e = .TRUE.
+        SOLVE_POISSON  = .TRUE.
       ENDIF
       IF(parray_e(ip) .EQ. 1) THEN
         ip1_e          = ip
         CONTAINS_ip1_e = .TRUE.
+        SOLVE_AMPERE   = .TRUE.
       ENDIF
       IF(parray_e(ip) .EQ. 2) THEN
         ip2_e          = ip
@@ -228,10 +237,12 @@ CONTAINS
       IF(parray_i(ip) .EQ. 0) THEN
         ip0_i          = ip
         CONTAINS_ip0_i = .TRUE.
-      ENDIF
+        SOLVE_POISSON  = .TRUE.
+    ENDIF
       IF(parray_i(ip) .EQ. 1) THEN
         ip1_i          = ip
         CONTAINS_ip1_i = .TRUE.
+        SOLVE_AMPERE   = .TRUE.
       ENDIF
       IF(parray_i(ip) .EQ. 2) THEN
         ip2_i          = ip
@@ -245,6 +256,11 @@ CONTAINS
     ! Precomputations
     pmaxe_dp   = real(pmaxe,dp)
     pmaxi_dp   = real(pmaxi,dp)
+
+    ! Overwrite SOLVE_AMPERE flag if beta is zero
+    IF(beta .EQ. 0._dp) THEN
+      SOLVE_AMPERE = .FALSE.
+    ENDIF
   END SUBROUTINE set_pgrid
 
   SUBROUTINE set_jgrid
diff --git a/src/inital.F90 b/src/inital.F90
index c692fb10..d1958e72 100644
--- a/src/inital.F90
+++ b/src/inital.F90
@@ -8,7 +8,7 @@ SUBROUTINE inital
   USE time_integration, ONLY: set_updatetlevel
   USE collision,        ONLY: load_COSOlver_mat, cosolver_coll
   USE closure,          ONLY: apply_closure_model
-  USE ghosts,           ONLY: update_ghosts_moments, update_ghosts_phi
+  USE ghosts,           ONLY: update_ghosts_moments, update_ghosts_EM
   USE restarts,         ONLY: load_moments, job2load
   USE numerics,         ONLY: play_with_modes, save_EM_ZF_modes
   USE processing,       ONLY: compute_fluid_moments
@@ -24,8 +24,8 @@ SUBROUTINE inital
     IF (my_id .EQ. 0) WRITE(*,*) 'Load moments'
     CALL load_moments ! get N_0
     CALL update_ghosts_moments
-    CALL poisson ! compute phi_0=phi(N_0)
-    CALL update_ghosts_phi
+    CALL solve_EM_fields ! compute phi_0=phi(N_0)
+    CALL update_ghosts_EM
   ! through initialization
   ELSE
     SELECT CASE (INIT_OPT)
@@ -33,35 +33,35 @@ SUBROUTINE inital
     CASE ('phi')
       IF (my_id .EQ. 0) WRITE(*,*) 'Init noisy phi'
       CALL init_phi
-      CALL update_ghosts_phi
+      CALL update_ghosts_EM
     ! set moments_00 (GC density) with noise and compute phi afterwards
     CASE('mom00')
       IF (my_id .EQ. 0) WRITE(*,*) 'Init noisy gyrocenter density'
       CALL init_gyrodens ! init only gyrocenter density
       CALL update_ghosts_moments
-      CALL poisson
-      CALL update_ghosts_phi
+      CALL solve_EM_fields
+      CALL update_ghosts_EM
     ! init all moments randomly (unadvised)
     CASE('allmom')
       IF (my_id .EQ. 0) WRITE(*,*) 'Init noisy moments'
       CALL init_moments ! init all moments
       CALL update_ghosts_moments
-      CALL poisson
-      CALL update_ghosts_phi
+      CALL solve_EM_fields
+      CALL update_ghosts_EM
     ! init a gaussian blob in gyrodens
     CASE('blob')
       IF (my_id .EQ. 0) WRITE(*,*) '--init a blob'
       CALL initialize_blob
       CALL update_ghosts_moments
-      CALL poisson
-      CALL update_ghosts_phi
+      CALL solve_EM_fields
+      CALL update_ghosts_EM
     ! init moments 00 with a power law similarly to GENE
     CASE('ppj')
       IF (my_id .EQ. 0) WRITE(*,*) 'ppj init ~ GENE'
       call init_ppj
       CALL update_ghosts_moments
-      CALL poisson
-      CALL update_ghosts_phi
+      CALL solve_EM_fields
+      CALL update_ghosts_EM
     END SELECT
   ENDIF
   ! closure of j>J, p>P and j<0, p<0 moments
@@ -70,7 +70,7 @@ SUBROUTINE inital
   ! ghosts for p parallelization
   IF (my_id .EQ. 0) WRITE(*,*) 'Ghosts communication'
   CALL update_ghosts_moments
-  CALL update_ghosts_phi
+  CALL update_ghosts_EM
   !! End of phi and moments initialization
 
   ! Save (kx,0) and (0,ky) modes for num exp
@@ -399,8 +399,8 @@ SUBROUTINE init_ppj
   REAL(dp) :: kx, ky, sigma_z, amp, ky_shift, z
   INTEGER, DIMENSION(12) :: iseedarr
 
-  sigma_z = pi/4.0
-  amp = 1e4
+  sigma_z = pi/4._dp
+  amp = 1.0_dp
 
     !**** Broad noise initialization *******************************************
     ! Electrons
@@ -418,11 +418,11 @@ SUBROUTINE init_ppj
                   IF(ky .EQ. 0) THEN
                     moments_e(ip,ij,iky,ikx,iz,:) = 0._dp
                   ELSE
-                    moments_e(ip,ij,iky,ikx,iz,:) = 0._dp!0.5_dp * ky_min/(ABS(ky)+ky_min)
+                    moments_e(ip,ij,iky,ikx,iz,:) = 0.5_dp * ky_min/(ABS(ky)+ky_min)
                   ENDIF
                 ELSE
                   IF(ky .GT. 0) THEN
-                    moments_e(ip,ij,iky,ikx,iz,:) = 0._dp!(kx_min/(ABS(kx)+kx_min))*(ky_min/(ABS(ky)+ky_min))
+                    moments_e(ip,ij,iky,ikx,iz,:) = (kx_min/(ABS(kx)+kx_min))*(ky_min/(ABS(ky)+ky_min))
                   ELSE
                     moments_e(ip,ij,iky,ikx,iz,:) = 0.5_dp*amp*(kx_min/(ABS(kx)+kx_min))
                   ENDIF
@@ -461,11 +461,11 @@ SUBROUTINE init_ppj
                   IF(ky .EQ. 0) THEN
                     moments_i(ip,ij,iky,ikx,iz,:) = 0._dp
                   ELSE
-                    moments_i(ip,ij,iky,ikx,iz,:) = 0._dp!0.5_dp * ky_min/(ABS(ky)+ky_min)
+                    moments_i(ip,ij,iky,ikx,iz,:) = 0.5_dp * ky_min/(ABS(ky)+ky_min)
                   ENDIF
                 ELSE
                   IF(ky .GT. 0) THEN
-                    moments_i(ip,ij,iky,ikx,iz,:) = 0._dp!(kx_min/(ABS(kx)+kx_min))*(ky_min/(ABS(ky)+ky_min))
+                    moments_i(ip,ij,iky,ikx,iz,:) = (kx_min/(ABS(kx)+kx_min))*(ky_min/(ABS(ky)+ky_min))
                   ELSE
                     moments_i(ip,ij,iky,ikx,iz,:) = 0.5_dp*amp*(kx_min/(ABS(kx)+kx_min))
                   ENDIF
@@ -509,9 +509,5 @@ SUBROUTINE init_ppj
       ENDDO
     ENDIF
 
-    ! Adjust the scaling to trigger faster NL saturation
-    IF(KIN_E) &
-    moments_e = 1e3*moments_e
-    moments_i = 1e3*moments_i
 END SUBROUTINE init_ppj
 !******************************************************************************!
diff --git a/src/memory.F90 b/src/memory.F90
index f39ca92d..ec0297e8 100644
--- a/src/memory.F90
+++ b/src/memory.F90
@@ -14,9 +14,11 @@ SUBROUTINE memory
 
   ! Electrostatic potential
   CALL allocate_array(           phi, ikys,ikye, ikxs,ikxe, izgs,izge)
+  CALL allocate_array(           psi, ikys,ikye, ikxs,ikxe, izgs,izge)
   CALL allocate_array(        phi_ZF, ikxs,ikxe, izs,ize)
   CALL allocate_array(        phi_EM, ikys,ikye, izs,ize)
   CALL allocate_array(inv_poisson_op, ikys,ikye, ikxs,ikxe, izs,ize)
+  CALL allocate_array( inv_ampere_op, ikys,ikye, ikxs,ikxe, izs,ize)
   CALL allocate_array(   inv_pol_ion, ikys,ikye, ikxs,ikxe, izs,ize)
   CALL allocate_array(HF_phi_correction_operator, ikys,ikye, ikxs,ikxe, izs,ize)
 
@@ -100,10 +102,16 @@ SUBROUTINE memory
     CALL allocate_array( xphij_e,   ips_e,ipe_e, ijs_e,ije_e)
     CALL allocate_array( xphijp1_e, ips_e,ipe_e, ijs_e,ije_e)
     CALL allocate_array( xphijm1_e, ips_e,ipe_e, ijs_e,ije_e)
+    CALL allocate_array( xpsij_e,   ips_e,ipe_e, ijs_e,ije_e)
+    CALL allocate_array( xpsijp1_e, ips_e,ipe_e, ijs_e,ije_e)
+    CALL allocate_array( xpsijm1_e, ips_e,ipe_e, ijs_e,ije_e)
   ENDIF
   CALL allocate_array( xphij_i,   ips_i,ipe_i, ijs_i,ije_i)
   CALL allocate_array( xphijp1_i, ips_i,ipe_i, ijs_i,ije_i)
   CALL allocate_array( xphijm1_i, ips_i,ipe_i, ijs_i,ije_i)
+  CALL allocate_array( xpsij_i,   ips_i,ipe_i, ijs_i,ije_i)
+  CALL allocate_array( xpsijp1_i, ips_i,ipe_i, ijs_i,ije_i)
+  CALL allocate_array( xpsijm1_i, ips_i,ipe_i, ijs_i,ije_i)
 
   !___________________ 2x5D ARRAYS __________________________
   !! Collision matrices
diff --git a/src/model_mod.F90 b/src/model_mod.F90
index 043c5b02..12d16a58 100644
--- a/src/model_mod.F90
+++ b/src/model_mod.F90
@@ -30,6 +30,7 @@ MODULE model
   REAL(dp), PUBLIC, PROTECTED ::   GradB =  1._dp     ! Magnetic gradient
   REAL(dp), PUBLIC, PROTECTED ::   CurvB =  1._dp     ! Magnetic curvature
   REAL(dp), PUBLIC, PROTECTED :: lambdaD =  1._dp     ! Debye length
+  REAL(dp), PUBLIC, PROTECTED ::    beta =  0._dp     ! electron plasma Beta (8piNT_e/B0^2)
 
   REAL(dp), PUBLIC, PROTECTED :: taue_qe         ! factor of the magnetic moment coupling
   REAL(dp), PUBLIC, PROTECTED :: taui_qi         !
@@ -46,24 +47,30 @@ MODULE model
   REAL(dp), PUBLIC, PROTECTED :: nu_e,  nu_i          ! electron-ion, ion-ion collision frequency
   REAL(dp), PUBLIC, PROTECTED :: nu_ee, nu_ie         ! e-e, i-e coll. frequ.
   REAL(dp), PUBLIC, PROTECTED :: qe2_taue, qi2_taui   ! factor of the gammaD sum
-
+  REAL(dp), PUBLIC, PROTECTED :: q_o_sqrt_tau_sigma_e, q_o_sqrt_tau_sigma_i
+  REAL(dp), PUBLIC, PROTECTED :: sqrt_tau_o_sigma_e, sqrt_tau_o_sigma_i
   PUBLIC :: model_readinputs, model_outputinputs
 
 CONTAINS
 
   SUBROUTINE model_readinputs
     !    Read the input parameters
-    USE basic, ONLY : lu_in
+    USE basic, ONLY : lu_in, my_id
     USE prec_const
     IMPLICIT NONE
 
     NAMELIST /MODEL_PAR/ CLOS, NL_CLOS, KERN, LINEARITY, KIN_E, &
                          mu_x, mu_y, N_HD, mu_z, mu_p, mu_j, nu,&
                          tau_e, tau_i, sigma_e, sigma_i, q_e, q_i,&
-                         K_n, K_T, K_E, GradB, CurvB, lambdaD
+                         K_n, K_T, K_E, GradB, CurvB, lambdaD, beta
 
     READ(lu_in,model_par)
 
+    IF(.NOT. KIN_E) THEN
+      IF(my_id.EQ.0) print*, 'Adiabatic electron model -> beta = 0'
+      beta = 0._dp
+    ENDIF
+
     taue_qe    = tau_e/q_e ! factor of the magnetic moment coupling
     taui_qi    = tau_i/q_i ! factor of the magnetic moment coupling
     qe_taue    = q_e/tau_e
@@ -78,6 +85,10 @@ CONTAINS
     sigmai2_taui_o2 = sigma_i**2 * tau_i/2._dp
     sqrt_sigmae2_taue_o2 = SQRT(sigma_e**2 * tau_e/2._dp) ! to avoid multiple SQRT eval
     sqrt_sigmai2_taui_o2 = SQRT(sigma_i**2 * tau_i/2._dp)
+    q_o_sqrt_tau_sigma_e = q_e/SQRT(tau_e)/sigma_e ! For psi field terms
+    q_o_sqrt_tau_sigma_i = q_i/SQRT(tau_i)/sigma_i ! For psi field terms
+    sqrt_tau_o_sigma_e   = SQRT(tau_e)/sigma_e     ! For Ampere eq
+    sqrt_tau_o_sigma_i   = SQRT(tau_i)/sigma_i
     !! We use the ion-ion collision as normalization with definition
     !   nu_ii = 4 sqrt(pi)/3 T_i^(-3/2) m_i^(-1/2) q^4 n_i0 ln(Lambda)
     !
diff --git a/src/moments_eq_rhs_mod.F90 b/src/moments_eq_rhs_mod.F90
index d6ce46df..9d1626b2 100644
--- a/src/moments_eq_rhs_mod.F90
+++ b/src/moments_eq_rhs_mod.F90
@@ -35,9 +35,9 @@ SUBROUTINE moments_eq_rhs_e
   REAL(dp)    :: kx, ky, kperp2, dzlnB_o_J
   COMPLEX(dp) :: Tnepj, Tnepp2j, Tnepm2j, Tnepjp1, Tnepjm1 ! Terms from b x gradB and drives
   COMPLEX(dp) :: Tnepp1j, Tnepm1j, Tnepp1jm1, Tnepm1jm1 ! Terms from mirror force with non adiab moments
-  COMPLEX(dp) :: Tperp, Tpar, Tmir, Tphi
+  COMPLEX(dp) :: Tperp, Tpar, Tmir, Tphi, Tpsi
   COMPLEX(dp) :: Unepm1j, Unepm1jp1, Unepm1jm1 ! Terms from mirror force with adiab moments
-  COMPLEX(dp) :: i_kx,i_ky,phikykxz
+  COMPLEX(dp) :: i_kx,i_ky,phikykxz, psikykxz
 
    ! Measuring execution time
   CALL cpu_time(t0_rhs)
@@ -52,6 +52,7 @@ SUBROUTINE moments_eq_rhs_e
         ky     = kyarray(iky)   ! toroidal wavevector
         i_ky   = imagu * ky     ! toroidal derivative
         phikykxz = phi(iky,ikx,iz)! tmp phi value
+        psikykxz = psi(iky,ikx,iz)! tmp psi value
 
         ! Kinetic loops
         jloope : DO ij = ijs_e, ije_e  ! This loop is from 1 to jmaxi+1
@@ -93,13 +94,22 @@ SUBROUTINE moments_eq_rhs_e
             Tmir = Tnepp1j + Tnepp1jm1 + Tnepm1j + Tnepm1jm1 + Unepm1j + Unepm1jp1 + Unepm1jm1
             !! Electrical potential term
             IF ( p_int .LE. 2 ) THEN ! kronecker p0 p1 p2
-              Tphi = (xphij_i  (ip,ij)*kernel_e(ij  ,iky,ikx,iz,eo) &
-                    + xphijp1_i(ip,ij)*kernel_e(ij+1,iky,ikx,iz,eo) &
-                    + xphijm1_i(ip,ij)*kernel_e(ij-1,iky,ikx,iz,eo))*phikykxz
+              Tphi = (xphij_e  (ip,ij)*kernel_e(ij  ,iky,ikx,iz,eo) &
+                    + xphijp1_e(ip,ij)*kernel_e(ij+1,iky,ikx,iz,eo) &
+                    + xphijm1_e(ip,ij)*kernel_e(ij-1,iky,ikx,iz,eo))*phikykxz
             ELSE
               Tphi = 0._dp
             ENDIF
 
+            !! Vector potential term
+            IF ( (p_int .LE. 3) .AND. (p_int .GT. 1) ) THEN ! Kronecker p1 or p3
+              Tpsi = (xpsij_e  (ip,ij)*kernel_e(ij  ,iky,ikx,iz,eo) &
+                    + xpsijp1_e(ip,ij)*kernel_e(ij+1,iky,ikx,iz,eo) &
+                    + xpsijm1_e(ip,ij)*kernel_e(ij-1,iky,ikx,iz,eo))*psikykxz
+            ELSE
+              Tpsi = 0._dp
+            ENDIF
+
             !! Sum of all RHS terms
             moments_rhs_e(ip,ij,iky,ikx,iz,updatetlevel) = &
                 ! Perpendicular magnetic gradient/curvature effects
@@ -109,7 +119,7 @@ SUBROUTINE moments_eq_rhs_e
                 ! Mirror term (parallel magnetic gradient)
                 - gradzB(iz,eo)* Tmir  *gradz_coeff(iz,eo) &
                 ! Drives (density + temperature gradients)
-                - i_ky * Tphi &
+                - i_ky * (Tphi - Tpsi) &
                 ! Numerical perpendicular hyperdiffusion (totally artificial, for stability purpose)
                 - mu_x*diff_kx_coeff*kx**N_HD*moments_e(ip,ij,iky,ikx,iz,updatetlevel) &
                 - mu_y*diff_ky_coeff*ky**N_HD*moments_e(ip,ij,iky,ikx,iz,updatetlevel) &
@@ -165,8 +175,8 @@ SUBROUTINE moments_eq_rhs_i
   COMPLEX(dp) :: Tnipj, Tnipp2j, Tnipm2j, Tnipjp1, Tnipjm1
   COMPLEX(dp) :: Tnipp1j, Tnipm1j, Tnipp1jm1, Tnipm1jm1 ! Terms from mirror force with non adiab moments
   COMPLEX(dp) :: Unipm1j, Unipm1jp1, Unipm1jm1 ! Terms from mirror force with adiab moments
-  COMPLEX(dp) :: Tperp, Tpar, Tmir, Tphi
-  COMPLEX(dp) :: i_kx, i_ky, phikykxz
+  COMPLEX(dp) :: Tperp, Tpar, Tmir, Tphi, Tpsi
+  COMPLEX(dp) :: i_kx, i_ky, phikykxz, psikykxz
 
   ! Measuring execution time
   CALL cpu_time(t0_rhs)
@@ -181,6 +191,7 @@ SUBROUTINE moments_eq_rhs_i
           ky     = kyarray(iky)   ! toroidal wavevector
           i_ky   = imagu * ky     ! toroidal derivative
           phikykxz = phi(iky,ikx,iz)! tmp phi value
+          psikykxz = psi(iky,ikx,iz)! tmp phi value
 
         ! Kinetic loops
         jloopi : DO ij = ijs_i, ije_i  ! This loop is from 1 to jmaxi+1
@@ -231,6 +242,16 @@ SUBROUTINE moments_eq_rhs_i
                 Tphi = 0._dp
               ENDIF
 
+              !! Vector potential term
+              IF ( (p_int .LE. 3) .AND. (p_int .GT. 1) ) THEN ! Kronecker p1 or p3
+                Tpsi = (xpsij_i  (ip,ij)*kernel_i(ij  ,iky,ikx,iz,eo) &
+                      + xpsijp1_i(ip,ij)*kernel_i(ij+1,iky,ikx,iz,eo) &
+                      + xpsijm1_i(ip,ij)*kernel_i(ij-1,iky,ikx,iz,eo))*psikykxz
+              ELSE
+                Tpsi = 0._dp
+              ENDIF
+
+
               !! Sum of all RHS terms
               moments_rhs_i(ip,ij,iky,ikx,iz,updatetlevel) = &
                   ! Perpendicular magnetic gradient/curvature effects
@@ -240,7 +261,7 @@ SUBROUTINE moments_eq_rhs_i
                   ! Mirror term (parallel magnetic gradient)
                   - gradzB(iz,eo) * gradz_coeff(iz,eo) * Tmir &
                   ! Drives (density + temperature gradients)
-                  - i_ky * Tphi &
+                  - i_ky * (Tphi - Tpsi) &
                   ! Numerical hyperdiffusion (totally artificial, for stability purpose)
                   - mu_x*diff_kx_coeff*kx**N_HD*moments_i(ip,ij,iky,ikx,iz,updatetlevel) &
                   - mu_y*diff_ky_coeff*ky**N_HD*moments_i(ip,ij,iky,ikx,iz,updatetlevel) &
diff --git a/src/numerics_mod.F90 b/src/numerics_mod.F90
index 833c4f68..1ede5ac6 100644
--- a/src/numerics_mod.F90
+++ b/src/numerics_mod.F90
@@ -6,8 +6,8 @@ MODULE numerics
     USE coeff
     implicit none
 
-    PUBLIC :: build_dnjs_table, evaluate_kernels, evaluate_poisson_op, compute_lin_coeff
-    PUBLIC :: play_with_modes, save_EM_ZF_modes
+    PUBLIC :: build_dnjs_table, evaluate_kernels, evaluate_poisson_op, evaluate_ampere_op
+    PUBLIC :: compute_lin_coeff, play_with_modes, save_EM_ZF_modes
 
 CONTAINS
 
@@ -151,10 +151,57 @@ SUBROUTINE evaluate_poisson_op
 END SUBROUTINE evaluate_poisson_op
 !******************************************************************************!
 
+!******************************************************************************!
+!!!!!!! Evaluate inverse polarisation operator for Poisson equation
+!******************************************************************************!
+SUBROUTINE evaluate_ampere_op
+  USE basic
+  USE array, Only : kernel_e, kernel_i, inv_ampere_op
+  USE grid
+  USE model, ONLY : tau_e, tau_i, q_e, q_i, KIN_E, beta
+  IMPLICIT NONE
+  REAL(dp)    :: pol_i, pol_e, kperp2     ! (Z_a^2/tau_a (1-sum_n kernel_na^2))
+  INTEGER     :: ini,ine
+
+  ! We do not solve Ampere if beta = 0 to spare waste of ressources
+  IF(SOLVE_AMPERE) THEN
+    ! This term has no staggered grid dependence. It is evalued for the
+    ! even z grid since poisson uses p=0 moments and phi only.
+    kxloop: DO ikx = ikxs,ikxe
+    kyloop: DO iky = ikys,ikye
+    zloop:  DO iz  = izs,ize
+    kperp2 = kparray(iky,ikx,iz,0)**2
+    IF( (kxarray(ikx).EQ.0._dp) .AND. (kyarray(iky).EQ.0._dp) ) THEN
+        inv_ampere_op(iky, ikx, iz) =  0._dp
+    ELSE
+      !!!!!!!!!!!!!!!!! Ion contribution
+      ! loop over n only if the max polynomial degree
+      pol_i = 0._dp
+      DO ini=1,jmaxi+1
+        pol_i = pol_i  + kernel_i(ini,iky,ikx,iz,0)**2 ! ... sum recursively ...
+      END DO
+      pol_i = q_i**2/(sigma_i**2) * pol_i
+      !!!!!!!!!!!!! Electron contribution
+      pol_e = 0._dp
+      ! loop over n only if the max polynomial degree
+      DO ine=1,jmaxe+1 ! ine = n+1
+        pol_e = pol_e  + kernel_e(ine,iky,ikx,iz,0)**2 ! ... sum recursively ...
+      END DO
+      pol_e = q_e**2/(sigma_e**2) * pol_e
+      inv_ampere_op(iky, ikx, iz) =  1._dp/(2._dp*kperp2 + beta*(pol_i + pol_e))
+    ENDIF
+    END DO zloop
+    END DO kyloop
+    END DO kxloop
+  ENDIF
+
+END SUBROUTINE evaluate_ampere_op
+!******************************************************************************!
+
 SUBROUTINE compute_lin_coeff
   USE array
   USE model, ONLY: taue_qe, taui_qi, sqrtTaue_qe, sqrtTaui_qi, &
-                   K_T, K_n, CurvB, GradB, KIN_E
+                   K_T, K_n, CurvB, GradB, KIN_E, tau_e, tau_i, sigma_e, sigma_i
   USE prec_const
   USE grid,  ONLY: parray_e, parray_i, jarray_e, jarray_i, &
                    ip,ij, ips_e,ipe_e, ips_i,ipe_i, ijs_e,ije_e, ijs_i,ije_i
@@ -270,7 +317,7 @@ SUBROUTINE compute_lin_coeff
       j_dp = REAL(j_int,dp) ! REALof Laguerre degree
       !! Electrostatic potential pj terms
       IF (p_int .EQ. 0) THEN ! kronecker p0
-        xphij_i(ip,ij)    =+K_n + 2.*j_dp*K_T
+        xphij_i(ip,ij)    =+K_n + 2._dp*j_dp*K_T
         xphijp1_i(ip,ij)  =-K_T*(j_dp+1._dp)
         xphijm1_i(ip,ij)  =-K_T* j_dp
       ELSE IF (p_int .EQ. 2) THEN ! kronecker p2
@@ -282,6 +329,48 @@ SUBROUTINE compute_lin_coeff
       ENDIF
     ENDDO
   ENDDO
+  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  !! EM linear coefficients for moment RHS !!!!!!!!!!
+  IF (KIN_E) THEN
+    DO ip = ips_e, ipe_e
+      p_int= parray_e(ip)   ! Hermite degree
+      DO ij = ijs_e, ije_e
+        j_int= jarray_e(ij)   ! REALof Laguerre degree
+        j_dp = REAL(j_int,dp) ! REALof Laguerre degree
+        !! Electrostatic potential pj terms
+        IF (p_int .EQ. 1) THEN ! kronecker p1
+          xpsij_e(ip,ij)    =+(K_n + (2._dp*j_dp+1._dp)*K_T) * SQRT(tau_e)/sigma_e
+          xpsijp1_e(ip,ij)  =- K_T*(j_dp+1._dp)              * SQRT(tau_e)/sigma_e
+          xpsijm1_e(ip,ij)  =- K_T* j_dp                     * SQRT(tau_e)/sigma_e
+        ELSE IF (p_int .EQ. 3) THEN ! kronecker p3
+          xpsij_e(ip,ij)    =+ K_T*SQRT3/SQRT2               * SQRT(tau_e)/sigma_e
+          xpsijp1_e(ip,ij)  = 0._dp; xpsijm1_e(ip,ij)  = 0._dp;
+        ELSE
+          xpsij_e(ip,ij)    = 0._dp; xpsijp1_e(ip,ij)  = 0._dp
+          xpsijm1_e(ip,ij)  = 0._dp;
+        ENDIF
+      ENDDO
+    ENDDO
+  ENDIF
+  DO ip = ips_i, ipe_i
+    p_int= parray_i(ip)   ! Hermite degree
+    DO ij = ijs_i, ije_i
+      j_int= jarray_i(ij)   ! REALof Laguerre degree
+      j_dp = REAL(j_int,dp) ! REALof Laguerre degree
+      !! Electrostatic potential pj terms
+      IF (p_int .EQ. 1) THEN ! kronecker p1
+        xpsij_i(ip,ij)    =+(K_n + (2._dp*j_dp+1._dp)*K_T) * SQRT(tau_i)/sigma_i
+        xpsijp1_i(ip,ij)  =- K_T*(j_dp+1._dp)              * SQRT(tau_i)/sigma_i
+        xpsijm1_i(ip,ij)  =- K_T* j_dp                     * SQRT(tau_i)/sigma_i
+      ELSE IF (p_int .EQ. 3) THEN ! kronecker p3
+        xpsij_i(ip,ij)    =+ K_T*SQRT3/SQRT2               * SQRT(tau_i)/sigma_i
+        xpsijp1_i(ip,ij)  = 0._dp; xpsijm1_i(ip,ij)  = 0._dp;
+      ELSE
+        xpsij_i(ip,ij)    = 0._dp; xpsijp1_i(ip,ij)  = 0._dp
+        xpsijm1_i(ip,ij)  = 0._dp;
+      ENDIF
+    ENDDO
+  ENDDO
 END SUBROUTINE compute_lin_coeff
 
 !******************************************************************************!
diff --git a/src/poisson.F90 b/src/poisson.F90
deleted file mode 100644
index 8b401b0c..00000000
--- a/src/poisson.F90
+++ /dev/null
@@ -1,78 +0,0 @@
-SUBROUTINE poisson
-  ! Solve poisson equation to get phi
-
-  USE basic
-  USE time_integration, ONLY: updatetlevel
-  USE array
-  USE fields
-  USE grid
-  USE calculus, ONLY : simpson_rule_z
-  USE parallel,  ONLY : manual_3D_bcast
-  use model, ONLY : qe2_taue, qi2_taui, q_e, q_i, lambdaD, KIN_E
-  USE processing, ONLY : compute_density
-  USE prec_const
-  USE geometry, ONLY : iInt_Jacobian, Jacobian
-  IMPLICIT NONE
-
-  INTEGER     :: ini,ine, i_, root_bcast
-  COMPLEX(dp) :: fsa_phi, intf_   ! current flux averaged phi
-  INTEGER     :: count !! mpi integer to broadcast the electric potential at the end
-  COMPLEX(dp), DIMENSION(izs:ize) :: rho_i, rho_e, integrant  ! charge density q_a n_a and aux var
-
-  ! Execution time start
-  CALL cpu_time(t0_poisson)
-  !! Poisson can be solved only for process containing p=0
-  IF ( (ips_e .EQ. ip0_e) .AND. (ips_i .EQ. ip0_i) ) THEN
-
-
-    kxloop: DO ikx = ikxs,ikxe
-      kyloop: DO iky = ikys,ikye
-        phi(iky,ikx,izs:ize)  = 0._dp
-        !!!! Compute ion particle charge density q_i n_i
-        rho_i = 0._dp
-        DO ini=1,jmaxi+1
-          rho_i(izs:ize) = rho_i(izs:ize) &
-           +q_i*kernel_i(ini,iky,ikx,izs:ize,0)*moments_i(ip0_i,ini,iky,ikx,izs:ize,updatetlevel)
-        END DO
-
-        !!!! Compute electron particle charge density q_e n_e
-        rho_e = 0._dp
-        IF (KIN_E) THEN ! Kinetic electrons
-          DO ine=1,jmaxe+1
-            rho_e(izs:ize) = rho_e(izs:ize) &
-             +q_e*kernel_e(ine,iky,ikx,izs:ize,0)*moments_e(ip0_e,ine,iky,ikx,izs:ize,updatetlevel)
-          END DO
-        ELSE  ! Adiabatic electrons
-          ! Adiabatic charge density (linked to flux surface averaged phi)
-          ! We compute the flux surface average solving a flux surface averaged
-          ! Poisson equation, i.e.
-          ! [qi^2(1-sum_j K_j^2)/tau_i] <phi>_psi = <q_i n_i >_psi
-          !       inv_pol_ion^-1         fsa_phi  = simpson(Jacobian rho_i ) * iInt_Jacobian
-          fsa_phi = 0._dp
-          IF(kyarray(iky).EQ.0._dp) THEN ! take ky=0 mode (y-average)
-            ! Prepare integrant for z-average
-            integrant(izs:ize) = Jacobian(izs:ize,0)*rho_i(izs:ize)*inv_pol_ion(iky,ikx,izs:ize)
-            call simpson_rule_z(integrant(izs:ize),intf_) ! get the flux averaged phi
-            fsa_phi = intf_ * iInt_Jacobian !Normalize by 1/int(Jxyz)dz
-          ENDIF
-          rho_e(izs:ize) = fsa_phi
-        ENDIF
-        !!!!!!!!!!!!!!! Inverting the poisson equation !!!!!!!!!!!!!!!!!!!!!!!!!!
-        phi(iky,ikx,izs:ize) = (rho_e(izs:ize) + rho_i(izs:ize))*inv_poisson_op(iky,ikx,izs:ize)
-
-      END DO kyloop
-    END DO kxloop
-
-    ! Cancel origin singularity
-    IF (contains_kx0 .AND. contains_ky0) phi(iky_0,ikx_0,:) = 0._dp
-
-  ENDIF
-
-  ! Transfer phi to all the others process along p
-  CALL manual_3D_bcast(phi(ikys:ikye,ikxs:ikxe,izs:ize))
-
-  ! Execution time end
-  CALL cpu_time(t1_poisson)
-  tc_poisson = tc_poisson + (t1_poisson - t0_poisson)
-  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-END SUBROUTINE poisson
diff --git a/src/processing_mod.F90 b/src/processing_mod.F90
index 649d51ef..79d80f27 100644
--- a/src/processing_mod.F90
+++ b/src/processing_mod.F90
@@ -295,12 +295,13 @@ SUBROUTINE compute_nadiab_moments_z_gradients_and_interp
   !
   ! n_{pi} = N^{pj} + kernel(j) /tau_i phi delta_p0
   !
-  USE fields,           ONLY : moments_i, moments_e, phi
+  USE fields,           ONLY : moments_i, moments_e, phi, psi
   USE array,            ONLY : kernel_e, kernel_i, nadiab_moments_e, nadiab_moments_i, &
                                ddz_nepj, ddz4_Nepj, interp_nepj,&
                                ddz_nipj, ddz4_Nipj, interp_nipj
   USE time_integration, ONLY : updatetlevel
-  USE model,            ONLY : qe_taue, qi_taui, KIN_E, CLOS
+  USE model,            ONLY : qe_taue, qi_taui,q_o_sqrt_tau_sigma_e, q_o_sqrt_tau_sigma_i, &
+                               KIN_E, CLOS
   USE calculus,         ONLY : grad_z, grad_z4, interp_z
   IMPLICIT NONE
   INTEGER :: eo, p_int, j_int
@@ -315,6 +316,9 @@ SUBROUTINE compute_nadiab_moments_z_gradients_and_interp
             nadiab_moments_e(ip,ij,:,:,:) = moments_e(ip,ij,:,:,:,updatetlevel) &
                                       + qe_taue*kernel_e(ij,:,:,:,0)*phi(:,:,:)
           ENDDO
+        ELSEIF(parray_e(ip) .EQ. 1) THEN
+            nadiab_moments_e(ip,ij,:,:,:) = moments_e(ip,ij,:,:,:,updatetlevel) &
+                                      - q_o_sqrt_tau_sigma_e*kernel_e(ij,:,:,:,0)*psi(:,:,:)
         ELSE
           DO ij=ijgs_e,ijge_e
             nadiab_moments_e(ip,ij,:,:,:) = moments_e(ip,ij,:,:,:,updatetlevel)
@@ -329,6 +333,9 @@ SUBROUTINE compute_nadiab_moments_z_gradients_and_interp
           nadiab_moments_i(ip,ij,:,:,:) = moments_i(ip,ij,:,:,:,updatetlevel) &
                                     + qi_taui*kernel_i(ij,:,:,:,0)*phi(:,:,:)
         ENDDO
+      ELSEIF(parray_i(ip) .EQ. 1) THEN
+          nadiab_moments_e(ip,ij,:,:,:) = moments_i(ip,ij,:,:,:,updatetlevel) &
+                                    - q_o_sqrt_tau_sigma_i*kernel_i(ij,:,:,:,0)*psi(:,:,:)
       ELSE
         DO ij=ijgs_i,ijge_i
           nadiab_moments_i(ip,ij,:,:,:) = moments_i(ip,ij,:,:,:,updatetlevel)
diff --git a/src/solve_EM_fields.F90 b/src/solve_EM_fields.F90
new file mode 100644
index 00000000..b102ac1a
--- /dev/null
+++ b/src/solve_EM_fields.F90
@@ -0,0 +1,147 @@
+SUBROUTINE solve_EM_fields
+  ! Solve Poisson and Ampere equations
+  USE model, ONLY : beta
+  USE basic
+  USE prec_const
+  IMPLICIT NONE
+
+  CALL poisson
+
+  IF(beta .GT. 0._dp) &
+  CALL ampere
+
+CONTAINS
+
+  SUBROUTINE poisson
+    ! Solve poisson equation to get phi
+    USE time_integration, ONLY: updatetlevel
+    USE array,            ONLY: kernel_e, kernel_i, inv_poisson_op, inv_pol_ion
+    USE fields,           ONLY: phi, moments_e, moments_i
+    USE grid
+    USE calculus,         ONLY : simpson_rule_z
+    USE parallel,         ONLY : manual_3D_bcast
+    use model,            ONLY : qe2_taue, qi2_taui, q_e, q_i, lambdaD, KIN_E
+    USE processing,       ONLY : compute_density
+    USE geometry,         ONLY : iInt_Jacobian, Jacobian
+    IMPLICIT NONE
+
+    INTEGER     :: ini,ine, i_, root_bcast
+    COMPLEX(dp) :: fsa_phi, intf_   ! current flux averaged phi
+    INTEGER     :: count !! mpi integer to broadcast the electric potential at the end
+    COMPLEX(dp), DIMENSION(izs:ize) :: rho_i, rho_e, integrant  ! charge density q_a n_a and aux var
+
+    ! Execution time start
+    CALL cpu_time(t0_poisson)
+    !! Poisson can be solved only for process containing p=0
+    ! IF ( SOLVE_POISSON ) THEN
+    IF ( (ips_e .EQ. ip0_e) .AND. (ips_i .EQ. ip0_i) ) THEN
+
+      kxloop: DO ikx = ikxs,ikxe
+        kyloop: DO iky = ikys,ikye
+          phi(iky,ikx,izs:ize)  = 0._dp
+          !!!! Compute ion particle charge density q_i n_i
+          rho_i = 0._dp
+          DO ini=1,jmaxi+1
+            rho_i(izs:ize) = rho_i(izs:ize) &
+             +q_i*kernel_i(ini,iky,ikx,izs:ize,0)*moments_i(ip0_i,ini,iky,ikx,izs:ize,updatetlevel)
+          END DO
+
+          !!!! Compute electron particle charge density q_e n_e
+          rho_e = 0._dp
+          IF (KIN_E) THEN ! Kinetic electrons
+            DO ine=1,jmaxe+1
+              rho_e(izs:ize) = rho_e(izs:ize) &
+               +q_e*kernel_e(ine,iky,ikx,izs:ize,0)*moments_e(ip0_e,ine,iky,ikx,izs:ize,updatetlevel)
+            END DO
+          ELSE  ! Adiabatic electrons
+            ! Adiabatic charge density (linked to flux surface averaged phi)
+            ! We compute the flux surface average solving a flux surface averaged
+            ! Poisson equation, i.e.
+            ! [qi^2(1-sum_j K_j^2)/tau_i] <phi>_psi = <q_i n_i >_psi
+            !       inv_pol_ion^-1         fsa_phi  = simpson(Jacobian rho_i ) * iInt_Jacobian
+            fsa_phi = 0._dp
+            IF(kyarray(iky).EQ.0._dp) THEN ! take ky=0 mode (y-average)
+              ! Prepare integrant for z-average
+              integrant(izs:ize) = Jacobian(izs:ize,0)*rho_i(izs:ize)*inv_pol_ion(iky,ikx,izs:ize)
+              call simpson_rule_z(integrant(izs:ize),intf_) ! get the flux averaged phi
+              fsa_phi = intf_ * iInt_Jacobian !Normalize by 1/int(Jxyz)dz
+            ENDIF
+            rho_e(izs:ize) = fsa_phi
+          ENDIF
+          !!!!!!!!!!!!!!! Inverting the poisson equation !!!!!!!!!!!!!!!!!!!!!!!!!!
+          phi(iky,ikx,izs:ize) = (rho_e(izs:ize) + rho_i(izs:ize))*inv_poisson_op(iky,ikx,izs:ize)
+
+        END DO kyloop
+      END DO kxloop
+
+      ! Cancel origin singularity
+      IF (contains_kx0 .AND. contains_ky0) phi(iky_0,ikx_0,:) = 0._dp
+
+    ENDIF
+
+    ! Transfer phi to all the others process along p
+    CALL manual_3D_bcast(phi(ikys:ikye,ikxs:ikxe,izs:ize))
+
+    ! Execution time end
+    CALL cpu_time(t1_poisson)
+    tc_poisson = tc_poisson + (t1_poisson - t0_poisson)
+    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  END SUBROUTINE poisson
+
+  SUBROUTINE ampere
+    ! Solve ampere equation to get psi
+    USE time_integration, ONLY: updatetlevel
+    USE array,            ONLY: kernel_e, kernel_i, inv_ampere_op
+    USE fields,           ONLY: moments_i, moments_e, psi
+    USE grid
+    USE parallel,         ONLY : manual_3D_bcast
+    use model,            ONLY : sqrt_tau_o_sigma_e, sqrt_tau_o_sigma_i, q_e, q_i, beta, KIN_E
+    IMPLICIT NONE
+
+    INTEGER     :: ini,ine, i_, root_bcast
+    INTEGER     :: count !! mpi integer to broadcast the electric potential at the end
+    COMPLEX(dp), DIMENSION(izs:ize) :: I_i, I_e  ! current density q_a u_a and aux var
+
+    ! Execution time start
+    CALL cpu_time(t0_poisson)
+    !! Ampere can be solved only with beta > 0 and for process containing p=1
+    IF ( SOLVE_AMPERE ) THEN
+
+      kxloop: DO ikx = ikxs,ikxe
+        kyloop: DO iky = ikys,ikye
+          psi(iky,ikx,izs:ize)  = 0._dp
+          !!!! Compute ion particle current density q_i u_i
+          I_i = 0._dp
+          DO ini=1,jmaxi+1
+            I_i(izs:ize) = I_i(izs:ize) &
+             +kernel_i(ini,iky,ikx,izs:ize,0)*moments_i(ip1_i,ini,iky,ikx,izs:ize,updatetlevel)
+          END DO
+          I_i = q_i * sqrt_tau_o_sigma_i * I_i
+          !!!! Compute electron particle charge density q_e n_e
+          I_e = 0._dp
+          DO ine=1,jmaxe+1
+            I_e(izs:ize) = I_e(izs:ize) &
+             +q_e*kernel_e(ine,iky,ikx,izs:ize,0)*moments_e(ip1_e,ine,iky,ikx,izs:ize,updatetlevel)
+          END DO
+          I_e = q_e * sqrt_tau_o_sigma_e * I_e
+          !!!!!!!!!!!!!!! Inverting the poisson equation !!!!!!!!!!!!!!!!!!!!!!!!!!
+          psi(iky,ikx,izs:ize) = beta*(I_e(izs:ize) + I_i(izs:ize))*inv_ampere_op(iky,ikx,izs:ize)
+
+        END DO kyloop
+      END DO kxloop
+
+      ! Cancel origin singularity
+      IF (contains_kx0 .AND. contains_ky0) psi(iky_0,ikx_0,:) = 0._dp
+
+    ENDIF
+
+    ! Transfer phi to all the others process along p
+    CALL manual_3D_bcast(psi(ikys:ikye,ikxs:ikxe,izs:ize))
+
+    ! Execution time end
+    CALL cpu_time(t1_poisson)
+    tc_poisson = tc_poisson + (t1_poisson - t0_poisson)
+    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+  END SUBROUTINE ampere
+
+END SUBROUTINE solve_EM_fields
diff --git a/src/stepon.F90 b/src/stepon.F90
index 09ad4533..1771985e 100644
--- a/src/stepon.F90
+++ b/src/stepon.F90
@@ -3,7 +3,7 @@ SUBROUTINE stepon
   USE advance_field_routine, ONLY: advance_time_level, advance_field, advance_moments
   USE basic
   USE closure
-  USE ghosts, ONLY: update_ghosts_moments, update_ghosts_phi
+  USE ghosts, ONLY: update_ghosts_moments, update_ghosts_EM
   USE grid
   USE model, ONLY : LINEARITY, KIN_E
   use prec_const
@@ -34,9 +34,9 @@ SUBROUTINE stepon
       ! Exchanges the ghosts values of N_n+1
       CALL update_ghosts_moments
 
-      ! Update electrostatic potential phi_n = phi(N_n+1)
-      CALL poisson
-      CALL update_ghosts_phi
+      ! Update electrostatic potential phi_n = phi(N_n+1) and potential vect psi
+      CALL solve_EM_fields
+      CALL update_ghosts_EM
 
       ! Numerical experiments
       ! Store or cancel/maintain zonal modes artificially
@@ -130,7 +130,7 @@ SUBROUTINE stepon
       END SUBROUTINE anti_aliasing
 
       SUBROUTINE enforce_symmetry ! Force X(k) = X(N-k)* complex conjugate symmetry
-        USE fields, ONLY: phi, moments_e, moments_i
+        USE fields, ONLY: phi, psi, moments_e, moments_i
         IMPLICIT NONE
         IF ( contains_ky0 ) THEN
           ! Electron moments
@@ -165,6 +165,12 @@ SUBROUTINE stepon
           END DO
           ! must be real at origin
           phi(iky_0,ikx_0,izs:ize) = REAL(phi(iky_0,ikx_0,izs:ize))
+          ! Psi
+          DO ikx=2,Nkx/2 !symmetry at ky = 0
+            psi(iky_0,ikx,izs:ize) = psi(iky_0,Nkx+2-ikx,izs:ize)
+          END DO
+          ! must be real at origin
+          psi(iky_0,ikx_0,izs:ize) = REAL(psi(iky_0,ikx_0,izs:ize))
         ENDIF
       END SUBROUTINE enforce_symmetry
 
diff --git a/wk/analysis_HeLaZ.m b/wk/analysis_HeLaZ.m
index 99ceca4d..7721a364 100644
--- a/wk/analysis_HeLaZ.m
+++ b/wk/analysis_HeLaZ.m
@@ -44,18 +44,18 @@ if 0
 % Options
 options.INTERP    = 1;
 options.POLARPLOT = 0;
-% options.NAME      = '\phi';
+options.NAME      = '\phi';
 % options.NAME      = 'N_i^{00}';
-options.NAME      = 'v_y';
+% options.NAME      = 'v_y';
 % options.NAME      = 'n_i^{NZ}';
 % options.NAME      = '\Gamma_x';
 % options.NAME      = 'n_i';
-options.PLAN      = 'xy';
+options.PLAN      = 'xz';
 % options.NAME      = 'f_i';
 % options.PLAN      = 'sx';
-options.COMP      = 1;
+options.COMP      = 'avg';
 % options.TIME      = data.Ts5D(end-30:end);
-options.TIME      =  data.Ts3D(1:20:end);
+options.TIME      =  data.Ts3D(1:2:end);
 % options.TIME      = [750:1:1000];
 data.EPS          = 0.1;
 data.a = data.EPS * 2000;
@@ -65,7 +65,7 @@ end
 if 0
 %% 2D snapshots
 % Options
-options.INTERP    = 1;
+options.INTERP    = 0;
 options.POLARPLOT = 0;
 options.AXISEQUAL = 1;
 % options.NAME      = '\phi';
@@ -74,11 +74,11 @@ options.NAME      = 'N_i^{00}';
 % options.NAME      = 'T_i';
 % options.NAME      = '\Gamma_x';
 % options.NAME      = 'k^2n_e';
-options.PLAN      = 'xy';
+options.PLAN      = 'kxz';
 % options.NAME      'f_i';
 % options.PLAN      = 'sx';
 options.COMP      = 'avg';
-options.TIME      = [500 800 1000];
+options.TIME      = [120 150 155];
 data.a = data.EPS * 2e3;
 fig = photomaton(data,options);
 % save_figure(data,fig)
@@ -87,9 +87,9 @@ end
 if 0
 %% 3D plot on the geometry
 options.INTERP    = 1;
-options.NAME      = 'n_i';
-options.PLANES    = [1:10:80];
-options.TIME      = [200];
+options.NAME      = '\phi';
+options.PLANES    = [1:1:16];
+options.TIME      = [15];
 options.PLT_MTOPO = 0;
 data.rho_o_R      = 2e-3; % Sound larmor radius over Machine size ratio
 fig = show_geometry(data,options);
@@ -121,7 +121,7 @@ options.ST         = 1;
 options.PLOT_TYPE  = 'space-time';
 options.NORMALIZED = 1;
 options.JOBNUM     = 0;
-options.TIME       = [100:1200];
+options.TIME       = [1000];
 options.specie     = 'i';
 options.compz      = 'avg';
 fig = show_moments_spectrum(data,options);
@@ -167,7 +167,7 @@ if 0
 %% Mode evolution
 options.NORMALIZED = 0;
 options.K2PLOT = 1;
-options.TIME   = data.Ts3D;
+options.TIME   = [0:160];
 options.NMA    = 1;
 options.NMODES = 15;
 options.iz     = 'avg';
diff --git a/wk/analysis_gene.m b/wk/analysis_gene.m
index 822daf31..4b20e0b5 100644
--- a/wk/analysis_gene.m
+++ b/wk/analysis_gene.m
@@ -1,6 +1,6 @@
 % folder = '/misc/gene_results/shearless_cyclone/miller_output_1.0/';
 % folder = '/misc/gene_results/shearless_cyclone/miller_output_0.8/';
-% folder = '/misc/gene_results/shearless_cyclone/s_alpha_output_1.2/';
+% folder = '/misc/gene_results/shearless_cyclone/s_alpha_output_1.0/';
 % folder = '/misc/gene_results/shearless_cyclone/rm_corrections_HF/';
 % folder = '/misc/gene_results/shearless_cyclone/linear_s_alpha_CBC_100/';
 % folder = '/misc/gene_results/shearless_cyclone/s_alpha_output_0.5/';
@@ -47,8 +47,8 @@ options.NAME      = '\phi';
 options.PLAN      = 'xy';
 % options.NAME      ='f_e';
 % options.PLAN      = 'sx';
-options.COMP      = 'avg';
-options.TIME      = [1:10];
+options.COMP      = 1;
+options.TIME      = [15 50 100 200];
 gene_data.a = data.EPS * 2000;
 fig = photomaton(gene_data,options);
 save_figure(gene_data,fig,'.png')
@@ -64,7 +64,7 @@ options.NAME      = '\phi';
 % options.NAME      = 'n_i^{NZ}';
 % options.NAME      = '\Gamma_x';
 % options.NAME      = 'n_i';
-options.PLAN      = 'kxky';
+options.PLAN      = 'xy';
 % options.NAME      = 'f_e';
 % options.PLAN      = 'sx';
 options.COMP      = 'avg';
diff --git a/wk/header_3D_results.m b/wk/header_3D_results.m
index 7088014c..9b6139f7 100644
--- a/wk/header_3D_results.m
+++ b/wk/header_3D_results.m
@@ -16,7 +16,7 @@ helazdir = '/home/ahoffman/HeLaZ/';
 % outfile = 'shearless_cyclone/96x32x160x5x3_CBC_Npol_10_kine';
 % outfile = 'shearless_cyclone/64x32x160x5x3_CBC_Npol_10_kine';
 % outfile = 'shearless_cyclone/96x32x160x5x3_CBC_Npol_10_kine';
-%% CBC
+%% shearless CBC
 % outfile ='shearless_cyclone/64x32x16x5x3_CBC_080';
 % outfile ='shearless_cyclone/64x32x16x5x3_CBC_scan/64x32x16x5x3_CBC_100';
 % outfile ='shearless_cyclone/64x32x16x5x3_CBC_120';
@@ -31,9 +31,15 @@ helazdir = '/home/ahoffman/HeLaZ/';
 % outfile ='Zpinch_rerun/Kn_2.5_256x128x5x3';
 % outfile ='Zpinch_rerun/Kn_2.5_312x196x5x3_Lx_400_Ly_200';
 % outfile ='Zpinch_rerun/Kn_2.5_256x64x5x3';
-% outfile ='Zpinch_rerun/Kn_2.0_200x48x9x5_large_box';
+outfile ='Zpinch_rerun/Kn_2.0_200x48x9x5_large_box';
 % outfile ='Zpinch_rerun/Kn_2.0_256x64x9x5_Lx_240_Ly_120';
 % outfile ='Zpinch_rerun/Kn_1.6_256x128x7x4';
 % outfile ='Zpinch_rerun/Kn_1.6_200x48x11x6';
-outfile ='Zpinch_rerun/Kn_1.6_256x128x21x11';
+% outfile ='Zpinch_rerun/Kn_1.6_256x128x21x11';
+
+%% CBC
+% outfile = 'CBC/64x32x16x5x3';
+% outfile = 'CBC/64x128x16x5x3';
+% outfile = 'CBC/128x64x16x5x3';
+outfile = 'CBC/64x64x16x3x2';
 run analysis_HeLaZ
diff --git a/wk/quick_run.m b/wk/quick_run.m
index 737428b0..33faeed8 100644
--- a/wk/quick_run.m
+++ b/wk/quick_run.m
@@ -16,21 +16,22 @@ CLUSTER.TIME  = '99:00:00'; % allocation time hh:mm:ss
 NU      = 0.01;   % Collision frequency
 TAU     = 1.0;    % e/i temperature ratio
 K_N     = 2.22;%2.0;   % Density gradient drive
-K_T     = 6.92;%0.25*K_N;   % Temperature '''
+K_T     = 6.96;%0.25*K_N;   % Temperature '''
 K_E     = 0.0;   % Electrostat '''
 % SIGMA_E = 0.05196152422706632;   % mass ratio sqrt(m_a/m_i) (correct = 0.0233380)
 SIGMA_E = 0.0233380;   % mass ratio sqrt(m_a/m_i) (correct = 0.0233380)
 KIN_E   = 0;     % 1: kinetic electrons, 2: adiabatic electrons
+BETA    = 0e-1;     % electron plasma beta 
 %% GRID PARAMETERS
-PMAXE   = 4;     % Hermite basis size of electrons
-JMAXE   = 2;     % Laguerre "
+PMAXE   = 12;     % Hermite basis size of electrons
+JMAXE   = 6;     % Laguerre "
 PMAXI   = 4;     % " ions
 JMAXI   = 2;     % "
-NX      = 12;    % real space x-gridpoints
-NY      = 8;     %     ''     y-gridpoints
+NX      = 16;    % real space x-gridpoints
+NY      = 2;     %     ''     y-gridpoints
 LX      = 2*pi/0.1;   % Size of the squared frequency domain
-LY      = 2*pi/0.1;     % Size of the squared frequency domain
-NZ      = 16;     % number of perpendicular planes (parallel grid)
+LY      = 2*pi/0.3;     % Size of the squared frequency domain
+NZ      = 32;    % number of perpendicular planes (parallel grid)
 NPOL    = 1;
 SG      = 0;     % Staggered z grids option
 %% GEOMETRY
@@ -41,7 +42,7 @@ SHEAR   = 0.8;    % magnetic shear (Not implemented yet)
 EPS     = 0.18;    % inverse aspect ratio
 %% TIME PARMETERS
 TMAX    = 20;  % Maximal time unit
-DT      = 5e-3;   % Time step
+DT      = 1e-2;   % Time step
 SPS0D   = 1;      % Sampling per time unit for 2D arrays
 SPS2D   = 0;      % Sampling per time unit for 2D arrays
 SPS3D   = 1;      % Sampling per time unit for 2D arrays
@@ -92,9 +93,9 @@ setup
 % Run linear simulation
 if RUN
 %     system(['cd ../results/',SIMID,'/',PARAMS,'/; time mpirun -np 4 ',HELAZDIR,'bin/',EXECNAME,' 1 4 1 0; cd ../../../wk'])
-%     system(['cd ../results/',SIMID,'/',PARAMS,'/; mpirun -np 4 ',HELAZDIR,'bin/',EXECNAME,' 1 2 2 0; cd ../../../wk'])
+%     system(['cd ../results/',SIMID,'/',PARAMS,'/; mpirun -np 4 ',HELAZDIR,'bin/',EXECNAME,' 1 4 1 0; cd ../../../wk'])
 %     system(['cd ../results/',SIMID,'/',PARAMS,'/; mpirun -np 1 ',HELAZDIR,'bin/',EXECNAME,' 1 1 1 0; cd ../../../wk'])
-    system(['cd ../results/',SIMID,'/',PARAMS,'/; mpirun -np 6 ',HELAZDIR,'bin/',EXECNAME,' 2 1 3 0; cd ../../../wk'])
+    system(['cd ../results/',SIMID,'/',PARAMS,'/; mpirun -np 6 ',HELAZDIR,'bin/',EXECNAME,' 1 2 3 0; cd ../../../wk'])
 %     system(['cd ../results/',SIMID,'/',PARAMS,'/; mpirun -np 6 ',HELAZDIR,'bin/',EXECNAME,' 1 6 1 0; cd ../../../wk'])
 end
 
@@ -107,7 +108,7 @@ JOBNUMMIN = 00; JOBNUMMAX = 00;
 data = compile_results(LOCALDIR,JOBNUMMIN,JOBNUMMAX); %Compile the results from first output found to JOBNUMMAX if existing
 
 %% Short analysis
-if 0
+if 1
 %% linear growth rate (adapted for 2D zpinch and fluxtube)
 trange = [0.5 1]*data.Ts3D(end);
 nplots = 1;
@@ -118,9 +119,9 @@ msg = sprintf('gmax = %2.2f, kmax = %2.2f',gmax,lg.ky(kmax)); disp(msg);
 msg = sprintf('gmax/k = %2.2f, kmax/k = %2.2f',gmaxok,lg.ky(kmaxok)); disp(msg);
 end
 
-if 1
+if 0
 %% Ballooning plot
-options.time_2_plot = [1]*data.Ts3D(end);
+options.time_2_plot = [120];
 options.kymodes     = [0.1 0.2 0.3];
 options.normalized  = 1;
 options.field       = 'phi';
-- 
GitLab