From 506b9c5d27d789c9870d919d9bf762a9eb9324ea Mon Sep 17 00:00:00 2001
From: Antoine Hoffmann <antoine.hoffmann@epfl.ch>
Date: Tue, 27 Jun 2023 08:54:10 +0200
Subject: [PATCH] Miller is now working kx grid uses now the Cyq0_x0 factor
 grid module init first the indices

---
 src/auxval.F90     |   5 +-
 src/grid_mod.F90   | 381 +++++++++++++++---------------
 src/miller_mod.F90 | 560 ++++++++++++++++++++++-----------------------
 3 files changed, 474 insertions(+), 472 deletions(-)

diff --git a/src/auxval.F90 b/src/auxval.F90
index eec63594..dd4f4a16 100644
--- a/src/auxval.F90
+++ b/src/auxval.F90
@@ -19,6 +19,7 @@ subroutine auxval
   INTEGER :: i_, ierr
   CALL speak('=== Set auxiliary values ===')
   ! Init the grids
+  CALL init_grids_data(Na,EM,LINEARITY) 
   CALL set_grids(shear,Npol,LINEARITY,N_HD,EM,Na) 
   ! Allocate memory for global arrays
   CALL memory
@@ -40,13 +41,11 @@ subroutine auxval
   ! precompute the hermite fourth derivative table
   CALL build_dv4Hp_table 
   ! set the closure scheme in use
-  CALL set_closure_model 
-  
+  CALL set_closure_model   
 #ifdef TEST_SVD
   ! If we want to test SVD decomposition etc.
   CALL init_CLA(local_nky,local_np*local_nj)
 #endif
-
   !! Display parallel settings
   CALL mpi_barrier(MPI_COMM_WORLD, ierr)
   DO i_ = 0,num_procs-1
diff --git a/src/grid_mod.F90 b/src/grid_mod.F90
index 6aa9ad31..9891b2ac 100644
--- a/src/grid_mod.F90
+++ b/src/grid_mod.F90
@@ -108,8 +108,8 @@ MODULE grid
   REAL(xp), DIMENSION(:), ALLOCATABLE, PUBLIC,PROTECTED :: AA_y
 
   ! Public Functions
-  PUBLIC :: init_1Dgrid_distr
-  PUBLIC :: set_grids, set_kparray
+  PUBLIC :: init_1Dgrid_distr, init_grids_data
+  PUBLIC :: set_grids, set_kxgrid, set_kparray
   PUBLIC :: grid_readinputs, grid_outputinputs
   PUBLIC :: bar
 
@@ -118,7 +118,6 @@ MODULE grid
 
 CONTAINS
 
-
   SUBROUTINE grid_readinputs
     ! Read the input parameters
     USE prec_const
@@ -135,6 +134,136 @@ CONTAINS
     inv_Nx = 1._xp/REAL(Nx,xp)
     inv_Ny = 1._xp/REAL(Ny,xp)
   END SUBROUTINE grid_readinputs
+
+  !! Init the local and global number of points in all directions
+  SUBROUTINE init_grids_data(Na,EM,LINEARITY) 
+    USE fourier,  ONLY: init_grid_distr_and_plans
+    USE parallel, ONLY: num_procs_p, rank_p, num_procs_z, rank_z
+    IMPLICIT NONE
+    INTEGER, INTENT(IN) :: Na        ! number of species coming from the model module
+    LOGICAL, INTENT(IN) :: EM        ! electromagnetic effects (to skip odd Hermite or not)
+    CHARACTER(len=*), INTENT(IN) :: LINEARITY    ! Linear or nonlinear run
+    INTEGER :: in, istart, iend
+    !!----------------- SPECIES INDICES (not parallelized)
+    ias = 1
+    iae = Na
+    total_Na = Na
+    local_Na = Na
+    local_Na_offset = ias - 1
+    !!----------------- HERMITE INDICES (parallelized)
+    ! If no parallel dim (Nz=1) and no EM effects (beta=0), the moment hierarchy
+    !! is separable between odds and even P
+    IF((Nz .EQ. 1) .AND. .NOT. EM) THEN
+      deltap  = 2
+      Ngp     = 2  ! two ghosts cells for p+/-2 only
+      pp2     = 1  ! index p+2 is ip+1
+    ELSE
+      deltap  = 1
+      Ngp     = 4  ! four ghosts cells for p+/-1 and p+/-2 terms
+      pp2     = 2  ! index p+2 is ip+2
+    ENDIF
+    ! Total number of Hermite polynomials we will evolve
+    total_np = (Pmax/deltap) + 1
+    ! Local data distribution
+    CALL decomp1D(total_np, num_procs_p, rank_p, ips, ipe)
+    local_np        = ipe - ips + 1
+    local_np_offset = ips - 1
+    ! Allocate the grid arrays
+    ALLOCATE(parray_full(total_np))
+    ALLOCATE(parray(local_np+ngp))
+    !!----------------- LAGUERRE INDICES (not parallelized)
+    ! Total number of J degrees
+    total_nj   = jmax+1
+    local_jmax = jmax
+    Ngj= 2      ! 2-points ghosts for j+\-1 terms
+    ! Indices of local data
+    ijs = 1; ije = jmax + 1
+    ! Local number of J
+    local_nj        = ije - ijs + 1
+    local_nj_offset = ijs - 1
+    ! allocate global and local
+    ALLOCATE(jarray_full(total_nj))
+    ALLOCATE(jarray(local_nj+ngj))
+    ALLOCATE(kroneck_j0(local_nj+ngj));
+    ALLOCATE(kroneck_j1(local_nj+ngj));
+    !!----------------- SPATIAL GRIDS (parallelized)
+    !! Parallel distribution of kx ky grid
+    IF (LINEARITY .NE. 'linear') THEN ! we let FFTW distribute if we use it
+      IF (my_id .EQ. 0) write(*,*) 'FFTW3 y-grid distribution'
+      CALL init_grid_distr_and_plans(Nx,Ny,comm_ky,local_nkx_ptr,local_nkx_ptr_offset,local_nky_ptr,local_nky_ptr_offset)
+    ELSE ! otherwise we distribute equally
+      IF (my_id .EQ. 0) write(*,*) 'Manual y-grid distribution'
+      CALL init_1Dgrid_distr
+    ENDIF
+    !!----------------- BINORMAL KY INDICES (parallelized)
+    Nky       = Ny/2+1 ! Defined only on positive kx since fields are real
+    total_nky = Nky
+    Ngy = 0 ! no ghosts cells in ky
+    ikys = local_nky_ptr_offset + 1
+    ikye = ikys + local_nky_ptr - 1
+    local_nky = ikye - ikys + 1
+    local_nky_offset = local_nky_ptr_offset
+    ALLOCATE(kyarray_full(Nky))
+    ALLOCATE(kyarray(local_nky))
+    ALLOCATE(AA_y(local_nky))
+    !!---------------- RADIAL KX INDICES (not parallelized)
+    Nkx       = Nx
+    total_nkx = Nx
+    ikxs = 1
+    ikxe = total_nkx
+    local_nkx_ptr = ikxe - ikxs + 1
+    local_nkx     = ikxe - ikxs + 1
+    local_nkx_offset = ikxs - 1
+    ALLOCATE(kxarray(local_nkx))
+    ALLOCATE(kxarray_full(total_nkx))
+    ALLOCATE(AA_x(local_nkx))
+    !!---------------- PARALLEL Z GRID (parallelized)
+    total_nz = Nz
+    IF (SG) THEN
+      CALL speak('--2 staggered z grids--')
+      ! indices for even p and odd p grids (used in kernel, jacobian, gij etc.)
+      ieven  = 1
+      iodd   = 2
+      nzgrid = 2
+    ELSE
+      ieven  = 1
+      iodd   = 1
+      nzgrid = 1
+    ENDIF
+    !! Parallel data distribution
+    IF( (Nz .EQ. 1) .AND. (num_procs_z .GT. 1) ) &
+    ERROR STOP '>> ERROR << Cannot have multiple core in z-direction (Nz = 1)'
+    ! Local data distribution
+    CALL decomp1D(total_nz, num_procs_z, rank_z, izs, ize)
+    local_nz        = ize - izs + 1
+    local_nz_offset = izs - 1
+    ! Ghosts boundaries (depend on the order of z operators)
+    IF(Nz .EQ. 1) THEN
+      ngz = 0
+    ELSEIF(Nz .GE. 4) THEN
+      ngz =4
+      IF(mod(Nz,2) .NE. 0 ) THEN
+        ERROR STOP '>> ERROR << Nz must be an even number for Simpson integration rule !!!!'
+     ENDIF
+    ELSE
+      ERROR STOP '>> ERROR << Nz is not appropriate!!'
+    ENDIF
+    ALLOCATE(zarray(local_nz+ngz,nzgrid))
+    ALLOCATE(zarray_full(total_nz))
+    ALLOCATE(counts_nz (num_procs_z))
+    ALLOCATE(displs_nz (num_procs_z))
+    CALL allocate_array(local_zmax,1,nzgrid)
+    CALL allocate_array(local_zmin,1,nzgrid)
+    ALLOCATE(zweights_SR(local_nz))
+    ! List of shift and local numbers between the different processes (used in scatterv and gatherv)
+    DO in = 0,num_procs_z-1
+      CALL decomp1D(total_nz, num_procs_z, in, istart, iend)
+      counts_nz(in+1) = iend-istart+1
+      displs_nz(in+1) = istart-1
+    ENDDO
+    !!---------------- Kperp grid
+    CALL allocate_array( kparray, 1,local_nky, 1,local_nkx, 1,local_nz+ngz, 1,nzgrid)
+  END SUBROUTINE
   !!!! GRID REPRESENTATION
   ! We define the grids that contain ghosts (p,j,z) with indexing from 1 to Nlocal + nghost
   ! e.g. nghost = 4, nlocal = 4
@@ -145,7 +274,6 @@ CONTAINS
   ! |_|_|_|_|
   !  1 2 3 4
   SUBROUTINE set_grids(shear,Npol,LINEARITY,N_HD,EM,Na)
-    USE fourier, ONLY: init_grid_distr_and_plans
     REAL(xp), INTENT(IN) :: shear, Npol
     CHARACTER(len=*), INTENT(IN) :: LINEARITY
     INTEGER, INTENT(IN)  :: N_HD
@@ -154,16 +282,8 @@ CONTAINS
     CALL set_agrid(Na)
     CALL set_pgrid(EM)
     CALL set_jgrid
-    !! Parallel distribution of kx ky grid
-    IF (LINEARITY .NE. 'linear') THEN
-      IF (my_id .EQ. 0) write(*,*) 'FFTW3 y-grid distribution'
-      CALL init_grid_distr_and_plans(Nx,Ny,comm_ky,local_nkx_ptr,local_nkx_ptr_offset,local_nky_ptr,local_nky_ptr_offset)
-    ELSE
-      CALL init_1Dgrid_distr
-      IF (my_id .EQ. 0) write(*,*) 'Manual y-grid distribution'
-    ENDIF
     CALL set_kygrid(LINEARITY,N_HD)
-    CALL set_kxgrid(shear,Npol,LINEARITY,N_HD)
+    CALL set_kxgrid(shear,Npol,1._xp,LINEARITY,N_HD) ! this will be redone after geometry if Cyq0_x0 .NE. 1
     CALL set_zgrid (Npol)
   END SUBROUTINE set_grids
 
@@ -188,39 +308,14 @@ CONTAINS
 
   SUBROUTINE set_pgrid(EM)
     USE prec_const
-    USE parallel, ONLY: num_procs_p, rank_p
     IMPLICIT NONE
     LOGICAL, INTENT(IN) :: EM
     INTEGER :: ip
-    ! 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. .NOT. EM) THEN
-      deltap  = 2
-      Ngp     = 2  ! two ghosts cells for p+/-2 only
-      pp2     = 1  ! index p+2 is ip+1
-    ELSE
-      deltap  = 1
-      Ngp     = 4  ! four ghosts cells for p+/-1 and p+/-2 terms
-      pp2     = 2  ! index p+2 is ip+2
-    ENDIF
-    ! Total number of Hermite polynomials we will evolve
-    total_np = (Pmax/deltap) + 1
     ! Build the full grids on process 0 to diagnose it without comm
-    ALLOCATE(parray_full(total_np))
     ! P
     DO ip = 1,total_np; parray_full(ip) = (ip-1)*deltap; END DO
-    !! Parallel data distribution
-    ! Local data distribution
-    CALL decomp1D(total_np, num_procs_p, rank_p, ips, ipe)
-    local_np       = ipe - ips + 1
-    local_np_offset = ips - 1
     !! local grid computations
-    ! Allocate and fill pgrid array
-    ALLOCATE(parray(local_np+ngp))
+    ! Fill pgrid array
     DO ip = 1,local_np+ngp
       parray(ip) = (ip-1-ngp/2+local_np_offset)*deltap
     ENDDO
@@ -279,20 +374,11 @@ CONTAINS
     USE prec_const
     IMPLICIT NONE
     INTEGER :: ij
-    ! Total number of J degrees
-    total_nj   = jmax+1
-    local_jmax = jmax
-    Ngj= 2      ! 2-points ghosts for j+\-1 terms
     ! Build the full grids on process 0 to diagnose it without comm
-    ALLOCATE(jarray_full(total_nj))
     ! J
-    DO ij = 1,total_nj; jarray_full(ij) = (ij-1); END DO
-    ! Indices of local data
-    ijs = 1; ije = jmax + 1
-    ! Local number of J
-    local_nj        = ije - ijs + 1
-    local_nj_offset = ijs - 1
-    ALLOCATE(jarray(local_nj+ngj))
+    DO ij = 1,total_nj
+      jarray_full(ij) = (ij-1)
+    END DO
     DO ij = 1,local_nj+ngj
       jarray(ij) = ij-1-ngj/2+local_nj_offset
     END DO
@@ -307,8 +393,8 @@ CONTAINS
       IF(jarray(ij) .EQ. 1) ij1 = ij
     END DO
     ! Kronecker arrays for j
-    ALLOCATE(kroneck_j0(local_nj+ngj)); kroneck_j0 = 0._xp
-    ALLOCATE(kroneck_j1(local_nj+ngj)); kroneck_j1 = 0._xp
+    kroneck_j0 = 0._xp
+    kroneck_j1 = 0._xp
     DO ij = 1,local_nj+ngj
       SELECT CASE(jarray(ij))
       CASE(0)
@@ -325,29 +411,18 @@ CONTAINS
     CHARACTER(len=*), INTENT(IN) ::LINEARITY
     INTEGER, INTENT(IN) :: N_HD
     INTEGER :: iky
-    Nky       = Ny/2+1 ! Defined only on positive kx since fields are real
-    total_nky = Nky
     ! Grid spacings
     IF (Ny .EQ. 1) THEN
-      deltaky = 2._xp*PI/Ly
-      ky_max  = deltaky
-      ky_min  = deltaky
+      ERROR STOP "Gyacomo cannot run with only one ky"
     ELSE
       deltaky = 2._xp*PI/Ly
       ky_max  = (Nky-1)*deltaky
       ky_min  = deltaky
     ENDIF
-    Ngy = 0 ! no ghosts cells in ky
     ! Build the full grids on process 0 to diagnose it without comm
-    ALLOCATE(kyarray_full(Nky))
     DO iky = 1,Nky
      kyarray_full(iky) = REAL(iky-1,xp) * deltaky
     END DO
-    ikys = local_nky_ptr_offset + 1
-    ikye = ikys + local_nky_ptr - 1
-    local_nky = ikye - ikys + 1
-    local_nky_offset = local_nky_ptr_offset
-    ALLOCATE(kyarray(local_nky))
     local_kymax = 0._xp
     ! Creating a grid ordered as dk*(0 1 2 3)
     ! We loop over the natural iky numbers (|1 2 3||4 5 6||... Nky|)
@@ -378,7 +453,6 @@ CONTAINS
     END DO
     ! Orszag 2/3 filter
     two_third_kymax = 2._xp/3._xp*deltaky*(Nky-1)
-    ALLOCATE(AA_y(local_nky))
     DO iky = 1,local_nky
       IF ( (kyarray(iky) .LT. two_third_kymax) .OR. (LINEARITY .EQ. 'linear')) THEN
         AA_y(iky) = 1._xp;
@@ -394,10 +468,10 @@ CONTAINS
     ENDIF
   END SUBROUTINE set_kygrid
 
-  SUBROUTINE set_kxgrid(shear,Npol,LINEARITY,N_HD)
+  SUBROUTINE set_kxgrid(shear,Npol,Cyq0_x0,LINEARITY,N_HD)
     USE prec_const
     IMPLICIT NONE
-    REAL(xp), INTENT(IN) :: shear, Npol
+    REAL(xp), INTENT(IN) :: shear, Npol, Cyq0_x0
     CHARACTER(len=*), INTENT(IN) ::LINEARITY
     INTEGER, INTENT(IN)  :: N_HD
     INTEGER :: ikx
@@ -405,7 +479,7 @@ CONTAINS
     IF(shear .GT. 0) THEN
       IF(my_id.EQ.0) write(*,*) 'Magnetic shear detected: set up sheared kx grid..'
       ! mininal size of box in x to respect dkx = 2pi shear dky
-      Lx_adapted = Ly/(2._xp*pi*shear*Npol)
+      Lx_adapted = Ly/(2._xp*pi*shear*Npol*Cyq0_x0)
       ! Put Nexc to 0 so that it is computed from a target value Lx
       IF(Nexc .EQ. 0) THEN
         Nexc = CEILING(0.9 * Lx/Lx_adapted)
@@ -414,60 +488,36 @@ CONTAINS
       ! x length is adapted
       Lx = Lx_adapted*Nexc
     ENDIF
-    Nkx       = Nx
-    total_nkx = Nx
-    ! Local data
-    ! Start and END indices of grid
-    ikxs = 1
-    ikxe = total_nkx
-    local_nkx_ptr = ikxe - ikxs + 1
-    local_nkx     = ikxe - ikxs + 1
-    local_nkx_offset = ikxs - 1
-    ALLOCATE(kxarray(local_nkx))
-    ALLOCATE(kxarray_full(total_nkx))
-    IF (Nx .EQ. 1) THEN
-      deltakx         = 1._xp
-      kxarray(1)      = 0._xp
-      ikx0           = 1
-      contains_kx0    = .true.
-      kx_max          = 0._xp
-      ikx_max         = 1
-      kx_min          = 0._xp
-      kxarray_full(1) = 0._xp
-      local_kxmax     = 0._xp
-    ELSE ! Build apprpopriate grid
-      deltakx      = 2._xp*PI/Lx
-      IF(MODULO(total_nkx,2) .EQ. 0) THEN ! Even number of kx (-2 -1 0 1 2 3)
-        ! Creating a grid ordered as dk*(0 1 2 3 -2 -1)
-        DO ikx = 1,total_nkx
-          kxarray_full(ikx) = deltakx*REAL(MODULO(ikx-1,total_nkx/2)-(total_nkx/2)*FLOOR(2.*real(ikx-1)/real(total_nkx)),xp)
-          IF (ikx .EQ. total_nkx/2+1) kxarray_full(ikx) = -kxarray_full(ikx)
-        END DO
-        kx_max = MAXVAL(kxarray_full)!(total_nkx/2)*deltakx
-        kx_min = MINVAL(kxarray_full)!-kx_max+deltakx
-        ! Set local grid (not parallelized so same as full one)
-        local_kxmax = 0._xp
-        DO ikx = 1,local_nkx
-          kxarray(ikx) = kxarray_full(ikx+local_nkx_offset)
-          ! Finding kx=0
-          IF (kxarray(ikx) .EQ. 0) THEN
-            ikx0 = ikx
-            contains_kx0 = .true.
-          ENDIF
-          ! Finding local kxmax
-          IF (ABS(kxarray(ikx)) .GT. local_kxmax) THEN
-            local_kxmax = ABS(kxarray(ikx))
-            ikx_max = ikx
-          ENDIF
-        END DO
-      ELSE ! Odd number of kx (-2 -1 0 1 2)
-        ERROR STOP "Gyacomo is safer with a even Kx number"
-      ENDIF
+    deltakx      = 2._xp*PI/Lx
+    IF(MODULO(total_nkx,2) .EQ. 0) THEN ! Even number of kx (-2 -1 0 1 2 3)
+      ! Creating a grid ordered as dk*(0 1 2 3 -2 -1)
+      DO ikx = 1,total_nkx
+        kxarray_full(ikx) = deltakx*REAL(MODULO(ikx-1,total_nkx/2)-(total_nkx/2)*FLOOR(2.*real(ikx-1)/real(total_nkx)),xp)
+        IF (ikx .EQ. total_nkx/2+1) kxarray_full(ikx) = -kxarray_full(ikx)
+      END DO
+      kx_max = MAXVAL(kxarray_full)!(total_nkx/2)*deltakx
+      kx_min = MINVAL(kxarray_full)!-kx_max+deltakx
+      ! Set local grid (not parallelized so same as full one)
+      local_kxmax = 0._xp
+      DO ikx = 1,local_nkx
+        kxarray(ikx) = kxarray_full(ikx+local_nkx_offset)
+        ! Finding kx=0
+        IF (kxarray(ikx) .EQ. 0) THEN
+          ikx0 = ikx
+          contains_kx0 = .true.
+        ENDIF
+        ! Finding local kxmax
+        IF (ABS(kxarray(ikx)) .GT. local_kxmax) THEN
+          local_kxmax = ABS(kxarray(ikx))
+          ikx_max = ikx
+        ENDIF
+      END DO
+    ELSE ! Odd number of kx (-2 -1 0 1 2)
+      ERROR STOP "Gyacomo is safer with an even Kx number"
     ENDIF
     ! Orszag 2/3 filter
     two_third_kxmax = 2._xp/3._xp*kx_max;
     ! Antialiasing filter
-    ALLOCATE(AA_x(local_nkx))
     DO ikx = 1,local_nkx
       IF ( ((kxarray(ikx) .GT. -two_third_kxmax) .AND. &
            (kxarray(ikx) .LT. two_third_kxmax))   .OR. (LINEARITY .EQ. 'linear')) THEN
@@ -486,11 +536,9 @@ CONTAINS
 
   SUBROUTINE set_zgrid(Npol)
     USE prec_const
-    USE parallel, ONLY: num_procs_z, rank_z
     IMPLICIT NONE
     REAL(xp):: grid_shift, Lz, zmax, zmin, Npol
-    INTEGER :: istart, iend, in, iz, ig, eo, iglob
-    total_nz = Nz
+    INTEGER :: iz, ig, eo
     ! Length of the flux tube (in ballooning angle)
     Lz         = 2._xp*pi*Npol
     ! Z stepping (#interval = #points since periodic)
@@ -499,80 +547,48 @@ CONTAINS
     ! Parallel hyperdiffusion coefficient
     diff_dz_coeff = (deltaz/2._xp)**4 ! adaptive fourth derivative (~GENE)
     IF (SG) THEN
-      CALL speak('--2 staggered z grids--')
       grid_shift = deltaz/2._xp
-      ! indices for even p and odd p grids (used in kernel, jacobian, gij etc.)
-      ieven  = 1
-      iodd   = 2
-      nzgrid = 2
     ELSE
       grid_shift = 0._xp
-      ieven  = 1
-      iodd   = 1
-      nzgrid = 1
-    ENDIF
-    ! Build the full grids on process 0 to diagnose it without comm
-    ALLOCATE(zarray_full(total_nz))
-    IF (Nz .EQ. 1) Npol = 0._xp
-      zmax = 0; zmin = 0;
-      DO iz = 1,total_nz ! z in [-pi pi-dz] x Npol
-        zarray_full(iz) = REAL(iz-1,xp)*deltaz - Lz/2._xp
-        IF(zarray_full(iz) .GT. zmax) zmax = zarray_full(iz)
-        IF(zarray_full(iz) .LT. zmin) zmin = zarray_full(iz)
-      END DO
-      !! Parallel data distribution
-      IF( (Nz .EQ. 1) .AND. (num_procs_z .GT. 1) ) &
-      ERROR STOP '>> ERROR << Cannot have multiple core in z-direction (Nz = 1)'
-      ! Local data distribution
-      CALL decomp1D(total_nz, num_procs_z, rank_z, izs, ize)
-      local_nz        = ize - izs + 1
-      local_nz_offset = izs - 1
-      ! Ghosts boundaries (depend on the order of z operators)
-      IF(Nz .EQ. 1) THEN
-        ngz              = 0
-        zarray_full(izs) = 0
-    ELSEIF(Nz .GE. 4) THEN
-      ngz =4
-      IF(mod(Nz,2) .NE. 0 ) THEN
-        ERROR STOP '>> ERROR << Nz must be an even number for Simpson integration rule !!!!'
-     ENDIF
-    ELSE
-      ERROR STOP '>> ERROR << Nz is not appropriate!!'
     ENDIF
-    ! List of shift and local numbers between the different processes (used in scatterv and gatherv)
-    ALLOCATE(counts_nz (num_procs_z))
-    ALLOCATE(displs_nz (num_procs_z))
-    DO in = 0,num_procs_z-1
-      CALL decomp1D(total_nz, num_procs_z, in, istart, iend)
-      counts_nz(in+1) = iend-istart+1
-      displs_nz(in+1) = istart-1
-    ENDDO
+    ! Build the full grids on process 0 to diagnose it without comm   
+    IF (Nz .EQ. 1) &
+      Npol = 0._xp
+    zmax = 0; zmin = 0;
+    DO iz = 1,total_nz ! z in [-pi pi-dz] x Npol
+      zarray_full(iz) = REAL(iz-1,xp)*deltaz - Lz/2._xp
+      IF(zarray_full(iz) .GT. zmax) zmax = zarray_full(iz)
+      IF(zarray_full(iz) .LT. zmin) zmin = zarray_full(iz)
+    END DO
+    IF(Nz .EQ. 1) &
+      zarray_full(izs) = 0
     ! Local z array
-    ALLOCATE(zarray(local_nz+ngz,nzgrid))
-    !! interior point loop
     DO iz = 1,local_nz
       DO eo = 1,nzgrid
         zarray(iz+ngz/2,eo) = zarray_full(iz+local_nz_offset) + REAL(eo-1,xp)*grid_shift
       ENDDO
     ENDDO
-    CALL allocate_array(local_zmax,1,nzgrid)
-    CALL allocate_array(local_zmin,1,nzgrid)
     DO eo = 1,nzgrid
       ! Find local extrema
       local_zmax(eo) = zarray(local_nz+ngz/2,eo)
       local_zmin(eo) = zarray(1+ngz/2,eo)
       ! Periodic z \in (-pi pi-dz)
-      DO ig = 1,ngz/2 ! first ghost cells
-        iglob = ig+local_nz_offset-ngz/2
-        IF (iglob .LE. 0) &
-          iglob = iglob + total_nz
-        zarray(ig,eo) = zarray_full(iglob)
-      ENDDO
-      DO ig = local_nz+ngz/2,local_nz+ngz ! last ghost cells
-        iglob = ig+local_nz_offset-ngz/2
-        IF (iglob .GT. total_nz) &
-          iglob = iglob - total_nz
-        zarray(ig,eo) = zarray_full(iglob)
+      ! DO ig = 1,ngz/2 ! first ghost cells
+      !   iglob = ig+local_nz_offset-ngz/2
+      !   IF (iglob .LE. 0) &
+      !     iglob = iglob + total_nz
+      !   zarray(ig,eo) = zarray_full(iglob)
+      ! ENDDO
+      ! DO ig = local_nz+ngz/2,local_nz+ngz ! last ghost cells
+      !   iglob = ig+local_nz_offset-ngz/2
+      !   IF (iglob .GT. total_nz) &
+      !     iglob = iglob - total_nz
+      !   zarray(ig,eo) = zarray_full(iglob)
+      ! ENDDO
+      ! continue in z<pi and z>pi
+      DO ig = 1,ngz/2
+        zarray(local_nz+ngz/2+ig,eo) = zarray(local_nz+ngz/2,eo) + ig*deltaz
+        zarray(ig,eo) = zarray(1+ngz/2,eo) - (3-ig)*deltaz
       ENDDO
       ! Set up the flags to know if the process contains the tip and/or the tail
       ! of the z domain (important for z-boundary condition)
@@ -582,7 +598,6 @@ CONTAINS
         contains_zmax = .TRUE.
     ENDDO
     ! local weights for Simpson rule
-    ALLOCATE(zweights_SR(local_nz))
     IF(total_nz .EQ. 1) THEN
       zweights_SR = 1._xp
     ELSE
@@ -597,10 +612,10 @@ CONTAINS
   END SUBROUTINE set_zgrid
 
   SUBROUTINE set_kparray(gxx, gxy, gyy,hatB)
+    IMPLICIT NONE
     REAL(xp), DIMENSION(local_nz+ngz,nzgrid), INTENT(IN) :: gxx,gxy,gyy,hatB
     INTEGER     :: eo,iz,iky,ikx
     REAL(xp)    :: kx, ky
-    CALL allocate_array( kparray, 1,local_nky, 1,local_nkx, 1,local_nz+ngz, 1,nzgrid)
     DO eo = 1,nzgrid
       DO iz = 1,local_nz+ngz
         DO iky = 1,local_nky
diff --git a/src/miller_mod.F90 b/src/miller_mod.F90
index f6b9959f..ed65957e 100644
--- a/src/miller_mod.F90
+++ b/src/miller_mod.F90
@@ -6,10 +6,9 @@ MODULE miller
   USE basic
   USE parallel, ONLY: my_id, num_procs_z, nbr_U, nbr_D, comm0
   ! use coordinates,only: gcoor, get_dzprimedz
-  USE grid, ONLY: local_Nky, local_Nkx, local_nz, ngz, nzgrid, kyarray, kxarray, zarray, total_nz, local_nz_offset
+  USE grid, ONLY: local_Nky, local_Nkx, local_nz, ngz, nzgrid, kyarray, kxarray, zarray, total_nz, local_nz_offset, iodd, ieven
   ! use discretization
   USE lagrange_interpolation
-  ! use par_in, only: beta, sign_Ip_CW, sign_Bt_CW, Npol
   USE model
 
   implicit none
@@ -29,25 +28,24 @@ CONTAINS
   !>Set defaults for miller parameters
   subroutine set_miller_parameters(kappa_,s_kappa_,delta_,s_delta_,zeta_,s_zeta_)
     real(xp), INTENT(IN) :: kappa_,s_kappa_,delta_,s_delta_,zeta_,s_zeta_
-    rho     = -1.0
+    rho     = -1._xp
     kappa   = kappa_
     s_kappa = s_kappa_
     delta   = delta_
     s_delta = s_delta_
     zeta    = zeta_
     s_zeta  = s_zeta_
-    drR     = 0.0
-    drZ     = 0.0
-
-    thetak = 0.0
-    thetad = 0.0
+    drR     = 0._xp
+    drZ     = 0._xp
+    thetak  = 0._xp
+    thetad = 0._xp
 
   end subroutine set_miller_parameters
 
   !>Get Miller metric, magnetic field, jacobian etc.
   subroutine get_miller(trpeps,major_R,major_Z,q0,shat,Npol,amhd,edge_opt,&
-       C_y,C_xy,xpdx_pm_geom,gxx_,gyy_,gzz_,gxy_,gxz_,gyz_,dBdx_,dBdy_,&
-       Bfield_,jacobian_,dBdz_,R_hat_,Z_hat_,dxdR_,dxdZ_,Ckxky_,gradz_coeff_)
+       C_y,C_xy,Cyq0_x0,xpdx_pm_geom,gxx_,gxy_,gxz_,gyy_,gyz_,gzz_,dBdx_,dBdy_,dBdz_,&
+       Bfield_,jacobian_,R_hat_,Z_hat_,dxdR_,dxdZ_)
     !!!!!!!!!!!!!!!! GYACOMO INTERFACE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     real(xp), INTENT(INOUT) :: trpeps          ! eps in gyacomo (inverse aspect ratio)
     real(xp), INTENT(INOUT) :: major_R         ! major radius
@@ -58,20 +56,16 @@ CONTAINS
     real(xp), INTENT(INOUT) :: amhd            ! alpha mhd
     real(xp), INTENT(INOUT) :: edge_opt        ! optimization of point placement
     real(xp), INTENT(INOUT) :: xpdx_pm_geom    ! amplitude mag. eq. pressure grad.
-    real(xp), INTENT(INOUT) :: C_y, C_xy
-    real(xp), dimension(local_nz+ngz,nzgrid), INTENT(INOUT) :: &
-                                              gxx_,gyy_,gzz_,gxy_,gxz_,gyz_,&
-                                              dBdx_,dBdy_,Bfield_,jacobian_,&
-                                              dBdz_,R_hat_,Z_hat_,dxdR_,dxdZ_, &
-                                              gradz_coeff_
-    real(xp), dimension(local_Nky,local_Nkx,local_nz+ngz,nzgrid), INTENT(INOUT) :: Ckxky_
-    INTEGER :: iz, ikx, iky, eo
+    real(xp), INTENT(INOUT) :: C_y, C_xy, Cyq0_x0
+    real(xp), dimension(local_nz+ngz,nzgrid), INTENT(OUT) :: &
+                                              gxx_,gxy_,gxz_,gyy_,gyz_,gzz_,&
+                                              dBdx_,dBdy_,dBdz_,Bfield_,jacobian_,&
+                                              R_hat_,Z_hat_,dxdR_,dxdZ_
+    INTEGER :: iz,eo
     ! No parameter in gyacomo yet
-    real(xp) :: sign_Ip_CW=1 ! current sign (only normal current)
-    real(xp) :: sign_Bt_CW=1 ! current sign (only normal current)
+    real(xp) :: sign_Ip_CW=1._xp ! current sign (only normal current)
+    real(xp) :: sign_Bt_CW=1._xp ! current sign (only normal current)
     !!!!!!!!!!!!!! END GYACOMO INTERFACE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-    ! Auxiliary variables for curvature computation
-    real(xp) :: G1,G2,G3,Cx,Cy,ky,kx
 
     integer:: np, np_s, Npol_ext, Npol_s
 
@@ -96,9 +90,9 @@ CONTAINS
     real(xp), dimension(500*(Npol+1)):: gxx, gxy, gxz, gyy, gyz, gzz, dtheta_dchi_s, dBp_dchi_s, jacobian, dBdx, dBdz
     real(xp), dimension(500*(Npol+1)):: g_xx, g_xy, g_xz, g_yy, g_yz, g_zz, tmp_arr_s, dxdR_s, dxdZ_s, K_x, K_y !tmp_arr2
 
-    real(xp), dimension(1:total_nz):: gxx_out,gxy_out,gxz_out,gyy_out,gyz_out,gzz_out,Bfield_out,jacobian_out, dBdx_out, dBdz_out, chi_out
-    real(xp), dimension(1:total_nz):: R_out, Z_out, dxdR_out, dxdZ_out
-    real(xp):: d_inv, drPsi, dxPsi, dq_dx, dq_xpsi, R0, Z0, B0, F, D0_full, D1_full, D2_full, D3_full
+    real(xp), dimension(1:total_nz+ngz):: gxx_out,gxy_out,gxz_out,gyy_out,gyz_out,gzz_out,Bfield_out,jacobian_out, dBdx_out, dBdz_out, chi_out
+    real(xp), dimension(1:total_nz+ngz):: R_out, Z_out, dxdR_out, dxdZ_out
+    real(xp):: d_inv, drPsi, dxPsi, dq_dx, dq_dpsi, R0, Z0, B0, F, D0_full, D1_full, D2_full, D3_full
     !real(xp) :: Lnorm, Psi0 ! currently module-wide defined anyway
     real(xp):: pprime, ffprime, D0_mid, D1_mid, D2_mid, D3_mid, dx_drho, pi, mu_0, dzprimedz
     ! real(xp):: rho_a, psiN, drpsiN, CN2, CN3, Rcenter, Zcenter, drRcenter, drZcenter
@@ -111,139 +105,140 @@ CONTAINS
     np_s = 500*Npol_s
 
     rho = trpeps*major_R
-    if (rho.le.0.0) ERROR STOP '>> ERROR << flux surface radius not defined'
+    if (rho.le.0._xp) ERROR STOP '>> ERROR << flux surface radius not defined'
     trpeps = rho/major_R
 
     q0 = sign_Ip_CW * sign_Bt_CW * abs(q0)
 
     R0=major_R
-    B0=1.0*sign_Bt_CW
+    B0=1._xp*sign_Bt_CW
     F=R0*B0
     Z0=major_Z
-    pi = acos(-1.0)
-    mu_0=4.0*pi
+    pi = acos(-1._xp)
+    mu_0=4._xp*pi
 
     theta=linspace(-pi*Npol_ext,pi*Npol_ext-2._xp*pi*Npol_ext/np,np)
     d_inv=asin(delta)
 
-    thetaShift = 0.0
+    thetaShift = 0._xp
     iBmax = 1
+    bMaxShift = .true. ! limits the initialization routine to run no more than twice
+    do while (bMaxShift)
+      !flux surface parametrization
+      thAdj = theta + thetaShift
+      if (zeta/=0._xp .or. s_zeta/=0._xp) then
+        R = R0 + rho*Cos(thAdj + d_inv*Sin(thAdj))
+        Z = Z0 + kappa*rho*Sin(thAdj + zeta*Sin(2*thAdj))
+
+        R_rho = drR + Cos(thAdj + d_inv*Sin(thAdj)) - s_delta*Sin(thAdj)*Sin(thAdj + d_inv*Sin(thAdj))
+        Z_rho = drZ + kappa*s_zeta*Cos(thAdj + zeta*Sin(2*thAdj))*Sin(2*thAdj) &
+              + kappa*Sin(thAdj + zeta*Sin(2*thAdj)) + kappa*s_kappa*Sin(thAdj + zeta*Sin(2*thAdj))
+
+        R_theta = -(rho*(1 + d_inv*Cos(thAdj))*Sin(thAdj + d_inv*Sin(thAdj)))
+        Z_theta = kappa*rho*(1 + 2*zeta*Cos(2*thAdj))*Cos(thAdj + zeta*Sin(2*thAdj))
+
+        R_theta_theta = -(rho*(1 + d_inv*Cos(thAdj))**2*Cos(thAdj + d_inv*Sin(thAdj))) &
+              + d_inv*rho*Sin(thAdj)*Sin(thAdj + d_inv*Sin(thAdj))
+        Z_theta_theta = -4*kappa*rho*zeta*Cos(thAdj + zeta*Sin(2*thAdj))*Sin(2*thAdj) &
+              - kappa*rho*(1 + 2*zeta*Cos(2*thAdj))**2*Sin(thAdj + zeta*Sin(2*thAdj))
+      else
+        Rcirc = rho*Cos(thAdj - thetad + thetak)
+        Zcirc = rho*Sin(thAdj - thetad + thetak)
+        Relong = Rcirc
+        Zelong = Zcirc + (-1 + kappa)*rho*Sin(thAdj - thetad + thetak)
+        RelongTilt = Relong*Cos(thetad - thetak) - Zelong*Sin(thetad - thetak)
+        ZelongTilt = Zelong*Cos(thetad - thetak) + Relong*Sin(thetad - thetak)
+        Rtri = RelongTilt - rho*Cos(thAdj) + rho*Cos(thAdj + delta*Sin(thAdj))
+        Ztri = ZelongTilt
+        RtriTilt = Rtri*Cos(thetad) + Ztri*Sin(thetad)
+        ZtriTilt = Ztri*Cos(thetad) - Rtri*Sin(thetad)
+        R = R0 + RtriTilt
+        Z = Z0 + ZtriTilt
+
+        drRcirc = Cos(thAdj - thetad + thetak)
+        drZcirc = Sin(thAdj - thetad + thetak)
+        drRelong = drRcirc
+        drZelong = drZcirc - (1 - kappa - kappa*s_kappa)*Sin(thAdj - thetad + thetak)
+        drRelongTilt = drRelong*Cos(thetad - thetak) - drZelong*Sin(thetad - thetak)
+        drZelongTilt = drZelong*Cos(thetad - thetak) + drRelong*Sin(thetad - thetak)
+        drRtri = drRelongTilt - Cos(thAdj) + Cos(thAdj + delta*Sin(thAdj)) &
+              - s_delta*Sin(thAdj)*Sin(thAdj + delta*Sin(thAdj))
+        drZtri = drZelongTilt
+        drRtriTilt = drRtri*Cos(thetad) + drZtri*Sin(thetad)
+        drZtriTilt = drZtri*Cos(thetad) - drRtri*Sin(thetad)
+        R_rho = drR + drRtriTilt
+        Z_rho = drZ + drZtriTilt
+
+        dtRcirc = -(rho*Sin(thAdj - thetad + thetak))
+        dtZcirc = rho*Cos(thAdj - thetad + thetak)
+        dtRelong = dtRcirc
+        dtZelong = dtZcirc + (-1 + kappa)*rho*Cos(thAdj - thetad + thetak)
+        dtRelongTilt = dtRelong*Cos(thetad - thetak) - dtZelong*Sin(thetad - thetak)
+        dtZelongTilt = dtZelong*Cos(thetad - thetak) + dtRelong*Sin(thetad - thetak)
+        dtRtri = dtRelongTilt + rho*Sin(thAdj) - rho*(1 + delta*Cos(thAdj))*Sin(thAdj + delta*Sin(thAdj))
+        dtZtri = dtZelongTilt
+        dtRtriTilt = dtRtri*Cos(thetad) + dtZtri*Sin(thetad)
+        dtZtriTilt = dtZtri*Cos(thetad) - dtRtri*Sin(thetad)
+        R_theta = dtRtriTilt
+        Z_theta = dtZtriTilt
+
+        dtdtRcirc = -(rho*Cos(thAdj - thetad + thetak))
+        dtdtZcirc = -(rho*Sin(thAdj - thetad + thetak))
+        dtdtRelong = dtdtRcirc
+        dtdtZelong = dtdtZcirc - (-1 + kappa)*rho*Sin(thAdj - thetad + thetak)
+        dtdtRelongTilt = dtdtRelong*Cos(thetad - thetak) - dtdtZelong*Sin(thetad - thetak)
+        dtdtZelongTilt = dtdtZelong*Cos(thetad - thetak) + dtdtRelong*Sin(thetad - thetak)
+        dtdtRtri = dtdtRelongTilt + rho*Cos(thAdj) - rho*(1 + delta*Cos(thAdj))**2*Cos(thAdj + delta*Sin(thAdj)) &
+              + delta*rho*Sin(thAdj)*Sin(thAdj + delta*Sin(thAdj))
+        dtdtZtri = dtdtZelongTilt
+        dtdtRtriTilt = dtdtRtri*Cos(thetad) + dtdtZtri*Sin(thetad)
+        dtdtZtriTilt = dtdtZtri*Cos(thetad) - dtdtRtri*Sin(thetad)
+        R_theta_theta = dtdtRtriTilt
+        Z_theta_theta = dtdtZtriTilt
+      endif
 
-    !flux surface parametrization
-    thAdj = theta + thetaShift
-    if (zeta/=0.0 .or. s_zeta/=0.0) then
-       R = R0 + rho*Cos(thAdj + d_inv*Sin(thAdj))
-       Z = Z0 + kappa*rho*Sin(thAdj + zeta*Sin(2*thAdj))
-
-       R_rho = drR + Cos(thAdj + d_inv*Sin(thAdj)) - s_delta*Sin(thAdj)*Sin(thAdj + d_inv*Sin(thAdj))
-       Z_rho = drZ + kappa*s_zeta*Cos(thAdj + zeta*Sin(2*thAdj))*Sin(2*thAdj) &
-            + kappa*Sin(thAdj + zeta*Sin(2*thAdj)) + kappa*s_kappa*Sin(thAdj + zeta*Sin(2*thAdj))
-
-       R_theta = -(rho*(1 + d_inv*Cos(thAdj))*Sin(thAdj + d_inv*Sin(thAdj)))
-       Z_theta = kappa*rho*(1 + 2*zeta*Cos(2*thAdj))*Cos(thAdj + zeta*Sin(2*thAdj))
-
-       R_theta_theta = -(rho*(1 + d_inv*Cos(thAdj))**2*Cos(thAdj + d_inv*Sin(thAdj))) &
-            + d_inv*rho*Sin(thAdj)*Sin(thAdj + d_inv*Sin(thAdj))
-       Z_theta_theta = -4*kappa*rho*zeta*Cos(thAdj + zeta*Sin(2*thAdj))*Sin(2*thAdj) &
-            - kappa*rho*(1 + 2*zeta*Cos(2*thAdj))**2*Sin(thAdj + zeta*Sin(2*thAdj))
-    else
-       Rcirc = rho*Cos(thAdj - thetad + thetak)
-       Zcirc = rho*Sin(thAdj - thetad + thetak)
-       Relong = Rcirc
-       Zelong = Zcirc + (-1 + kappa)*rho*Sin(thAdj - thetad + thetak)
-       RelongTilt = Relong*Cos(thetad - thetak) - Zelong*Sin(thetad - thetak)
-       ZelongTilt = Zelong*Cos(thetad - thetak) + Relong*Sin(thetad - thetak)
-       Rtri = RelongTilt - rho*Cos(thAdj) + rho*Cos(thAdj + delta*Sin(thAdj))
-       Ztri = ZelongTilt
-       RtriTilt = Rtri*Cos(thetad) + Ztri*Sin(thetad)
-       ZtriTilt = Ztri*Cos(thetad) - Rtri*Sin(thetad)
-       R = R0 + RtriTilt
-       Z = Z0 + ZtriTilt
-
-       drRcirc = Cos(thAdj - thetad + thetak)
-       drZcirc = Sin(thAdj - thetad + thetak)
-       drRelong = drRcirc
-       drZelong = drZcirc - (1 - kappa - kappa*s_kappa)*Sin(thAdj - thetad + thetak)
-       drRelongTilt = drRelong*Cos(thetad - thetak) - drZelong*Sin(thetad - thetak)
-       drZelongTilt = drZelong*Cos(thetad - thetak) + drRelong*Sin(thetad - thetak)
-       drRtri = drRelongTilt - Cos(thAdj) + Cos(thAdj + delta*Sin(thAdj)) &
-            - s_delta*Sin(thAdj)*Sin(thAdj + delta*Sin(thAdj))
-       drZtri = drZelongTilt
-       drRtriTilt = drRtri*Cos(thetad) + drZtri*Sin(thetad)
-       drZtriTilt = drZtri*Cos(thetad) - drRtri*Sin(thetad)
-       R_rho = drR + drRtriTilt
-       Z_rho = drZ + drZtriTilt
-
-       dtRcirc = -(rho*Sin(thAdj - thetad + thetak))
-       dtZcirc = rho*Cos(thAdj - thetad + thetak)
-       dtRelong = dtRcirc
-       dtZelong = dtZcirc + (-1 + kappa)*rho*Cos(thAdj - thetad + thetak)
-       dtRelongTilt = dtRelong*Cos(thetad - thetak) - dtZelong*Sin(thetad - thetak)
-       dtZelongTilt = dtZelong*Cos(thetad - thetak) + dtRelong*Sin(thetad - thetak)
-       dtRtri = dtRelongTilt + rho*Sin(thAdj) - rho*(1 + delta*Cos(thAdj))*Sin(thAdj + delta*Sin(thAdj))
-       dtZtri = dtZelongTilt
-       dtRtriTilt = dtRtri*Cos(thetad) + dtZtri*Sin(thetad)
-       dtZtriTilt = dtZtri*Cos(thetad) - dtRtri*Sin(thetad)
-       R_theta = dtRtriTilt
-       Z_theta = dtZtriTilt
-
-       dtdtRcirc = -(rho*Cos(thAdj - thetad + thetak))
-       dtdtZcirc = -(rho*Sin(thAdj - thetad + thetak))
-       dtdtRelong = dtdtRcirc
-       dtdtZelong = dtdtZcirc - (-1 + kappa)*rho*Sin(thAdj - thetad + thetak)
-       dtdtRelongTilt = dtdtRelong*Cos(thetad - thetak) - dtdtZelong*Sin(thetad - thetak)
-       dtdtZelongTilt = dtdtZelong*Cos(thetad - thetak) + dtdtRelong*Sin(thetad - thetak)
-       dtdtRtri = dtdtRelongTilt + rho*Cos(thAdj) - rho*(1 + delta*Cos(thAdj))**2*Cos(thAdj + delta*Sin(thAdj)) &
-            + delta*rho*Sin(thAdj)*Sin(thAdj + delta*Sin(thAdj))
-       dtdtZtri = dtdtZelongTilt
-       dtdtRtriTilt = dtdtRtri*Cos(thetad) + dtdtZtri*Sin(thetad)
-       dtdtZtriTilt = dtdtZtri*Cos(thetad) - dtdtRtri*Sin(thetad)
-       R_theta_theta = dtdtRtriTilt
-       Z_theta_theta = dtdtZtriTilt
-    endif
-
-    !dl/dtheta
-    dlp=(R_theta**2+Z_theta**2)**0.5
-
-    !curvature radius
-    Rc=dlp**3*(R_theta*Z_theta_theta-Z_theta*R_theta_theta)**(-1)
-
-    ! some useful quantities (see papers for definition of u)
-    cosu=Z_theta/dlp
-    sinu=-R_theta/dlp
-
-    !Jacobian J_r = (dPsi/dr) J_psi = (dPsi/dr) / [(nabla fz x nabla psi)* nabla theta]
-    !             = R * (dR/drho dZ/dtheta - dR/dtheta dZ/drho) = R dlp / |nabla r|
-    J_r=R*(R_rho*Z_theta-R_theta*Z_rho)
-
-    !From definition of q = 1/(2 pi) int (B nabla fz) / (B nabla theta) dtheta:
-    !dPsi/dr = sign_Bt sign_Ip / (2 pi q) int F / R^2 J_r dtheta
-    !        = F / (2 pi |q|) int J_r/R^2 dtheta
-    tmp_arr=J_r/R**2
-    drPsi=sign_Ip_CW*F/(2.*pi*Npol_ext*q0)*sum(tmp_arr)*2*pi*Npol_ext/np !dlp_int(tmp_arr,1.0)
-
-    !Poloidal field (Bp = Bvec * nabla l)
-    Bp=sign_Ip_CW * drPsi / J_r * dlp
-
-    !toroidal field
-    Bphi=F/R
-
-    !total modulus of Bfield
-    B=sqrt(Bphi**2+Bp**2)
-
-    bMaxShift = .false.
-    ! if (thetaShift==0.0.and.trim(magn_geometry).ne.'miller_general') then
-    if (thetaShift==0.0) then
-      do i = 2,np-1
-         if (B(iBmax)<B(i)) then
-            iBmax = i
-         end if
-      enddo
-      if (iBmax/=1) then
-         bMaxShift = .true.
-         thetaShift = theta(iBmax)-theta(1)
+      !dl/dtheta
+      dlp=(R_theta**2+Z_theta**2)**0.5_xp
+
+      !curvature radius
+      Rc=dlp**3*(R_theta*Z_theta_theta-Z_theta*R_theta_theta)**(-1)
+
+      ! some useful quantities (see papers for definition of u)
+      cosu=Z_theta/dlp
+      sinu=-R_theta/dlp
+
+      !Jacobian J_r = (dPsi/dr) J_psi = (dPsi/dr) / [(nabla fz x nabla psi)* nabla theta]
+      !             = R * (dR/drho dZ/dtheta - dR/dtheta dZ/drho) = R dlp / |nabla r|
+      J_r=R*(R_rho*Z_theta-R_theta*Z_rho)
+
+      !From definition of q = 1/(2 pi) int (B nabla fz) / (B nabla theta) dtheta:
+      !dPsi/dr = sign_Bt sign_Ip / (2 pi q) int F / R^2 J_r dtheta
+      !        = F / (2 pi |q|) int J_r/R^2 dtheta
+      tmp_arr=J_r/R**2
+      drPsi=sign_Ip_CW*F/(2._xp*pi*Npol_ext*q0)*sum(tmp_arr)*2._xp*pi*Npol_ext/np !dlp_int(tmp_arr,1.0)
+
+      !Poloidal field (Bp = Bvec * nabla l)
+      Bp=sign_Ip_CW * drPsi / J_r * dlp
+
+      !toroidal field
+      Bphi=F/R
+
+      !total modulus of Bfield
+      B=sqrt(Bphi**2+Bp**2)
+
+      bMaxShift = .false.
+      if (thetaShift==0._xp) then
+        do i = 2,np-1
+          if (B(iBmax)<B(i)) then
+              iBmax = i
+          end if
+        enddo
+        if (iBmax/=1) then
+          bMaxShift = .true.
+          thetaShift = theta(iBmax)-theta(1)
+        end if
       end if
-    end if
+    enddo
 
     !definition of radial coordinate! dx_drho=1 --> x = r
     dx_drho=1. !drPsi/Psi0*Lnorm*q0
@@ -257,14 +252,15 @@ CONTAINS
             "Setting C_xy = ",C_xy,' C_y = ', C_y," C_x' = ", 1./dxPsi
        write(*,'(A,ES12.4)') "B_unit/Bref conversion factor = ", q0/rho*drPsi
        write(*,'(A,ES12.4)') "dPsi/dr = ", drPsi
-       if (thetaShift.ne.0.0) write(*,'(A,ES12.4)') "thetaShift = ", thetaShift
+       if (thetaShift.ne.0._xp) write(*,'(A,ES12.4)') "thetaShift = ", thetaShift
     endif
 
 
     !--------shear is expected to be defined as rho/q*dq/drho--------!
-    dq_dx=shat*q0/rho/dx_drho
-    dq_xpsi=dq_dx/dxPsi
-    pprime=-amhd/q0**2/R0/(2*mu_0)*B0**2/drPsi
+    dq_dx   = shat*q0/rho/dx_drho
+    Cyq0_x0 = C_y*q0/rho
+    dq_dpsi = dq_dx/dxPsi
+    pprime  = -amhd/q0**2/R0/(2*mu_0)*B0**2/drPsi
 
     !neg. xpdx normalized to magnetic pressure for pressure term
     xpdx_pm_geom=amhd/q0**2/R0/dx_drho
@@ -274,7 +270,7 @@ CONTAINS
 
     !integrals for ffprime evaluation
     do i=1,np
-       tmp_arr=(2./Rc-2.*cosu/R)/(R*psi1**2)
+       tmp_arr=(2._xp/Rc-2._xp*cosu/R)/(R*psi1**2)
        D0(i)=-F*dlp_int_ind(tmp_arr,dlp,i)
        tmp_arr=B**2*R/psi1**3
        D1(i)=-dlp_int_ind(tmp_arr,dlp,i)/F
@@ -283,7 +279,7 @@ CONTAINS
        tmp_arr=1./(R*psi1)
        D3(i)=-dlp_int_ind(tmp_arr,dlp,i)*F
     enddo
-    tmp_arr=(2./Rc-2.*cosu/R)/(R*psi1**2)
+    tmp_arr=(2._xp/Rc-2._xp*cosu/R)/(R*psi1**2)
     D0_full=-F*dlp_int(tmp_arr,dlp)
     tmp_arr=B**2*R/psi1**3
     D1_full=-dlp_int(tmp_arr,dlp)/F
@@ -296,7 +292,7 @@ CONTAINS
     D2_mid=D2(np/2+1)
     D3_mid=D3(np/2+1)
 
-    ffprime=-(sign_Ip_CW*dq_xpsi*2.*pi*Npol_ext+D0_full+D2_full*pprime)/D1_full
+    ffprime=-(sign_Ip_CW*dq_dpsi*2._xp*pi*Npol_ext+D0_full+D2_full*pprime)/D1_full
 
     if (my_id==0) then
        write(*,'(A,ES12.4)') "ffprime = ", ffprime
@@ -318,7 +314,7 @@ CONTAINS
     !new grid equidistant in straight field line angle
     chi_s = linspace(-pi*Npol_s,pi*Npol_s-2*pi*Npol_s/np_s,np_s)
 
-    if (sign_Ip_CW.lt.0.0) then !make chi increasing function to not confuse lag3interp
+    if (sign_Ip_CW.lt.0._xp) then !make chi increasing function to not confuse lag3interp
        tmp_reverse = chi(np:1:-1)
        theta_reverse = theta(np:1:-1)
        call lag3interp(theta_reverse,tmp_reverse,np,theta_s,chi_s,np_s)
@@ -332,7 +328,7 @@ CONTAINS
     !arrays equidistant in straight field line angle
     thAdj_s = theta_s + thetaShift
 
-    if (zeta/=0.0 .or. s_zeta/=0.0) then
+    if (zeta/=0._xp .or. s_zeta/=0._xp) then
       R_s = R0 + rho*Cos(thAdj_s + d_inv*Sin(thAdj_s))
       Z_s = Z0 + kappa*rho*Sin(thAdj_s + zeta*Sin(2*thAdj_s))
 
@@ -366,7 +362,7 @@ CONTAINS
       R_theta_s = dtheta_dchi_s*dtRtriTilt_s
       Z_theta_s = dtheta_dchi_s*dtZtriTilt_s
     endif
-    if (sign_Ip_CW.lt.0.0) then
+    if (sign_Ip_CW.lt.0._xp) then
        call lag3interp(nu1,theta,np,tmp_arr_s,theta_s_reverse,np_s)
        nu1_s = tmp_arr_s(np_s:1:-1)
        call lag3interp(Bp,theta,np,tmp_arr_s,theta_s_reverse,np_s)
@@ -402,13 +398,13 @@ CONTAINS
     dnu_dl_s=-F/(R_s*psi1_s)
     grad_nu_s=sqrt(dnu_drho_s**2+dnu_dl_s**2)
 
-    !contravariant metric coefficients (varrho,l,fz)->(x,y,z)
+    !contravariant metric coefficients (varrho,l,phi)->(x,y,z)
     gxx=(psi1_s/dxPsi)**2
     gxy=-psi1_s/dxPsi*C_y*sign_Ip_CW*nu1_s
-    gxz=-psi1_s/dxPsi*(nu1_s+psi1_s*dq_xpsi*chi_s)/q0
+    gxz=-psi1_s/dxPsi*(nu1_s+psi1_s*dq_dpsi*chi_s)/q0
     gyy=C_y**2*(grad_nu_s**2+1/R_s**2)
-    gyz=sign_Ip_CW*C_y/q0*(grad_nu_s**2+dq_xpsi*nu1_s*psi1_s*chi_s)
-    gzz=1./q0**2*(grad_nu_s**2+2.*dq_xpsi*nu1_s*psi1_s*chi_s+(dq_xpsi*psi1_s*chi_s)**2)
+    gyz=sign_Ip_CW*C_y/q0*(grad_nu_s**2+dq_dpsi*nu1_s*psi1_s*chi_s)
+    gzz=1./q0**2*(grad_nu_s**2+2.*dq_dpsi*nu1_s*psi1_s*chi_s+(dq_dpsi*psi1_s*chi_s)**2)
 
     jacobian=1./sqrt(gxx*gyy*gzz + 2.*gxy*gyz*gxz - gxz**2*gyy - gyz**2*gxx - gzz*gxy**2)
 
@@ -422,32 +418,35 @@ CONTAINS
 
     !Bfield derivatives
     !dBdx = e_x * nabla B = J (nabla y x nabla z) * nabla B
-    dBdx=jacobian*C_y/(q0*R_s)*(F/(R_s*psi1_s)*dB_drho_s+(nu1_s+dq_xpsi*chi_s*psi1_s)*dB_dl_s)
+    dBdx=jacobian*C_y/(q0*R_s)*(F/(R_s*psi1_s)*dB_drho_s+(nu1_s+dq_dpsi*chi_s*psi1_s)*dB_dl_s)
     dBdz=1./B_s*(Bp_s*dBp_dchi_s-F**2/R_s**3*R_theta_s)
 
-    !curvature terms (these are just local and will be recalculated in geometry.F90)
-    K_x = (0.-g_yz/g_zz*dBdz)
+    !curvature terms (these are just local and will be recalculated in geometry module)
+    K_x = (0._xp-g_yz/g_zz*dBdz)
     K_y = (dBdx-g_xz/g_zz*dBdz)
 
     !(R,Z) derivatives for visualization
     dxdR_s = dx_drho/drPsi*psi1_s*cosu_s
     dxdZ_s = dx_drho/drPsi*psi1_s*sinu_s
-
-    if (edge_opt==0.0) then
-       !gene z-grid
-       chi_out=linspace(-pi*Npol,pi*Npol-2*pi*Npol/total_nz,total_nz)
+    ! GHOSTS ADAPTED VERSION
+    if (edge_opt==0._xp) then
+      !gyacomo z-grid wo ghosts
+      ! chi_out=linspace(-pi*Npol,pi*Npol-2*pi*Npol/total_nz,total_nz)
+      !gyacomo z-grid with ghosts
+      chi_out=linspace(-pi*Npol-4._xp*pi*Npol/total_nz,pi*Npol+2._xp*pi*Npol/total_nz,total_nz+ngz)
     else
+      ERROR STOP '>> ERROR << ghosts not implemented for edge_opt yet'
        !new parallel coordinate chi_out==zprime
        !see also tracer_aux.F90
-       if (Npol>1) ERROR STOP '>> ERROR << Npol>1 has not been implemented for edge_opt=\=0.0'
+       if (Npol>1) ERROR STOP '>> ERROR << Npol>1 has not been implemented for edge_opt=\=0._xp'
        do k=1,total_nz
-          chi_out(k)=sinh((-pi+k*2.*pi/total_nz)*log(edge_opt*pi+sqrt(edge_opt**2*pi**2+1))/pi)/edge_opt
+          chi_out(k)=sinh((-pi+k*2._xp*pi/total_nz)*log(edge_opt*pi+sqrt(edge_opt**2*pi**2+1))/pi)/edge_opt
        enddo
        !transform metrics according to chain rule
        do k=1,np_s
          !>dz'/dz conversion for edge_opt as function of z
           if (edge_opt.gt.0) then
-             dzprimedz = edge_opt*pi/log(edge_opt*pi+sqrt((edge_opt*pi)**2+1))/&
+             dzprimedz = edge_opt*pi/log(edge_opt*pi+sqrt((edge_opt*pi)**2+1._xp))/&
                   sqrt((edge_opt*chi_s(k))**2+1)
           else
              dzprimedz = 1.0
@@ -459,123 +458,117 @@ CONTAINS
           dBdz(k)=dBdz(k)/dzprimedz
        enddo
     endif !edge_opt
-
-    !interpolate down to GENE z-grid
-    call lag3interp(gxx,chi_s,np_s,gxx_out,chi_out,total_nz)
-    call lag3interp(gxy,chi_s,np_s,gxy_out,chi_out,total_nz)
-    call lag3interp(gxz,chi_s,np_s,gxz_out,chi_out,total_nz)
-    call lag3interp(gyy,chi_s,np_s,gyy_out,chi_out,total_nz)
-    call lag3interp(gyz,chi_s,np_s,gyz_out,chi_out,total_nz)
-    call lag3interp(gzz,chi_s,np_s,gzz_out,chi_out,total_nz)
-    call lag3interp(B_s,chi_s,np_s,Bfield_out,chi_out,total_nz)
-    call lag3interp(jacobian,chi_s,np_s,jacobian_out,chi_out,total_nz)
-    call lag3interp(dBdx,chi_s,np_s,dBdx_out,chi_out,total_nz)
-    call lag3interp(dBdz,chi_s,np_s,dBdz_out,chi_out,total_nz)
-    call lag3interp(R_s,chi_s,np_s,R_out,chi_out,total_nz)
-    call lag3interp(Z_s,chi_s,np_s,Z_out,chi_out,total_nz)
-    call lag3interp(dxdR_s,chi_s,np_s,dxdR_out,chi_out,total_nz)
-    call lag3interp(dxdZ_s,chi_s,np_s,dxdZ_out,chi_out,total_nz)
-    ! Fill the interior of the geom arrays with the results
-    do eo=1,nzgrid
-      DO iz = 1,local_nz
-        gxx_(iz+ngz/2,eo)      = gxx_out(iz+local_nz_offset)
-        gyy_(iz+ngz/2,eo)      = gyy_out(iz+local_nz_offset)
-        gxz_(iz+ngz/2,eo)      = gxz_out(iz+local_nz_offset)
-        gyz_(iz+ngz/2,eo)      = gyz_out(iz+local_nz_offset)
-        dBdx_(iz+ngz/2,eo)     = dBdx_out(iz+local_nz_offset)
-        dBdy_(iz+ngz/2,eo)     = 0.
-        gxy_(iz+ngz/2,eo)      = gxy_out(iz+local_nz_offset)
-        gzz_(iz+ngz/2,eo)      = gzz_out(iz+local_nz_offset)
-        Bfield_(iz+ngz/2,eo)   = Bfield_out(iz+local_nz_offset)
-        jacobian_(iz+ngz/2,eo) = jacobian_out(iz+local_nz_offset)
-        dBdz_(iz+ngz/2,eo)     = dBdz_out(iz+local_nz_offset)
-        R_hat_(iz+ngz/2,eo)    = R_out(iz+local_nz_offset)
-        Z_hat_(iz+ngz/2,eo)    = Z_out(iz+local_nz_offset)
-        dxdR_(iz+ngz/2,eo)     = dxdR_out(iz+local_nz_offset)
-        dxdZ_(iz+ngz/2,eo)     = dxdZ_out(iz+local_nz_offset)
-      ENDDO
-      !! UPDATE GHOSTS VALUES (since the miller function in GENE does not)
-      CALL update_ghosts_z(gxx_(:,eo))
-      CALL update_ghosts_z(gyy_(:,eo))
-      CALL update_ghosts_z(gxz_(:,eo))
-      CALL update_ghosts_z(gxy_(:,eo))
-      CALL update_ghosts_z(gzz_(:,eo))
-      CALL update_ghosts_z(Bfield_(:,eo))
-      CALL update_ghosts_z(dBdx_(:,eo))
-      CALL update_ghosts_z(dBdy_(:,eo))
-      CALL update_ghosts_z(dBdz_(:,eo))
-      CALL update_ghosts_z(jacobian_(:,eo))
-      CALL update_ghosts_z(R_hat_(:,eo))
-      CALL update_ghosts_z(Z_hat_(:,eo))
-      CALL update_ghosts_z(dxdR_(:,eo))
-      CALL update_ghosts_z(dxdZ_(:,eo))
-
-      ! Curvature operator (Frei et al. 2022 eq 2.15)
-      DO iz = 1,local_nz+ngz
-        G1 = gxy_(iz,eo)*gxy_(iz,eo)-gxx_(iz,eo)*gyy_(iz,eo)
-        G2 = gxy_(iz,eo)*gxz_(iz,eo)-gxx_(iz,eo)*gyz_(iz,eo)
-        G3 = gyy_(iz,eo)*gxz_(iz,eo)-gxy_(iz,eo)*gyz_(iz,eo)
-        Cx = (G1*dBdy_(iz,eo) + G2*dBdz_(iz,eo))/Bfield_(iz,eo)
-        Cy = (G3*dBdz_(iz,eo) - G1*dBdx_(iz,eo))/Bfield_(iz,eo)
-
-        DO iky = 1,local_Nky
-          ky = kyarray(iky)
-          DO ikx= 1,local_Nkx
-            kx = kxarray(ikx)
-            Ckxky_(iky, ikx, iz,eo) = Cx*kx + Cy*ky
-          ENDDO
-        ENDDO
-        ! coefficient in the front of parallel derivative
-        gradz_coeff_(iz,eo) = 1._xp / jacobian_(iz,eo) / Bfield_(iz,eo)
+    ! interpolate with ghosts
+    call lag3interp(gxx,chi_s,np_s,gxx_out,chi_out,total_nz+ngz)
+    call lag3interp(gxy,chi_s,np_s,gxy_out,chi_out,total_nz+ngz)
+    call lag3interp(gxz,chi_s,np_s,gxz_out,chi_out,total_nz+ngz)
+    call lag3interp(gyy,chi_s,np_s,gyy_out,chi_out,total_nz+ngz)
+    call lag3interp(gyz,chi_s,np_s,gyz_out,chi_out,total_nz+ngz)
+    call lag3interp(gzz,chi_s,np_s,gzz_out,chi_out,total_nz+ngz)
+    call lag3interp(B_s,chi_s,np_s,Bfield_out,chi_out,total_nz+ngz)
+    call lag3interp(dBdx,chi_s,np_s,dBdx_out,chi_out,total_nz+ngz)
+    call lag3interp(dBdz,chi_s,np_s,dBdz_out,chi_out,total_nz+ngz)
+    call lag3interp(jacobian,chi_s,np_s,jacobian_out,chi_out,total_nz+ngz)
+    call lag3interp(R_s,chi_s,np_s,R_out,chi_out,total_nz+ngz)
+    call lag3interp(Z_s,chi_s,np_s,Z_out,chi_out,total_nz+ngz)
+    call lag3interp(dxdR_s,chi_s,np_s,dxdR_out,chi_out,total_nz+ngz)
+    call lag3interp(dxdZ_s,chi_s,np_s,dxdZ_out,chi_out,total_nz+ngz)
+    ! Fill the local geom arrays with the results
+    do eo=iodd,ieven
+      DO iz = 1,local_nz + ngz
+        gxx_(iz,eo)      = gxx_out(iz+local_nz_offset)
+        gxy_(iz,eo)      = gxy_out(iz+local_nz_offset)
+        gxz_(iz,eo)      = gxz_out(iz+local_nz_offset)
+        gyy_(iz,eo)      = gyy_out(iz+local_nz_offset)
+        gyz_(iz,eo)      = gyz_out(iz+local_nz_offset)
+        gzz_(iz,eo)      = gzz_out(iz+local_nz_offset)
+        Bfield_(iz,eo)   = Bfield_out(iz+local_nz_offset)
+        dBdx_(iz,eo)     = dBdx_out(iz+local_nz_offset)
+        dBdy_(iz,eo)     = 0._xp
+        dBdz_(iz,eo)     = dBdz_out(iz+local_nz_offset)
+        jacobian_(iz,eo) = jacobian_out(iz+local_nz_offset)
+        R_hat_(iz,eo)    = R_out(iz+local_nz_offset)
+        Z_hat_(iz,eo)    = Z_out(iz+local_nz_offset)
+        dxdR_(iz,eo)     = dxdR_out(iz+local_nz_offset)
+        dxdZ_(iz,eo)     = dxdZ_out(iz+local_nz_offset)
       ENDDO
-  ENDDO
-
+    ENDDO
   contains
 
-
-    SUBROUTINE update_ghosts_z(fz_)
+    ! Update (and communicate) ghosts of the metric arrays
+    SUBROUTINE update_ghosts_z(fz_,eo,periodic)
       IMPLICIT NONE
       ! INTEGER,  INTENT(IN) :: nztot_
-      REAL(xp), DIMENSION(1:local_nz+ngz), INTENT(INOUT) :: fz_
-      REAL(xp), DIMENSION(-2:2) :: buff
-      INTEGER :: status(MPI_STATUS_SIZE), count, last, first
-      last = local_nz+ngz/2
+      REAL(xp), DIMENSION(local_nz+ngz), INTENT(INOUT) :: fz_
+      LOGICAL,  INTENT(IN) :: periodic
+      INTEGER,  INTENT(IN) :: eo !even/odd z grid
+      REAL(xp), DIMENSION(-ngz/2:ngz/2) :: buff
+      INTEGER :: status(MPI_STATUS_SIZE), count, last, first, ig
+      REAL(xp):: dfdz, beta, z1, z2, f1, f2, z3, f3
       first= 1 + ngz/2
-      IF(total_nz .GT. 1) THEN
-        IF (num_procs_z .GT. 1) THEN
-          CALL MPI_BARRIER(MPI_COMM_WORLD,ierr)
-            count = 1 ! one point to exchange
-            !!!!!!!!!!! Send ghost to up neighbour !!!!!!!!!!!!!!!!!!!!!!
-            CALL mpi_sendrecv(fz_(last), count, MPI_DOUBLE, nbr_U, 0, & ! Send to Up the last
-                               buff(-1), count, MPI_DOUBLE, nbr_D, 0, & ! Receive from Down the first-1
-                              comm0, status, ierr)
-
-            CALL mpi_sendrecv(fz_(last-1), count, MPI_DOUBLE, nbr_U, 0, & ! Send to Up the last
-                                 buff(-2), count, MPI_DOUBLE, nbr_D, 0, & ! Receive from Down the first-2
-                              comm0, status, ierr)
-
-            !!!!!!!!!!! Send ghost to down neighbour !!!!!!!!!!!!!!!!!!!!!!
-            CALL mpi_sendrecv(fz_(first), count, MPI_DOUBLE, nbr_D, 0, & ! Send to Down the first
-                                buff(+1), count, MPI_DOUBLE, nbr_U, 0, & ! Recieve from Up the last+1
-                              comm0, status, ierr)
-
-            CALL mpi_sendrecv(fz_(first+1), count, MPI_DOUBLE, nbr_D, 0, & ! Send to Down the first
-                                  buff(+2), count, MPI_DOUBLE, nbr_U, 0, & ! Recieve from Up the last+2
-                              comm0, status, ierr)
-         ELSE
-           buff(-1) = fz_(last  )
-           buff(-2) = fz_(last-1)
-           buff(+1) = fz_(first  )
-           buff(+2) = fz_(first+1)
-         ENDIF
-         fz_(last +1) = buff(+1)
-         fz_(last +2) = buff(+2)
-         fz_(first-1) = buff(-1)
-         fz_(first-2) = buff(-2)
+      last = local_nz+ngz/2
+      count = 1 ! one point to exchange
+      IF (num_procs_z .GT. 1) THEN
+        CALL MPI_BARRIER(MPI_COMM_WORLD,ierr)
+        !!!!!!!!!!! Send ghost to up neighbour !!!!!!!!!!!!!!!!!!!!!!
+        DO ig = 1,ngz/2
+          CALL mpi_sendrecv(fz_(last-(ig-1)), count, mpi_xp_r, nbr_U, 1206+ig, & ! Send to Up the last
+          buff(-ig),        count, mpi_xp_r, nbr_D, 1206+ig, & ! Receive from Down the first-1
+          comm0, status, ierr)
+        ENDDO
+        !!!!!!!!!!! Send ghost to down neighbour !!!!!!!!!!!!!!!!!!!!!!\
+        DO ig = 1,ngz/2
+          CALL mpi_sendrecv(fz_(first+(ig-1)), count, mpi_xp_r, nbr_D, 1208+ig, & ! Send to Down the first
+          buff(ig),          count, mpi_xp_r, nbr_U, 1208+ig, & ! Recieve from Up the last+1
+          comm0, status, ierr)
+        ENDDO
+      ELSE
+        DO ig = 1,ngz/2
+          buff(-ig) = fz_(last-(ig-1))
+          buff( ig) = fz_(first+(ig-1))
+        ENDDO
+      ENDIF
+      ! if the metric is not periodic, we extrapolate it linearly
+      IF(.NOT. periodic) THEN
+        !!!! Right side
+        ! extrapolation from a linear fit
+        ! g(z) = dfdz*(z-z1) + f1
+        f1 = fz_(last-1)
+        f2 = fz_(last)
+        z1 = zarray(last-1,eo)
+        z2 = zarray(last,eo)
+        dfdz = (f2-f1)/(z2-z1) ! slope
+        beta  = f1              ! shift
+        ! right ghosts values
+        DO ig = 1,ngz/2
+          z3    = z2 + REAL(ig,xp)*(z2 - z1) ! z3 = z2 + ig * dz
+          f3    = dfdz*(z3 - z1) + beta
+          buff(ig) = f3
+        ENDDO       
+        !!!! Left side
+        ! extrapolation from a linear fit
+        ! g(z) = dfdz*(z-z1) + f1
+        f1 = fz_(first)
+        f2 = fz_(first+1)
+        z1 = zarray(first,eo)
+        z2 = zarray(first+1,eo)
+        dfdz = (f2-f1)/(z2-z1) ! slope
+        beta  = f1              ! shift
+        ! right ghosts values
+        DO ig = 1,ngz/2
+          z3    = z1 - REAL(ig,xp)*(z2 - z1) ! z3 = z1 - ig * dz
+          f3    = dfdz*(z3 -z1) + beta
+          buff(-ig) = f3
+        ENDDO       
       ENDIF
+      ! Updating ghosts 
+      DO ig = 1,ngz/2
+        fz_(last +ig) = buff(ig)
+        fz_(first-ig) = buff(-ig)
+      ENDDO
+      !  print*,fz_
     END SUBROUTINE update_ghosts_z
 
-
     !> Generate an equidistant array from min to max with n points
     function linspace(min,max,n) result(out)
       real(xp), INTENT(IN):: min, max
@@ -596,15 +589,14 @@ CONTAINS
     !> full theta integral with weight function dlp
     real(xp) function dlp_int(var,dlp)
       real(xp), dimension(np), INTENT(IN):: var, dlp
-      dlp_int=sum(var*dlp)*2*pi*Npol_ext/np
+      dlp_int=sum(var*dlp)*2._xp*pi*Npol_ext/np
     end function dlp_int
 
     !> theta integral with weight function dlp, up to index 'ind'
     real(xp) function dlp_int_ind(var,dlp,ind)
       real(xp), dimension(np), INTENT(IN):: var, dlp
       integer, INTENT(IN):: ind
-
-      dlp_int_ind=0.
+      dlp_int_ind=0._xp
       if (ind.gt.1) then
          dlp_int_ind=dlp_int_ind+var(1)*dlp(1)*pi*Npol_ext/np
          dlp_int_ind=dlp_int_ind+(sum(var(2:ind-1)*dlp(2:ind-1)))*2*pi*Npol_ext/np
@@ -617,22 +609,18 @@ CONTAINS
       integer,                INTENT(IN) :: n
       real(xp), dimension(n), INTENT(IN):: x,y
       real(xp), dimension(n) :: out,dx
-
       !call lag3deriv(y,x,n,out,x,n)
-
-      out=0.
+      out=0._xp
       do i=2,n-1
-         out(i)=out(i)-y(i-1)/2
-         out(i)=out(i)+y(i+1)/2
+         out(i)=out(i)-y(i-1)/2._xp
+         out(i)=out(i)+y(i+1)/2._xp
       enddo
       out(1)=y(2)-y(1)
       out(n)=y(n)-y(n-1)
       dx=x(2)-x(1)
       out=out/dx
-
     end function deriv_fd
 
-
   end subroutine get_miller
 
 
-- 
GitLab