From 5de52ec1a6552265ec0d4b8692c1d0ad9f58df13 Mon Sep 17 00:00:00 2001 From: Chloe Mimeau <Chloe.Mimeau@imag.fr> Date: Tue, 4 Jun 2013 15:32:13 +0000 Subject: [PATCH] Updates concerning Navier-Stokes problems --- Docs/force_computation.tex | 25 ++-- Docs/vorticity_solenoidal_projection.tex | 8 ++ Examples/Attic/NavierStokes3d_sphere.py | 26 ++-- Examples/Attic/NavierStokes3d_vortRing.py | 71 +++++++--- Examples/testDiffusion.py | 47 +++++-- HySoP/hysop/f2py/fftw2py.f90 | 16 +++ HySoP/hysop/operator/discrete/poisson_fft.py | 57 ++++++-- .../operator/discrete/scales_advection.py | 104 ++++++++++++-- HySoP/hysop/operator/energy_enstrophy.py | 81 ++++++----- .../hysop/operator/monitors/compute_forces.py | 2 + HySoP/hysop/operator/monitors/printer.py | 4 +- HySoP/hysop/operator/reprojection.py | 129 ++++++++++++++++++ HySoP/src/fftw/fft3d.f90 | 31 ++++- 13 files changed, 488 insertions(+), 113 deletions(-) create mode 100644 HySoP/hysop/operator/reprojection.py diff --git a/Docs/force_computation.tex b/Docs/force_computation.tex index 5ad09d22c..24ee46fe8 100644 --- a/Docs/force_computation.tex +++ b/Docs/force_computation.tex @@ -121,19 +121,19 @@ Ainsi, en remplaçant $n$ par cette expression puis en effectuant une intégrati \int_{\partial B} p \cdot n \ d\text{s}= R \int_{\partial B} p \cdot \dfrac{\partial \Gamma}{\partial s} \ d\text{s} = -R \int_{\partial B} \dfrac{\partial p}{\partial s} \cdot \Gamma \ d\text{s} \end{equation} % -En supposant $\dfrac{\partial p}{\partial s} = \dfrac{\partial p}{\partial \Gamma}$, on a alors : +On a alors : \begin{equation} -\int_{\partial B} p \cdot n \ d\text{s}= -R \int_{\partial B} \dfrac{\partial p}{\partial \Gamma} \cdot \Gamma \ d\text{s} +\int_{\partial B} p \cdot n \ d\text{s}= -R \int_{\partial B} \dfrac{\partial p}{\partial s} \cdot \Gamma \ d\text{s} \end{equation} % D'après l'équation de la quantité de mouvement l'égalité suivante est vérifiée : \begin{equation} -\nu (\nabla \times \omega) \cdot \Gamma + \dfrac{\partial p}{\partial \Gamma} \cdot \Gamma = 0 +\nu (\nabla \times \omega) \cdot \Gamma + \dfrac{\partial p}{\partial s} \cdot \Gamma = 0 \end{equation} % Ainsi, \begin{equation} --R \nu \int_{\partial B} (\nabla \times \omega) \cdot \Gamma \ d\text{s} - R \int_{\partial B} \dfrac{\partial p}{\partial \Gamma} \cdot \Gamma \ d\text{s} = 0 +-R \nu \int_{\partial B} (\nabla \times \omega) \cdot \Gamma \ d\text{s} - R \int_{\partial B} \dfrac{\partial p}{\partial s} \cdot \Gamma \ d\text{s} = 0 \end{equation} % Et par conséquent, @@ -170,7 +170,7 @@ Dans le cas du cylindre 2D on a donc : % Et dans ce cas, le coefficient de pression est donné par \begin{equation} -C_p = \dfrac{F_p \cdot e_x}{u_{\infty}^2 H R} = -\dfrac{\nu}{u_{\infty}^2 H}\int_{0}^{2\pi} \dfrac{\partial\omega}{\partial n} e_{\theta} \ d\theta \ \cdot e_x +C_p = \dfrac{F_p \cdot e_x}{u_{\infty}^2 \rho R} = -\dfrac{\nu}{u_{\infty}^2 \rho}\int_{0}^{2\pi} \dfrac{\partial\omega}{\partial n} e_{\theta} \ d\theta \ \cdot e_x \end{equation} % or @@ -180,7 +180,7 @@ e_{\theta} \cdot e_x = -(e_x \cdot e_x) \text{sin} \theta + (e_y \cdot e_x)\text % donc \begin{equation} -\boxed{C_p = \dfrac{\nu}{u_{\infty}^2 H}\int_{0}^{2\pi} \dfrac{\partial\omega}{\partial n} \ \text{sin} \theta \ d\theta} +\boxed{C_p = \dfrac{\nu}{u_{\infty}^2 \rho}\int_{0}^{2\pi} \dfrac{\partial\omega}{\partial n} \ \text{sin} \theta \ d\theta} \end{equation} \underline{Calcul de la traînée de friction $F_f=- \nu \int_{\partial B} \omega \times n \ d\text{s}$} @@ -213,12 +213,21 @@ Dans le cas du cylindre 2D on a donc : % Et dans ce cas, le coefficient de friction est donné par \begin{equation} -C_f = \dfrac{F_f \cdot e_x}{u_{\infty}^2 H R} = \dfrac{\nu}{u_{\infty}^2 H}\int_{0}^{2\pi} \omega e_{\theta} \ d\theta \ \cdot e_x +C_f = \dfrac{F_f \cdot e_x}{u_{\infty}^2 \rho R} = \dfrac{\nu}{u_{\infty}^2 \rho}\int_{0}^{2\pi} \omega e_{\theta} \ d\theta \ \cdot e_x \end{equation} % donc \begin{equation} -\boxed{C_f = -\dfrac{\nu}{u_{\infty}^2 H}\int_{0}^{2\pi} \omega \ \text{sin} \theta \ d\theta} +\boxed{C_f = -\dfrac{\nu}{u_{\infty}^2 \rho}\int_{0}^{2\pi} \omega \ \text{sin} \theta \ d\theta} \end{equation} +\vspace{2cm} + +\begin{figure}[ht] +\centering + \includegraphics[width=0.5\linewidth]{images/pressure_friction_drag.png} +\caption{Les forces de pression ($PdA$) et de friction ($\tau_w dA$) s'exerçant sur l'élément de surface $dA$ d'un corps bidimensionnel.} +\label{tore} +\end{figure} + \end{document} diff --git a/Docs/vorticity_solenoidal_projection.tex b/Docs/vorticity_solenoidal_projection.tex index b4165ffe6..e18de789f 100644 --- a/Docs/vorticity_solenoidal_projection.tex +++ b/Docs/vorticity_solenoidal_projection.tex @@ -99,6 +99,14 @@ or $\widehat{\nabla \boldsymbol{\pi}}_k = i \boldsymbol{\xi}_k \widehat{\boldsym \boxed{\widehat{\boldsymbol{\omega}'}_k = \widehat{\boldsymbol{\omega}}_k - \boldsymbol{\xi}_k \dfrac{\sum_{j=1}^3 \boldsymbol{\xi}_j \widehat{\boldsymbol{\omega}}_j}{\mid \boldsymbol{\xi} \mid^2}}, \ 1\leq k \leq 3 \end{equation} +Un critère de reprojection peut-être donné par : +\begin{equation} +\max\limits_{x} \left ( \dfrac{\rvert \text{div} (\omega) \rvert }{\max\limits_{x} \left \rvert\dfrac{\partial \omega_i (x)}{\partial x_j} \right \rvert } \right ) \geq c +\end{equation} + +avec $c$ une constante fixée inférieure à 1, de l'ordre de 1-10$\%$. + + \end{document} diff --git a/Examples/Attic/NavierStokes3d_sphere.py b/Examples/Attic/NavierStokes3d_sphere.py index 2206ab9f8..ca7ca59e8 100755 --- a/Examples/Attic/NavierStokes3d_sphere.py +++ b/Examples/Attic/NavierStokes3d_sphere.py @@ -78,7 +78,7 @@ hy = Ly / ncells[1] hz = Lz / ncells[2] ## Obstacle -lambd = np.array([lambdFluid, lambdPorous, lambdSolid], +lambd = np.array([lambdSolid, lambdPorous], dtype=PARMES_REAL, order=ORDER) sphere = Obstacle(myDomain3d, name=obstName, @@ -105,8 +105,10 @@ print "FFT solver local resolution/offset: ", localres, localoffset ##topofft = poisson.getTopology() # ---- Cartesian topology ----- -topoCart = pp.CartesianTopology(domain=myDomain3d, - resolution=resolution3d, dim=3, ghosts=[nbGhosts,nbGhosts,nbGhosts]) +topoCart = pp.Cartesian(domain=myDomain3d, + dim=3, + globalMeshResolution=resolution3d, + ghosts=[nbGhosts,nbGhosts,nbGhosts]) # ---- JB's topology ---------- nbProcs = MPI.COMM_WORLD.Get_size() @@ -243,21 +245,21 @@ navierStokes = pp.Problem(topoCart, [advecVort, stretch, diffusion, poisson, pen printer = Printer(fields=[vorticity, velocity, vortNorm], frequency=outModuloPrinter, outputPrefix=outputPrinter) -forces = Compute_forces(velocity=velocity, vorticity=vorticity, - topology=topoCart, - obstacle=sphere, - boxMin=[Ox + Lx / 10., Oy + Ly / 10., Oz + Lz / 10.], - boxMax=[Lx - Lx / 10., Ly - Ly / 10., Lz - Lz / 10.], - Reynolds=uinf * obstRadius/ visco, - frequency=outModuloForces, - outputPrefix=outputForces) +#forces = Compute_forces(velocity=velocity, vorticity=vorticity, +# topology=topoCart, +# obstacle=sphere, +# boxMin=[Ox + Lx / 10., Oy + Ly / 10., Oz + Lz / 10.], +# boxMax=[Lx - Lx / 10., Ly - Ly / 10., Lz - Lz / 10.], +# Reynolds=uinf * obstRadius/ visco, +# frequency=outModuloForces, +# outputPrefix=outputForces) energy = Energy_enstrophy(velocity=velocity, vorticity=vorticity, topology=topoCart, frequency=outModuloEnergies, outputPrefix=outputEnergies) -navierStokes.addDiagnostics([forces, energy]) +navierStokes.addDiagnostics([energy]) navierStokes.setSolver(finalTime, timeStep, solver_type='basic', io=printer) diff --git a/Examples/Attic/NavierStokes3d_vortRing.py b/Examples/Attic/NavierStokes3d_vortRing.py index ab8803fcf..fd7053228 100755 --- a/Examples/Attic/NavierStokes3d_vortRing.py +++ b/Examples/Attic/NavierStokes3d_vortRing.py @@ -1,4 +1,6 @@ #!/usr/bin/python +import sys +sys.path.insert(0,'/scratch/mimeau/install-parmes3/') import time import parmepy as pp from parmepy.f2py import fftw2py @@ -6,7 +8,6 @@ import numpy as np import mpi4py.MPI as MPI import math as m from parmepy.constants import PARMES_REAL, ORDER -from parmepy.domain.obstacle.obstacle_3D import Obstacle3D from parmepy.operator.advection import Advection from parmepy.operator.stretching import Stretching from parmepy.operator.poisson import Poisson @@ -14,9 +15,12 @@ from parmepy.operator.diffusion import Diffusion from parmepy.operator.penalization import Penalization from parmepy.operator.redistribute import Redistribute from parmepy.problem.navier_stokes import NSProblem +from parmepy.problem.simulation import Simulation from parmepy.operator.monitors.energy_enstrophy import Energy_enstrophy +from parmepy.operator.monitors.reprojection_criterion import Reprojection_criterion from parmepy.operator.monitors.printer import Printer + #from numpy import linalg as LA pi = m.pi @@ -39,8 +43,11 @@ Lz = np.float64(inputData.readline().rstrip('\n\r')) resX = np.uint32(inputData.readline().rstrip('\n\r')) resY = np.uint32(inputData.readline().rstrip('\n\r')) resZ = np.uint32(inputData.readline().rstrip('\n\r')) -timeStep = np.float64(inputData.readline().rstrip('\n\r')) +dt = np.float64(inputData.readline().rstrip('\n\r')) finalTime = np.float64(inputData.readline().rstrip('\n\r')) +restart = np.uint32(inputData.readline().rstrip('\n\r')) +dumpfreq = np.uint32(inputData.readline().rstrip('\n\r')) +dumpfile = inputData.readline().rstrip('\n\r') outModuloPrinter = np.uint32(inputData.readline().rstrip('\n\r')) outputPrinter = inputData.readline().rstrip('\n\r') outModuloForces = np.uint32(inputData.readline().rstrip('\n\r')) @@ -51,12 +58,17 @@ visco = np.float64(inputData.readline().rstrip('\n\r')) vortProj = np.uint32(inputData.readline().rstrip('\n\r')) methodAdv = inputData.readline().rstrip('\n\r') methodStretch = inputData.readline().rstrip('\n\r') +multires = np.uint32(inputData.readline().rstrip('\n\r')) +resFilterX = np.uint32(inputData.readline().rstrip('\n\r')) +resFilterY = np.uint32(inputData.readline().rstrip('\n\r')) +resFilterZ = np.uint32(inputData.readline().rstrip('\n\r')) inputData.close() # Parameters dim = 3 nbElem = [resX, resY, resZ] +nbElemFilter = [resFilterX, resFilterY, resFilterZ] t0 = time.time() @@ -153,36 +165,53 @@ poisson = Poisson(velo, vorti, resolutions={velo: nbElem, vorti: nbElem}, method='fftw', - projection=vortProj + projection=vortProj, + multires=multires, + filterSize=box.length / \ + (np.asarray(nbElemFilter, + dtype=PARMES_REAL) - 1) ) +## Diagnostics related to the problem +energy = Energy_enstrophy(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + viscosity=visco, + frequency=outModuloEnergies, + prefix=outputEnergies) + +reproj = Reprojection_criterion(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method='FD_order4', + frequency=1, + prefix='./res/Reproj.dat') + +printer = Printer(fields=[vorti, velo], + frequency=outModuloPrinter, + prefix=outputPrinter) + distrAdvStr = Redistribute([vorti, velo], advec, stretch) distrStrPoiss = Redistribute([vorti, velo], stretch, poisson) -## Define the problem to solve -#pb = NSProblem([advec, diffusion, poisson], -pb = NSProblem([advec, distrAdvStr, stretch, distrStrPoiss, diffusion, poisson], - monitors=[Energy_enstrophy(velo, vorti, - resolutions={velo: nbElem, - vorti: nbElem}, - viscosity=visco, - frequency=outModuloEnergies, - outputPrefix=outputEnergies), - Printer(fields=[vorti, velo], - resolutions={velo: nbElem, - vorti: nbElem}, - frequency=outModuloPrinter, - outputPrefix=outputPrinter)]) - - +## Definition of simulation parameters +simu = Simulation(tinit=0.0, tend=finalTime, timeStep=dt, iterMax=1000000) +## Define the problem to solve +#pb = NSProblem([diffusion, poisson], +pb = NSProblem(operators=[advec, distrAdvStr, stretch, distrStrPoiss, diffusion, poisson], + simulation=simu, monitors=[printer, energy, reproj], dumpFreq=int(dumpfreq), name=dumpfile) ## Setting solver to Problem -pb.setUp(finalTime, timeStep) +pb.setUp() + +## Restarting Problem from dumped field values +if restart : + pb.restart(dumpfile) t1 = time.time() ## Solve problem -#poisson.apply(0., timeStep, 0) +#poisson.apply(simu) timings = pb.solve() tf = time.time() diff --git a/Examples/testDiffusion.py b/Examples/testDiffusion.py index 3872fc894..6ef8bfe40 100755 --- a/Examples/testDiffusion.py +++ b/Examples/testDiffusion.py @@ -2,8 +2,8 @@ import parmepy as pp from parmepy.operator.diffusion import Diffusion from parmepy.operator.poisson import Poisson -from parmepy.problem.navier_stokes import NSProblem from parmepy.operator.monitors.energy_enstrophy import Energy_enstrophy +from parmepy.problem.simulation import Simulation import numpy as np import math pi = math.pi @@ -48,36 +48,57 @@ vorticity = pp.Field(domain=dom, formula=computeVort, ## Definition of the Diffusion and Poisson operators +output = 'energy.dat' nu = 1e-3 +finalTime = 1.0 +dt = 0.01 +restartTime = 0.5 +filenameVel = 'dump_velo_T=_' +filenameVel += str(restartTime) + +filenameVort = 'dump_vort_T=_' +filenameVort += str(restartTime) + diffusion = Diffusion(vorticity, resolution=resol, viscosity=nu) poisson = Poisson(velocity, vorticity, resolutions={velocity: resol, vorticity: resol}) -output = 'energy.dat' - -timeStep = 1e-2 - +## Definition of monitor monitor = Energy_enstrophy(velocity, vorticity, resolutions={velocity: resol, vorticity: resol}, viscosity=nu, frequency=1, - outputPrefix=output) + prefix=output) + +## Definition of simulation parameters +tini = restartTime +niter = (finalTime - tini) / dt +simu = Simulation(tinit=tini, tend=finalTime, nbiter=niter) diffusion.setUp() poisson.setUp() monitor.setUp() -t = 0.0 -niter = 1 +velocity.initialize() vorticity.initialize() print "pre ", vorticity.norm() +velocity.load('dump_velo_T=_0.5') +vorticity.load('dump_vort_T=_0.5') + +while simu.time <= finalTime: + print 'time, niter : ', simu.time, simu.currentIteration +# if (simu.currentIteration == 50): +# print 'dump fields ...' +# velocity.dump(filenameVel) +# vorticity.dump(filenameVort) +# print "norm restart ", vorticity.norm() + diffusion.apply(simu) + poisson.apply(simu) + monitor.apply(simu) + simu.time += simu.timeStep + simu.currentIteration += 1 -while t <= 1.0: - diffusion.apply(timeStep) - poisson.apply() - monitor.apply(t, timeStep, niter) - t += timeStep print "post ", vorticity.norm() diff --git a/HySoP/hysop/f2py/fftw2py.f90 b/HySoP/hysop/f2py/fftw2py.f90 index 9225ff8b6..42764aca1 100755 --- a/HySoP/hysop/f2py/fftw2py.f90 +++ b/HySoP/hysop/f2py/fftw2py.f90 @@ -192,4 +192,20 @@ contains end subroutine projection_om_3d + !> Projects vorticity values from fine to coarse grid : + !! @param[in] dxf, dyf, dzf: grid filter size = domainLength/(CoarseRes-1) + !! in the following, omega is the 3D vorticity vector field. + subroutine multires_om_3d(dxf, dyf, dzf, omega_x,omega_y,omega_z) + real(pk), intent(in) :: dxf, dyf, dzf + real(pk),dimension(:,:,:),intent(inout):: omega_x,omega_y,omega_z + !f2py intent(in,out) :: omega_x,omega_y,omega_z + + call r2c_3d(omega_x,omega_y,omega_z) + + call filter_multires_om_3d(dxf, dyf, dzf) + + call c2r_3d(omega_x,omega_y,omega_z) + + end subroutine multires_om_3d + end module fftw2py diff --git a/HySoP/hysop/operator/discrete/poisson_fft.py b/HySoP/hysop/operator/discrete/poisson_fft.py index 6620e3aee..f0616c3ef 100644 --- a/HySoP/hysop/operator/discrete/poisson_fft.py +++ b/HySoP/hysop/operator/discrete/poisson_fft.py @@ -3,8 +3,9 @@ @file poisson_fft.py Discrete operator for Poisson problem (fftw based) """ - +import numpy as np from parmepy.f2py import fftw2py +from parmepy.constants import PARMES_REAL, ORDER from discrete import DiscreteOperator from parmepy.constants import debug, prof from parmepy.tools.timers import timed_function @@ -17,7 +18,8 @@ class PoissonFFT(DiscreteOperator): """ @debug - def __init__(self, velocity, vorticity, method=None, projection=False): + def __init__(self, velocity, vorticity, method=None, projection=False, + multires=False, filterSize=None): """ Constructor. @param[out] velocity : discretisation of the solution field @@ -29,6 +31,10 @@ class PoissonFFT(DiscreteOperator): self.vorticity = vorticity ## Solenoidal projection on vorticity ? self.projection = projection + ## Multiresolution ? + self.multires = multires + ## Filter size array = domainLength/(CoarseRes-1) + self.filterSize = filterSize # Base class initialisation DiscreteOperator.__init__(self, [velocity, vorticity], method, name="Poisson FFT") @@ -51,6 +57,8 @@ class PoissonFFT(DiscreteOperator): @prof @timed_function def apply(self, simulation=None): + ite = simulation.currentIteration + if self.case is '2D': self.velocity.data[0], self.velocity.data[1] =\ fftw2py.solve_poisson_2d(self.vorticity.data, @@ -58,22 +66,47 @@ class PoissonFFT(DiscreteOperator): self.velocity.data[1]) elif self.case is '3D': - #=== SOLENOIDAL PROJECTION ON VORTICITY FIELD === - if (self.projection): + #=== SOLENOIDAL PROJECTION OF VORTICITY FIELD === + if (self.projection and ite % 10 == 0): 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]) - 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]) + if (self.multires): + # Projects vorticity values from fine to coarse grid + # in frequencies space by nullifying the smallest modes + vortFilter = np.copy(self.vorticity.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 + self.velocity.data[0], self.velocity.data[1], \ + self.velocity.data[2] = \ + fftw2py.solve_poisson_3d(vortFilter[0], + vortFilter[1], + vortFilter[2], + self.velocity.data[0], + self.velocity.data[1], + self.velocity.data[2]) + + else : + # Solves Poisson equation using usual vorticity + 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]) else: raise ValueError("invalid problem dimension") diff --git a/HySoP/hysop/operator/discrete/scales_advection.py b/HySoP/hysop/operator/discrete/scales_advection.py index 845a55d57..d35a2eb50 100644 --- a/HySoP/hysop/operator/discrete/scales_advection.py +++ b/HySoP/hysop/operator/discrete/scales_advection.py @@ -7,7 +7,7 @@ Discrete Advection operator based on scales library (Jean-Baptiste) from parmepy.f2py import scales2py from discrete import DiscreteOperator from parmepy.fields.vector import VectorField -from parmepy.constants import debug +from parmepy.constants import debug, np from parmepy.tools.timers import timed_function @@ -47,20 +47,98 @@ class ScalesAdvection(DiscreteOperator): raise ValueError("Missing simulation value for computation.") dt = simulation.timeStep - for adF in self.advectedFields: - if isinstance(adF, VectorField): - for d in xrange(adF.dimension): - adF[d][...] = scales2py.solve_advection( - dt, self.velocity.data[0], + +# for adF in self.advectedFields: +# if isinstance(adF, VectorField): +# for d in xrange(adF.dimension): +# adF[d][...] = scales2py.solve_advection( +# dt, self.velocity.data[0], +# self.velocity.data[1], +# self.velocity.data[2], +# adF[d][...]) +# else: +# adF[...] = scales2py.solve_advection( +# dt, self.velocity.data[0], +# self.velocity.data[1], +# self.velocity.data[2], +# adF.data) + + + ## Space discretization of grad(u) + mesh_size = self.velocity.topology.mesh.space_step + ind=np.arange(self.velocity.topology.mesh.resolution[0]) + +### First order scheme +### X components of temp and result + temp1 = (self.velocity[0][...] - + self.velocity[0][np.roll(ind,+1),...]) / (mesh_size[0]) + + temp2 = (self.velocity[0][...] - + self.velocity[0][:,np.roll(ind,+1),:]) / (mesh_size[1]) + + temp3 = (self.velocity[0][...] - + self.velocity[0][...,np.roll(ind,+1)]) / (mesh_size[2]) + + maxstr1= np.max(abs(temp1)+abs(temp2)+abs(temp3)) + maxadv1= np.max(abs(temp1)) + +# Y components of temp and result + temp4 = (self.velocity[1][...] - + self.velocity[1][np.roll(ind,+1),...]) / (mesh_size[0]) + + temp5 = (self.velocity[1][...] - + self.velocity[1][:,np.roll(ind,+1),:]) / (mesh_size[1]) + + temp6 = (self.velocity[1][...] - + self.velocity[1][...,np.roll(ind,+1)]) / (mesh_size[2]) + + maxstr2= np.max(abs(temp4)+abs(temp5)+abs(temp6)) + maxadv2= np.max(abs(temp5)) + +# Z components of temp and result + temp7 = (self.velocity[2][...] - + self.velocity[2][np.roll(ind,+1),...]) / (mesh_size[0]) + + temp8 = (self.velocity[2][...] - + self.velocity[2][:,np.roll(ind,+1),:]) / (mesh_size[1]) + + temp9 = (self.velocity[2][...] - + self.velocity[2][...,np.roll(ind,+1)]) / (mesh_size[2]) + + maxstr3= np.max(abs(temp7)+abs(temp8)+abs(temp9)) + maxadv3= np.max(abs(temp9)) + maxAdv = max(maxadv1,maxadv2,maxadv3) + + stabcoeff = 1.0 / 2.0 + + print "dtAdvec", stabcoeff / maxAdv + + ## Time Subcycles + dtadv = dt + dtadv = min(dtadv, stabcoeff / maxAdv) + if dt == dtadv: + print "dtadv, ndt, stab/max ", dtadv, int(dt / dtadv), stabcoeff / maxAdv + ndt = int(dt / dtadv) + else: + print "dtadv, ndt", dtadv, int(dt / dtadv) + 1, stabcoeff / maxAdv + ndt = int(dt / dtadv) + 1 + dtadv = dt / float(ndt) + + for i in range(ndt): + for adF in self.advectedFields: + if isinstance(adF, VectorField): + for d in xrange(adF.dimension): + adF[d][...] = scales2py.solve_advection( + dtadv, self.velocity.data[0], + self.velocity.data[1], + self.velocity.data[2], + adF[d][...]) + else: + adF[...] = scales2py.solve_advection( + dtadv, self.velocity.data[0], self.velocity.data[1], self.velocity.data[2], - adF[d][...]) - else: - adF[...] = scales2py.solve_advection( - dt, self.velocity.data[0], - self.velocity.data[1], - self.velocity.data[2], - adF.data) + adF.data) def finalize(self): """ diff --git a/HySoP/hysop/operator/energy_enstrophy.py b/HySoP/hysop/operator/energy_enstrophy.py index 1486fc1c1..83725d448 100644 --- a/HySoP/hysop/operator/energy_enstrophy.py +++ b/HySoP/hysop/operator/energy_enstrophy.py @@ -3,9 +3,11 @@ @file energy_enstrophy.py Compute Energy and Enstrophy """ -from parmepy.constants import np, debug, PARMES_REAL +import numpy as np +from numpy import linalg as la +from parmepy.constants import np, debug, PARMES_REAL, PARMES_MPI_REAL from parmepy.operator.monitors.monitoring import Monitoring -from parmepy.mpi import main_rank, main_comm, MPI +from parmepy.mpi import main_rank, main_comm, main_size, MPI from parmepy.tools.timers import timed_function @@ -50,12 +52,15 @@ class Energy_enstrophy(Monitoring): Monitoring.setUp(self) discreteFields = {} self.spaceStep = {} + topodims = np.ones((self.domain.dimension)) + topodims[-1] = main_size # Variables discretization for v in self.variables: # the topology for v ... topo = self.domain.getOrCreateTopology(self.domain.dimension, - self.resolutions[v]) + self.resolutions[v], + topodims) # ... and the corresponding discrete field discreteFields[v] = v.discretize(topo) self.spaceStep[v] = topo.mesh.space_step @@ -87,57 +92,71 @@ class Energy_enstrophy(Monitoring): else: raise ValueError("invalid problem dimension") - energy = (0.5 * squareNormVel) / (2.0 * np.pi) ** 3 + myEnergy = (0.5 * squareNormVel) / (2.0 * np.pi) ** 3 # Enstrophy computation dvol = np.prod(self.spaceStep[self.vorticity]) if (self.vort.dimension == 2): - enstrophy = np.sum(self.vort.data ** 2) * dvol + myEnstrophy = np.sum(self.vort.data ** 2) * dvol elif (self.vort.dimension == 3): - enstrophy = np.sum(self.vort.data[0] ** 2 + + myEnstrophy = np.sum(self.vort.data[0] ** 2 + self.vort.data[1] ** 2 + self.vort.data[2] ** 2) * dvol else: raise ValueError("invalid problem dimension") - enstrophy = enstrophy / (2.0 * np.pi) ** 3 + myEnstrophy = myEnstrophy / (2.0 * np.pi) ** 3 - # 1st order -# effectiveViscosity = - (energy - self.buffer_1) / (dt * enstrophy) -# timeDerivativeEnergy = - (energy - self.buffer_1) / dt + # Collective communications - # 2nd order - effectiveViscosity = - (3.0 * energy - 4.0 * - self.buffer_1 + 1.0 * self.buffer_2) / \ - (2.0 * dt * enstrophy) + topovelo = self.velo.topology + energy = topovelo.comm.reduce(myEnergy, PARMES_MPI_REAL, op=MPI.SUM, root=0) + energyBuff1 = topovelo.comm.reduce(self.buffer_1, PARMES_MPI_REAL, op=MPI.SUM, root=0) + energyBuff2 = topovelo.comm.reduce(self.buffer_2, PARMES_MPI_REAL, op=MPI.SUM, root=0) - timeDerivativeEnergy = - (3.0 * energy - 4.0 * self.buffer_1 + 1.0 * - self.buffer_2) / (2.0 * dt) + topovort = self.vort.topology + enstrophy = topovort.comm.reduce(myEnstrophy, PARMES_MPI_REAL, op=MPI.SUM, root=0) - ratio = effectiveViscosity / self.viscosity + # Update buffers - nuEnstrophy = self.viscosity * enstrophy + self.buffer_2 = self.buffer_1 + self.buffer_1 = myEnergy - nu_effEnstrophy = effectiveViscosity * enstrophy + # Effective viscosity computation - self.buffer_2 = self.buffer_1 - self.buffer_1 = energy + if main_rank == 0 : + + # 1st order + # effectiveViscosity = - (energy - energyBuff1) / (dt * enstrophy) + # timeDerivativeEnergy = - (energy - energyBuff1) / dt + + # 2nd order + effectiveViscosity = - (3.0 * energy - 4.0 * + energyBuff1 + 1.0 * energyBuff2) / \ + (2.0 * dt * enstrophy) + + ratio = effectiveViscosity / self.viscosity + + # Energy dissipation computation + + timeDerivativeEnergy = - (3.0 * energy - 4.0 * energyBuff1 + 1.0 * + energyBuff2) / (2.0 * dt) + + nuEnstrophy = self.viscosity * enstrophy -# dissipE = 0. -# main_comm.Reduce(nuEnstrophy, dissipE, op=MPI.SUM, root=0) - dissipE = main_comm.reduce(nuEnstrophy, op=MPI.SUM, root=0) + nu_effEnstrophy = effectiveViscosity * enstrophy + # dissipE = main_comm.reduce(nuEnstrophy, PARMES_MPI_REAL, op=MPI.SUM, root=0) if ((main_rank == 0) and (ite % self.freq == 0) and (t > dt)): self.f = open(self.prefix, 'a') -# self.f.write("%s %s %s %s %s %s %s\n" % (t, energy, -# enstrophy, -# ratio, -# timeDerivativeEnergy, -# nuEnstrophy, -# nu_effEnstrophy)) - self.f.write("%s %s\n" % (t, dissipE)) + self.f.write("%s %s %s %s %s %s %s\n" % (t, energy, + enstrophy, + ratio, + timeDerivativeEnergy, + nuEnstrophy, + nu_effEnstrophy)) self.f.close() def __str__(self): diff --git a/HySoP/hysop/operator/monitors/compute_forces.py b/HySoP/hysop/operator/monitors/compute_forces.py index 8a9acbed7..5e99259b0 100644 --- a/HySoP/hysop/operator/monitors/compute_forces.py +++ b/HySoP/hysop/operator/monitors/compute_forces.py @@ -399,6 +399,8 @@ class Compute_forces(Monitoring): """ t = simulation.time dt = simulation.timeStep + ite = simulation.currentIteration + if self.nbPointsBox == 0: pass else : diff --git a/HySoP/hysop/operator/monitors/printer.py b/HySoP/hysop/operator/monitors/printer.py index dfa31245f..4f1656e4d 100644 --- a/HySoP/hysop/operator/monitors/printer.py +++ b/HySoP/hysop/operator/monitors/printer.py @@ -115,8 +115,8 @@ class Printer(Monitoring): except AttributeError: pass # Set output file name - filename = self.prefix + "iter_{0:06d}".format(ite) - filename += '_' + str(main_rank) + self.ext + filename = self.prefix + str(main_rank) + filename += '_' + "iter_{0:02d}".format(ite) + self.ext print "Print to file " + filename ## VTK output \todo: Need fix in 2D, getting an IOError. if self.ext == '.vtk': diff --git a/HySoP/hysop/operator/reprojection.py b/HySoP/hysop/operator/reprojection.py new file mode 100644 index 000000000..87e3a2e99 --- /dev/null +++ b/HySoP/hysop/operator/reprojection.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +""" +@file reprojection_criterion.py +Compute reprojection criterion and divergence maximum +""" +import numpy as np +from numpy import linalg as la +from parmepy.constants import np, debug, PARMES_REAL, PARMES_MPI_REAL +from parmepy.operator.monitors.monitoring import Monitoring +from parmepy.numerics.differentialOperator import DifferentialOperator +from parmepy.mpi import main_rank, main_comm, main_size, MPI +from parmepy.tools.timers import timed_function + + +class Reprojection_criterion(Monitoring): + """ + Computes and prints reprojection criterion and divergence maximum + """ + + def __init__(self, velocity, vorticity, + resolutions=None, + method=None, + frequency=None, prefix=None): + """ + Constructor. + @param fields : List of fields + @param resolutions : list of resolutions (one per variable) + @param frequency : output file producing frequency. + @param prefix : file name prefix, contains relative path. + """ + Monitoring.__init__(self, [velocity, vorticity], frequency, + name="Reprojection") + self.prefix = prefix + self.velocity = velocity + self.vorticity = vorticity + self.resolutions = resolutions + self.method = method + if (main_rank == 0): + self.f = open(self.prefix, 'w') + self.input = [velocity, vorticity] + self.output = [] + + def setUp(self): + Monitoring.setUp(self) + discreteFields = {} + topodims = np.ones((self.domain.dimension)) + topodims[-1] = main_size + nbGhosts = 0 + if self.method.find('FD_order2') >= 0: + nbGhosts = 1 + elif self.method.find('FD_order4') >= 0: + nbGhosts = 2 + else: + nbGhosts = 2 + + # Variables discretization + ghosts = np.zeros((self.domain.dimension)) + ghosts[:] = nbGhosts + for v in self.variables: + # the topology for v ... + topo = self.domain.getOrCreateTopology(self.domain.dimension, + self.resolutions[v], + ghosts=ghosts) + # ... and the corresponding discrete field + discreteFields[v] = v.discretize(topo) + self.velo = discreteFields[self.velocity] + self.vort = discreteFields[self.vorticity] + + self._isUpToDate = True + + @debug + @timed_function + def apply(self, simulation=None): + """ + Computes and prints reprojection criterion and divergence maximum + """ + t = simulation.time + dt = simulation.timeStep + ite = simulation.currentIteration + gradVort, maxArrayVort, divVort = \ + DifferentialOperator(self.vort, self.vort, self.method, + choice='gradV').__call__() + + gradVelo, maxArrayVelo, divVelo = \ + DifferentialOperator(self.velo, self.velo, self.method, + choice='gradV').__call__() + + maxDiv = np.max(abs(divVort)) + maxdwx_dx = np.max(abs(gradVort[0])) + maxdwx_dy = np.max(abs(gradVort[1])) + maxdwx_dz = np.max(abs(gradVort[2])) + maxdwy_dx = np.max(abs(gradVort[3])) + maxdwy_dy = np.max(abs(gradVort[4])) + maxdwy_dz = np.max(abs(gradVort[5])) + maxdwz_dx = np.max(abs(gradVort[6])) + maxdwz_dy = np.max(abs(gradVort[7])) + maxdwz_dz = np.max(abs(gradVort[8])) + maxmax = max(maxdwx_dx, maxdwx_dy, maxdwx_dz, + maxdwy_dx, maxdwy_dy, maxdwy_dz, + maxdwz_dx, maxdwz_dy, maxdwz_dz) + projCriterion = maxDiv / maxmax + dtstabAdv = 0.5 / maxArrayVelo[1] + dtstabStretch = 2.5127 / maxArrayVelo[0] + + if ((main_rank == 0) and (ite % self.freq == 0) and (t > dt)): + self.f = open(self.prefix, 'a') + self.f.write("%s %s %s %s %s %s %s %s %s %s %s %s %s %s\n" % (t, projCriterion, + maxDiv, + maxdwx_dx, + maxdwx_dy, + maxdwx_dz, + maxdwy_dx, + maxdwy_dy, + maxdwy_dz, + maxdwz_dx, + maxdwz_dy, + maxdwz_dz, + dtstabAdv, + dtstabStretch)) + self.f.close() + + def __str__(self): + s = "Reprojection_criterion. " + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : Reprojection_criterion" + print Reprojection_criterion.__doc__ diff --git a/HySoP/src/fftw/fft3d.f90 b/HySoP/src/fftw/fft3d.f90 index d06ecd737..5a4a8878a 100755 --- a/HySoP/src/fftw/fft3d.f90 +++ b/HySoP/src/fftw/fft3d.f90 @@ -25,7 +25,8 @@ module fft3d public :: init_r2c_3d,init_c2c_3d,r2c_3d,c2c_3d,c2r_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_projection_om_3d + filter_poisson_3d_many, filter_diffusion_3d, filter_projection_om_3d,& + filter_multires_om_3d !> plan for fftw "c2c" forward or r2c transform type(C_PTR) :: plan_forward1, plan_forward2, plan_forward3 @@ -682,6 +683,34 @@ contains end do end subroutine filter_projection_om_3d + + !> Projects vorticity values from fine to coarse grid : + !> the smallest modes of vorticity are nullified + !! @param[in] dxf, dyf, dzf: grid filter size = domainLength/(CoarseRes-1) + subroutine filter_multires_om_3d(dxf, dyf, dzf) + + real(C_DOUBLE), intent(in) :: dxf, dyf, dzf + integer(C_INTPTR_T) :: i,j,k + real(C_DOUBLE) :: kxc, kyc, kzc + + kxc = pi / dxf + kyc = pi / dyf + kzc = pi / dzf + + !! mind the transpose -> index inversion between y and z + do j = 2,local_resolution(c_Y) + do k = 2, fft_resolution(c_Z) + do i = 2, local_resolution(c_X) + if ((abs(kx(i))>kxc) .and. (abs(ky(j))>kyc) .and. (abs(kz(k))>kzc)) then + dataout1(i,k,j) = 0. + dataout2(i,k,j) = 0. + dataout3(i,k,j) = 0. + endif + end do + end do + end do + + end subroutine filter_multires_om_3d !> Solve Poisson problem in the Fourier space : !! \f{eqnarray*} \Delta \psi &=& - \omega \\ v &=& \nabla\times\psi \f} -- GitLab