From 430cf288629cc60b07606c13f211ae70504a1445 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franck=20P=C3=A9rignon?= <franck.perignon@imag.fr>
Date: Thu, 22 Jan 2015 18:54:53 +0100
Subject: [PATCH] poisson/pressure (not really tested ...)

---
 HySoP/hysop/default_methods.py                |   3 +-
 HySoP/hysop/f2py/fftw2py.f90                  |  46 ++++--
 .../hysop/numerics/differential_operations.py |  59 ++++++++
 HySoP/hysop/operator/differential.py          |  24 ++-
 HySoP/hysop/operator/discrete/differential.py |  26 +++-
 HySoP/hysop/operator/discrete/poisson_fft.py  | 139 +++++++++++-------
 HySoP/hysop/operator/poisson.py               |  49 +++---
 HySoP/src/fftw/fft3d.f90                      |  73 +++++++--
 8 files changed, 323 insertions(+), 96 deletions(-)

diff --git a/HySoP/hysop/default_methods.py b/HySoP/hysop/default_methods.py
index 9e17fbf0e..a18e8c6df 100644
--- a/HySoP/hysop/default_methods.py
+++ b/HySoP/hysop/default_methods.py
@@ -28,7 +28,8 @@ BAROCLINIC = {SpaceDiscretisation: FD_C_4}
 
 DIFFUSION = {SpaceDiscretisation: 'fftw', GhostUpdate: True}
 
-POISSON = {SpaceDiscretisation: 'fftw', GhostUpdate: True}
+POISSON = {SpaceDiscretisation: 'fftw', GhostUpdate: True,
+           Formulation: 'velocity'}
 
 STRETCHING = {TimeIntegrator: RK3, Formulation: "Conservative",
               SpaceDiscretisation: FD_C_4}
diff --git a/HySoP/hysop/f2py/fftw2py.f90 b/HySoP/hysop/f2py/fftw2py.f90
index cfa244b94..721bcda06 100755
--- a/HySoP/hysop/f2py/fftw2py.f90
+++ b/HySoP/hysop/f2py/fftw2py.f90
@@ -64,6 +64,38 @@ contains
     end if
   end subroutine init_fftw_solver
 
+
+    !> Initialisation of fftw context : create plans and memory buffers
+  !! @param[in] resolution global resolution of the discrete domain
+  !! @param[in] lengths width of each side of the domain
+  !! @param[in] comm MPI communicator
+  !! @param[out] datashape local dimension of the input/output field
+  !! @param[out] offset absolute index of the first component of the local field
+  subroutine init_fftw_solver_scalar(resolution,lengths,comm,datashape,offset,dim,fftw_type_real)
+
+    integer, intent(in) :: dim
+    integer, dimension(dim),intent(in) :: resolution
+    real(pk),dimension(dim), intent(in) :: lengths
+    integer(ik), dimension(dim), intent(out) :: datashape
+    integer(ik), dimension(dim), intent(out) :: offset
+    integer, intent(in)                 :: comm
+    logical, optional :: fftw_type_real
+    !f2py optional :: dim=len(resolution)
+    !f2py intent(hide) dim
+    !f2py logical optional, intent(in) :: fftw_type_real = 1
+
+    integer :: ierr
+
+    ! Duplicate comm into client_data::main_comm (used later in fft2d and fft3d)
+    call mpi_comm_dup(comm, main_comm, ierr)
+    
+    print*, "Init fftw/poisson solver for a 3d problem"
+    call init_r2c_scalar_3d(resolution,lengths)
+    
+    call getParamatersTopologyFFTW3d(datashape,offset)
+    
+  end subroutine init_fftw_solver_scalar
+
   !> Free memory allocated for fftw-related objects (plans and buffers)
   subroutine clean_fftw_solver(dim)
 
@@ -225,18 +257,14 @@ contains
   !> Compute the pressure from the velocity field, solving a Poisson equation.
   !! \f{eqnarray*} \Delta p ' &=& rhs \f}
   !! with rhs depending on the first derivatives of the velocity field
-  !! @param[in] rhs
-  !! @param[out] pressure
-  !! in the following, rhs is the right hand side 3D-scalar field, and pressure is
-  !! a 3D scalar field.
-  subroutine pressure_3d(rhs, pressure, ghosts)
-    real(pk),dimension(:,:,:), intent(in) :: rhs
+  !! @param[in, out] pressure
+  !! in the following, pressure is used as inout parameter. It must contains the rhs of poisson equation.
+  subroutine pressure_3d(pressure, ghosts)
     integer, dimension(3), intent(in) :: ghosts
     real(pk),dimension(:,:,:),intent(inout):: pressure
+    !f2py intent(in,out) :: pressure
 
-    !f2py intent(in,out) :: omega_x,omega_y,omega_z
-
-    call r2c_scalar_3d(rhs, ghosts)
+    call r2c_scalar_3d(pressure, ghosts)
 
     call filter_pressure_3d()
 
diff --git a/HySoP/hysop/numerics/differential_operations.py b/HySoP/hysop/numerics/differential_operations.py
index ab4767efd..5dab84270 100755
--- a/HySoP/hysop/numerics/differential_operations.py
+++ b/HySoP/hysop/numerics/differential_operations.py
@@ -481,3 +481,62 @@ class GradVxW(DifferentialOperation):
                 npw.add(result[comp], self._work[0], result[comp])
             diagnostics[1] = max(diagnostics[1], np.max(self._work[1]))
         return result, diagnostics
+
+
+class DivAdvection(DifferentialOperation):
+    """
+    Computes \f$ - \nabla .(V . \nabla V) \f$, with
+    \f$V\f$ a vector field.
+    """
+    def __init__(self, topo, method=FD_C_4):
+        DifferentialOperation.__init__(self, topo)
+        if method is FD_C_4:
+            self.fcall = self.FDCentral
+            self.fd_scheme = FD_C_4(topo.mesh.space_step)
+            assert (topo.ghosts() >= 2).all(),\
+                'you need a ghost layer for FD4 scheme.'
+
+        elif method is FD_C_2:
+            self.fcall = self.FDCentral
+            self.fd_scheme = FD_C_2(topo.mesh.space_step)
+            assert (topo.ghosts() >= 1).all(),\
+                'you need a ghost layer for FD2 scheme.'
+
+        else:
+            raise ValueError("FD scheme Not yet implemented")
+        self._indices = topo.mesh.iCompute
+        self.fd_scheme.computeIndices(self._indices)
+        # dimension of the fields
+        self._dim = topo.domain.dimension
+
+    def __call__(self, var1, result):
+        return self.fcall(var1, result)
+
+    def FDCentral(self, var1, result):
+            
+
+        work = npw.zeros_like(rhs)
+
+        j1 = np.arange(self.velocity.nbComponents)
+        rhs[...] = 0.0
+
+        for i in xrange(self.velocity.nbComponents): 
+            j2 = np.where(j1 != i)[0]
+            self._fd_scheme.compute(vdata[j2[0]], j2[1], work)
+            self._fd_scheme.compute_and_mult(vdata[j2[1]], j2[0], work)
+            rhs[...] += work[...]
+            work[...] = 0.0
+        rhs[...] *= -1.0
+
+        for i in xrange(self.velocity.nbComponents): 
+            j2 = np.where(j1 != i)[0]
+            self._fd_scheme.compute(vdata[j2[0]], j2[0], work)
+            self._fd_scheme.compute_and_mult(vdata[j2[1]], j2[1], work)
+            rhs[...] += work[...]
+            work[...] = 0.0
+
+        rhs[...] *= 2.0
+
+
+        
+        return result
diff --git a/HySoP/hysop/operator/differential.py b/HySoP/hysop/operator/differential.py
index b10cb26db..060a6bd0f 100644
--- a/HySoP/hysop/operator/differential.py
+++ b/HySoP/hysop/operator/differential.py
@@ -5,7 +5,8 @@ Differential operators
 """
 from hysop.constants import debug
 from hysop.operator.computational import Computational
-from hysop.operator.discrete.differential import CurlFFT, CurlFD, GradFD
+from hysop.operator.discrete.differential import CurlFFT, CurlFD,\
+    GradFD, DivAdvectionFD
 from hysop.methods_keys import SpaceDiscretisation
 from hysop.operator.continuous import opsetup
 from hysop.numerics.finite_differences import FD_C_4,\
@@ -130,3 +131,24 @@ class Grad(Differential):
                                        outvar=self.discreteFields[self.outvar],
                                        method=self.method, rwork=rwork)
         self._is_uptodate = True
+
+
+class DivAdvection(Differential):
+    """
+    Computes \f$ outVar = -\nabla .(invar . \nabla invar) \f$
+    """
+
+    @debug
+    @opsetup
+    def setup(self, rwork=None, iwork=None):
+        if self.method[SpaceDiscretisation].mro()[1] is not FiniteDifference:
+            raise ValueError("DivAdvection operator only\
+                implemented with finite differences. Please change\
+                method[SpaceDiscretisation] value.")
+        # Create a discrete operator, according to the chosen method
+        # (only finite differences at the time).
+        self.discrete_op = DivAdvectionFD(
+            invar=self.discreteFields[self.invar],
+            outvar=self.discreteFields[self.outvar],
+            method=self.method, rwork=rwork)
+        self._is_uptodate = True
diff --git a/HySoP/hysop/operator/discrete/differential.py b/HySoP/hysop/operator/discrete/differential.py
index b00d6a074..4b7436052 100644
--- a/HySoP/hysop/operator/discrete/differential.py
+++ b/HySoP/hysop/operator/discrete/differential.py
@@ -6,7 +6,8 @@ Discretisation of the differential operators (curl, grad ...)
 """
 from hysop.constants import debug
 from hysop.operator.discrete.discrete import DiscreteOperator
-from hysop.numerics.differential_operations import Curl, GradV
+from hysop.numerics.differential_operations import Curl, GradV,\
+    DivAdvection
 import hysop.tools.numpywrappers as npw
 from abc import ABCMeta, abstractmethod
 from hysop.numerics.update_ghosts import UpdateGhosts
@@ -149,3 +150,26 @@ class GradFD(Differential):
     def apply(self, simulation=None):
         self._synchronize(self.invar.data)
         self.outvar.data = self._function(self.invar.data, self.outvar.data)
+
+
+class DivAdvectionFD(Differential):
+    """
+    Compute the grad of a discrete field, using finite differences.
+    """
+
+    def __init__(self, **kwds):
+
+        super(DivAdvectionFD, self).__init__(**kwds)
+        # prepare ghost points synchro for velocity
+        self._synchronize = UpdateGhosts(self.invar.topology,
+                                         self.invar.nb_components)
+        dim = self.domain.dimension
+        assert dim * self.outvar.nb_components == self.invar.nb_components
+        self._function = DivAdvection(self.invar.topology,
+                                      self.method[SpaceDiscretisation])
+
+    @debug
+    @profile
+    def apply(self, simulation=None):
+        self._synchronize(self.invar.data)
+        self.outvar.data = self._function(self.invar.data, self.outvar.data)
diff --git a/HySoP/hysop/operator/discrete/poisson_fft.py b/HySoP/hysop/operator/discrete/poisson_fft.py
index aa031458e..1b1be1875 100644
--- a/HySoP/hysop/operator/discrete/poisson_fft.py
+++ b/HySoP/hysop/operator/discrete/poisson_fft.py
@@ -22,42 +22,42 @@ class PoissonFFT(DiscreteOperator):
     """
 
     @debug
-    def __init__(self, velocity, vorticity, projection=None,
+    def __init__(self, output_field, input_field, projection=None,
                  filterSize=None, correction=None, **kwds):
         """
         Constructor.
-        @param[out] velocity : discretization of the solution field
-        @param[in] vorticity : discretization of the RHS (mind the minus rhs!)
+        @param[out] output_field : discretization of the solution field
+        @param[in] input_field : discretization of the RHS (mind the minus rhs!)
         @param projection : if None, no projection. Else:
         - either the value of the frequency of reprojection, never updated.
         - or Reprojection discrete operator. In that case, a criterion
-        depending on the vorticity will be computed at each time step, if
+        depending on the input_field will be computed at each time step, if
         criterion > threshold, then frequency projection is active.
         @param filterSize :
-        @param correction : operator used to shift velocity according
+        @param correction : operator used to shift output_field according
         to a given input (fixed) flowrate.
         See hysop.operator.velocity_correction.
         Default = None.
         """
         # Base class initialisation
         assert 'variables' not in kwds, 'variables parameter is useless.'
-        super(PoissonFFT, self).__init__(variables=[velocity, vorticity],
+        super(PoissonFFT, self).__init__(variables=[output_field, input_field],
                                          **kwds)
         ## Solution field
-        self.velocity = velocity
+        self.output_field = output_field
         ## RHS field
-        self.vorticity = vorticity
-        ## Solenoidal projection of vorticity ?
+        self.input_field = input_field
+        ## Solenoidal projection of input_field ?
         self.projection = projection
         ## Filter size array = domainLength/(CoarseRes-1)
         self.filterSize = filterSize
-        # If 2D problem, vorticity must be a scalar
-        self.dim = self.velocity.domain.dimension
+        # If 2D problem, input_field must be a scalar
+        self.dim = self.output_field.domain.dimension
         if self.dim == 2:
-            assert self.vorticity.nb_components == 1
+            assert self.input_field.nb_components == 1
         self.correction = correction
-        self.input = [self.vorticity]
-        self.output = [self.velocity]
+        self.input = [self.input_field]
+        self.output = [self.output_field]
 
         ## The function called during apply
         self.solve = None
@@ -67,16 +67,22 @@ class PoissonFFT(DiscreteOperator):
         self._select_solve()
 
     def _select_solve(self):
+
+        """
+        TODO : add pressure solver selection
+        f(output.nbComponents) + pb type 'pressure-poisson'
+        """
+        
         ## Multiresolution ?
-        multires = self.velocity.topology.mesh != self.vorticity.topology.mesh
+        multires = self.output_field.topology.mesh != self.input_field.topology.mesh
 
         # connexion to the required apply function
         if self.dim == 2:
             self._solve = self._solve2D
         elif self.dim == 3:
-            # If there is a projection, vorticity is also an output
+            # If there is a projection, input_field is also an output
             if self.projection is not None:
-                self.output.append(self.vorticity)
+                self.output.append(self.input_field)
                 if multires:
                     self._solve = self._solve3D_proj_multires
                 else:
@@ -95,7 +101,7 @@ class PoissonFFT(DiscreteOperator):
         else:
             raise AttributeError('Not implemented for 1D problems.')
 
-        # Operator to shift velocity according to an input required flowrate
+        # Operator to shift output_field according to an input required flowrate
         if self.correction is not None:
             self.solve = self._solve_and_correct
         else:
@@ -114,43 +120,43 @@ class PoissonFFT(DiscreteOperator):
         """
         Solve 2D poisson problem
         """
-        self.velocity.data[0], self.velocity.data[1] =\
-            fftw2py.solve_poisson_2d(self.vorticity.data[0],
-                                     self.velocity.data[0],
-                                     self.velocity.data[1])
+        self.output_field.data[0], self.output_field.data[1] =\
+            fftw2py.solve_poisson_2d(self.input_field.data[0],
+                                     self.output_field.data[0],
+                                     self.output_field.data[1])
 
     def _project(self):
         """
-        apply projection onto vorticity
+        apply projection onto input_field
         """
-        ghosts_w = self.vorticity.topology.ghosts()
-        self.vorticity.data[0], self.vorticity.data[1], \
-            self.vorticity.data[2] = \
-               fftw2py.projection_om_3d(self.vorticity.data[0],
-                                        self.vorticity.data[1],
-                                        self.vorticity.data[2], ghosts_w)
+        ghosts_w = self.input_field.topology.ghosts()
+        self.input_field.data[0], self.input_field.data[1], \
+            self.input_field.data[2] = \
+               fftw2py.projection_om_3d(self.input_field.data[0],
+                                        self.input_field.data[1],
+                                        self.input_field.data[2], ghosts_w)
 
     def _solve3D_multires(self, simu=None):
         """
         3D, multiresolution
         """
-        # Projects vorticity values from fine to coarse grid
+        # Projects input_field values from fine to coarse grid
         # in frequencies space by nullifying the smallest modes
-        vortFilter = npw.copy(self.vorticity.data)
+        vortFilter = npw.copy(self.input_field.data)
         vortFilter[0], vortFilter[1], vortFilter[2] = \
            fftw2py.multires_om_3d(self.filterSize[0], self.filterSize[1],
-                                  self.filterSize[2], self.vorticity.data[0],
-                                  self.vorticity.data[1],
-                                  self.vorticity.data[2])
-
-        # Solves Poisson equation using filter vorticity
-        ghosts_v = self.velocity.topology.ghosts()
-        ghosts_w = self.vorticity.topology.ghosts()
-        self.velocity.data[0], self.velocity.data[1], self.velocity.data[2] = \
+                                  self.filterSize[2], self.input_field.data[0],
+                                  self.input_field.data[1],
+                                  self.input_field.data[2])
+
+        # Solves Poisson equation using filter input_field
+        ghosts_v = self.output_field.topology.ghosts()
+        ghosts_w = self.input_field.topology.ghosts()
+        self.output_field.data[0], self.output_field.data[1], self.output_field.data[2] = \
             fftw2py.solve_poisson_3d(vortFilter[0], vortFilter[1],
-                                     vortFilter[2], self.velocity.data[0],
-                                     self.velocity.data[1],
-                                     self.velocity.data[2], ghosts_w, ghosts_v)
+                                     vortFilter[2], self.output_field.data[0],
+                                     self.output_field.data[1],
+                                     self.output_field.data[2], ghosts_w, ghosts_v)
 
     def _solve3D_proj_multires(self, simu):
         """
@@ -172,21 +178,48 @@ class PoissonFFT(DiscreteOperator):
         """
         Basic solve
         """
-        # Solves Poisson equation using usual vorticity
-        ghosts_v = self.velocity.topology.ghosts()
-        ghosts_w = self.vorticity.topology.ghosts()
-        self.velocity.data[0], self.velocity.data[1], self.velocity.data[2] =\
-            fftw2py.solve_poisson_3d(self.vorticity.data[0],
-                                     self.vorticity.data[1],
-                                     self.vorticity.data[2],
-                                     self.velocity.data[0],
-                                     self.velocity.data[1],
-                                     self.velocity.data[2], ghosts_w, ghosts_v)
+        # Solves Poisson equation using usual input_field
+        ghosts_v = self.output_field.topology.ghosts()
+        ghosts_w = self.input_field.topology.ghosts()
+        self.output_field.data[0], self.output_field.data[1], self.output_field.data[2] =\
+            fftw2py.solve_poisson_3d(self.input_field.data[0],
+                                     self.input_field.data[1],
+                                     self.input_field.data[2],
+                                     self.output_field.data[0],
+                                     self.output_field.data[1],
+                                     self.output_field.data[2], ghosts_w, ghosts_v)
 
     def _solve_and_correct(self, simu):
         self._solve(simu.currentIteration)
         self.correction.apply(simu)
 
+
+    def _solve_3d_scalar_fd(self, simu=None):
+        """solve poisson-pressure like problem
+        input = 3D vector field
+        output = 3D scalar field
+        """
+        # Compute rhs = f(input) inplace
+        # --> output == rhs
+        # Call fftw filter
+        # !!! pressure3d use the same arg for input and output
+        # ---> input_field will be overwritten
+        ghosts = self.output_field.topology.ghosts()
+        self.output_field.data[0] = fftw2py.pressure_3d(
+            self.input_field.data[0], ghosts)
+        
+    def _solve_3d_scalar(self, simu=None):
+        """solve poisson-pressure like problem
+        input = 3D vector field
+        output = 3D scalar field
+        """
+        # # Call fftw filter
+        # self._output_field.data[0] = fftw2py.solve_poisson_3d_pressure(
+        #     self._input_field.data[0],
+        #     self._input_field.data[1],
+        #     self._input_field.data[2])
+        pass
+
     @debug
     @profile
     def apply(self, simulation=None):
@@ -197,4 +230,4 @@ class PoissonFFT(DiscreteOperator):
         Clean memory (fftw plans and so on)
         """
         pass
-        #fftw2py.clean_fftw_solver(self.velocity.dimension)
+        #fftw2py.clean_fftw_solver(self.output_field.dimension)
diff --git a/HySoP/hysop/operator/poisson.py b/HySoP/hysop/operator/poisson.py
index 6043dedc6..9a237ae88 100644
--- a/HySoP/hysop/operator/poisson.py
+++ b/HySoP/hysop/operator/poisson.py
@@ -27,39 +27,46 @@ class Poisson(Computational):
     """
 
     @debug
-    def __init__(self, velocity, vorticity, flowrate=None,
+    def __init__(self, output_field, input_field, flowrate=None,
                  projection=None, **kwds):
         """
         Constructor for the Poisson problem.
 
-        @param[out] velocity : solution field
-        @param[in] vorticity : rhs field
-        @param[in] flowrate : a flow rate value (through input surf,
+        @param[out] output_field : solution field
+        @param[in] input_field : rhs field
+        @param[in] flowrate : a flow rate value (through input_field surf,
         normal to xdir) used to compute a correction of the solution field.
-        Default = 0 (no correction). See hysop.operator.velocity_correction.
+        Default = 0 (no correction). See hysop.operator.output_field_correction.
         @param projection : if None, no projection. Else:
         - either the value of the frequency of reprojection, never update.
         - or a tuple = (frequency, threshold).
         In that case, a criterion
-        depending on the vorticity will be computed at each time step, if
+        depending on the input_field will be computed at each time step, if
         criterion > threshold, then frequency projection is active.
+
+        Note about method:
+        - SpaceDiscretisation == fftw
+        - Formulation = 'velocity' or 'pressure'
+        velocity : laplacian(phi) = -w and v = nabla X psi, in = vorticity, out = velo
+        pressure : laplacian(p) = -nabla.(u.nabla u, in = velo, out = pressure
         """
         # Warning : for fftw all variables must have
         # the same resolution.
         assert 'variables' not in kwds, 'variables parameter is useless.'
-        super(Poisson, self).__init__(variables=[velocity, vorticity], **kwds)
+        super(Poisson, self).__init__(variables=[output_field, input_field],
+                                      **kwds)
         ## solution of the problem
-        self.velocity = velocity
+        self.output_field = output_field
         ## -(right-hand side)
-        self.vorticity = vorticity
+        self.input_field = input_field
         if self.method is None:
             self.method = default.POISSON
 
         if self.method[SpaceDiscretisation] is not 'fftw':
             raise AttributeError("Method not yet implemented.")
 
-        self.input = [self.vorticity]
-        self.output = [self.velocity]
+        self.input = [self.input_field]
+        self.output = [self.output_field]
         if flowrate is not None:
             self.withCorrection = True
             self._flowrate = flowrate
@@ -70,25 +77,25 @@ class Poisson(Computational):
         self._config = kwds
 
         if projection is not None:
-            self.output.append(self.vorticity)
+            self.output_field.append(self.input_field)
 
     def discretize(self):
         # Poisson solver based on fftw
         if self.method[SpaceDiscretisation] is 'fftw':
             super(Poisson, self)._fftw_discretize()
             if self.withCorrection:
-                toporef = self.discreteFields[self.velocity].topology
+                toporef = self.discreteFields[self.output_field].topology
                 if 'discretization' in self._config:
                     self._config['discretization'] = toporef
                 self.correction = VelocityCorrection(
-                    self.velocity, self.vorticity,
+                    self.output_field, self.input_field,
                     req_flowrate=self._flowrate, **self._config)
                 self.correction.discretize()
 
                 if isinstance(self.projection, tuple):
                     freq = self.projection[0]
                     threshold = self.projection[1]
-                    self.projection = Reprojection(self.vorticity,
+                    self.projection = Reprojection(self.input_field,
                                                    threshold, freq,
                                                    **self._config)
                     self.projection.discretize()
@@ -108,16 +115,16 @@ class Poisson(Computational):
         # Activate projection, if required
         if isinstance(self.projection, Reprojection):
             # Projection frequency is updated at each
-            # time step, and depends on the vorticity
+            # time step, and depends on the input_field
             self.projection.setup(rwork=rwork)
             projection_discr = self.projection.discrete_op
         else:
             projection_discr = self.projection
 
-        self.discrete_op = PoissonFFT(self.discreteFields[self.velocity],
-                                           self.discreteFields[self.vorticity],
-                                           correction=cd,
-                                           rwork=rwork, iwork=iwork,
-                                           projection=projection_discr)
+        self.discrete_op = PoissonFFT(self.discreteFields[self.output_field],
+                                      self.discreteFields[self.input_field],
+                                      correction=cd,
+                                      rwork=rwork, iwork=iwork,
+                                      projection=projection_discr)
 
         self._is_uptodate = True
diff --git a/HySoP/src/fftw/fft3d.f90 b/HySoP/src/fftw/fft3d.f90
index 89071c81d..6bb0c32a4 100755
--- a/HySoP/src/fftw/fft3d.f90
+++ b/HySoP/src/fftw/fft3d.f90
@@ -22,7 +22,7 @@ module fft3d
 
   private
 
-  public :: init_r2c_3d,init_c2c_3d,r2c_3d,r2c_scalar_3d,c2c_3d,c2r_3d,c2r_scalar_3d,cleanFFTW_3d,&
+  public :: init_r2c_3d,init_c2c_3d,init_r2c_scalar_3d, r2c_3d,r2c_scalar_3d,c2c_3d,c2r_3d,c2r_scalar_3d,cleanFFTW_3d,&
        getParamatersTopologyFFTW3d,filter_poisson_3d,filter_curl_diffusion_3d, &
        init_r2c_3d_many, r2c_3d_many, c2r_3d_many, filter_diffusion_3d_many,&
        filter_poisson_3d_many, filter_diffusion_3d, filter_curl_3d, filter_projection_om_3d,&
@@ -270,6 +270,60 @@ contains
 
   end subroutine init_r2c_3d
 
+  !> Initialisation of the fftw context for real to complex transforms (forward and backward)
+  !! @param[in] resolution global domain resolution
+  !! @param[in] lengths width of each side of the domain
+  subroutine init_r2c_scalar_3d(resolution,lengths)
+
+    integer, dimension(3), intent(in) :: resolution
+    real(mk),dimension(3), intent(in) :: lengths
+    !! Size of the local memory required for fftw (cbuffer)
+    integer(C_INTPTR_T) :: alloc_local,halfLength
+
+    if(is3DUpToDate) return
+
+    ! init fftw mpi context
+    call fftw_mpi_init()
+
+    if(rank==0) open(unit=21,file=filename,form="formatted")
+    allocate(fft_resolution(3))
+    fft_resolution(:) = resolution(:)-1
+    halfLength = fft_resolution(c_X)/2+1
+
+    ! compute "optimal" size (according to fftw) for local data (warning : dimension reversal)
+    alloc_local = fftw_mpi_local_size_3d_transposed(fft_resolution(c_Z),fft_resolution(c_Y),halfLength,&
+         main_comm,local_resolution(c_Z),local_offset(c_Z),local_resolution(c_Y),local_offset(c_Y));
+
+    ! init c_X part. This is required to compute kx with the same function in 2d and 3d cases.
+    local_offset(c_X) = 0
+    local_resolution(c_X) = halfLength
+
+    ! allocate local buffer (used to save datain/dataout ==> in-place transform!!)
+    cbuffer1 = fftw_alloc_complex(alloc_local)
+
+    ! link rdatain and dataout to cbuffer, setting the right dimensions for each
+    call c_f_pointer(cbuffer1, rdatain1, [2*halfLength,fft_resolution(c_Y),local_resolution(c_Z)])
+    call c_f_pointer(cbuffer1, dataout1, [halfLength, fft_resolution(c_Z), local_resolution(c_Y)])
+
+    rdatain1 = 0.0
+
+    !   create MPI plans for in-place forward/backward DFT (note dimension reversal)
+    plan_forward1 = fftw_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain1, dataout1, &
+         main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT))
+    plan_backward1 = fftw_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, &
+         main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN))
+    
+    call computeKx(lengths(c_X))
+    call computeKy(lengths(c_Y))
+    call computeKz(lengths(c_Z))
+
+    normFFT = 1./(fft_resolution(c_X)*fft_resolution(c_Y)*fft_resolution(c_Z))
+    !! call fft3d_diagnostics(alloc_local)
+    manycase = .false.
+    is3DUpToDate = .true.
+
+  end subroutine init_r2c_scalar_3d
+  
   !> forward transform - The result is saved in local buffers
   !!  @param[in] omega_x 3d scalar field, x-component of the input vector field
   !!  @param[in] omega_y 3d scalar field, y-component of the input vector field
@@ -342,9 +396,9 @@ contains
   !> forward transform - The result is saved in a local buffer
   !!  @param[in] omega 3d scalar field, x-component of the input vector field
   !!  @param[in] ghosts, number of points in the ghost layer of input field.
-  subroutine r2c_scalar_3d(omega, ghosts)
+  subroutine r2c_scalar_3d(scalar, ghosts)
 
-    real(mk),dimension(:,:,:),intent(in) :: omega
+    real(mk),dimension(:,:,:),intent(in) :: scalar
     integer, dimension(3), intent(in) :: ghosts
     real(mk) :: start
     integer(C_INTPTR_T) :: i,j,k, ig, jg, kg
@@ -359,7 +413,7 @@ contains
           jg = j + ghosts(c_Y)
           do i = 1, fft_resolution(c_X)
              ig = i + ghosts(c_X)
-             rdatain1(i,j,k) = omega(ig,jg,kg)
+             rdatain1(i,j,k) = scalar(ig,jg,kg)
           end do
        end do
     end do
@@ -372,10 +426,10 @@ contains
   end subroutine r2c_scalar_3d
 
   !> Backward fftw transform
-  !!  @param[in,out] omega 3d scalar field
-  !!  @param[in] ghosts, number of points in the ghost layer of in/out omega scalar field.
-  subroutine c2r_scalar_3d(omega, ghosts)
-    real(mk),dimension(:,:,:),intent(inout) :: omega
+  !!  @param[in,out] scalar 3d scalar field
+  !!  @param[in] ghosts, number of points in the ghost layer of in/out scalar field.
+  subroutine c2r_scalar_3d(scalar, ghosts)
+    real(mk),dimension(:,:,:),intent(inout) :: scalar
     integer, dimension(3), intent(in) :: ghosts
     real(mk) :: start
     integer(C_INTPTR_T) :: i,j,k, ig, jg, kg
@@ -389,7 +443,7 @@ contains
           jg = j + ghosts(c_Y)
           do i = 1, fft_resolution(c_X)
              ig = i + ghosts(c_X)
-             omega(ig,jg,kg) = rdatain1(i,j,k)*normFFT
+             scalar(ig,jg,kg) = rdatain1(i,j,k)*normFFT
           end do
        end do
     end do
@@ -845,7 +899,6 @@ contains
     end do
   end subroutine filter_pressure_3d
 
-
   !> Solve Poisson problem in the Fourier space :
   !! \f{eqnarray*} \Delta \psi &=& - \omega \\ v &=& \nabla\times\psi \f}
   subroutine filter_poisson_3d_many()
-- 
GitLab