From 6327a5ac8a30858380435de971180eb9619418f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20P=C3=A9rignon?= <franck.perignon@imag.fr> Date: Mon, 1 Dec 2014 11:17:14 +0100 Subject: [PATCH] Add flow around sphere example (first draft with new version) --- Examples/FlowAroundSphere.py | 373 +++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 Examples/FlowAroundSphere.py diff --git a/Examples/FlowAroundSphere.py b/Examples/FlowAroundSphere.py new file mode 100644 index 000000000..6e43288b5 --- /dev/null +++ b/Examples/FlowAroundSphere.py @@ -0,0 +1,373 @@ +#!/usr/bin/python + +""" +Taylor Green 3D : see paper van Rees 2011. + +All parameters are set and defined in python module dataTG. + +""" + +from hysop import Box +from hysop.f2py import fftw2py +import numpy as np +from hysop.fields.continuous import Field +from hysop.fields.variable_parameter import VariableParameter +from hysop.mpi.topology import Cartesian +from hysop.operator.advection import Advection +from hysop.operator.stretching import Stretching +from hysop.operator.poisson import Poisson +from hysop.operator.diffusion import Diffusion +from hysop.operator.adapt_timestep import AdaptTimeStep +from hysop.operator.redistribute_intra import RedistributeIntra +from hysop.operator.hdf_io import HDF_Writer +from hysop.operator.energy_enstrophy import EnergyEnstrophy +from hysop.problem.simulation import Simulation +from hysop.methods_keys import Scales, TimeIntegrator, Interpolation,\ + Remesh, Support, Splitting, dtCrit, SpaceDiscretisation +from hysop.numerics.integrators.runge_kutta2 import RK2 as RK2 +from hysop.numerics.integrators.runge_kutta3 import RK3 as RK3 +from hysop.numerics.integrators.runge_kutta4 import RK4 as RK4 +from hysop.numerics.finite_differences import FD_C_4, FD_C_2 +from hysop.numerics.interpolation import Linear +from hysop.numerics.remeshing import L6_4 as rmsh +import hysop.tools.io_utils as io +from hysop.mpi import main_rank, MPI +from hysop.tools.parameters import Discretization, IO_params + +print " ========= Start Navier-Stokes 3D (Taylor Green benchmark) =========" + +# ====== pi constant and trigonometric functions ====== +pi = np.pi +cos = np.cos +sin = np.sin + +# ====== Flow constants ======= +uinf = 1.0 +VISCOSITY = 1. / 300. + +# ======= Domain ======= +dim = 3 +Nx = 129 +Ny = Nz = 65 +g = 2 +boxlength = npw.realarray([10.24, 5.12, 5.12]) +boxorigin = npw.realarray([-2.0, -2.56, -2.56]) +box = Box(dim, length=boxlength, origin=boxorigin) + +# A global discretization with ghost points +d3dg = Discretization([Nx, Ny, Nz], [g, g, g]) +# A global discretization, without ghost points +d3d = Discretization([Nx, Ny, Nz]) + +# ====== Sphere inside the domain ====== +RADIUS = 0.5 +pos = [0., 0., 0.] +from hysop.domain.subsets.sphere import Sphere +sphere = Sphere(origin=pos, radius=RADIUS, parent=box) + + +# ======= Function to compute initial velocity ======= +def computeVel(res, x, y, z, t): + res[0][...] = uinf + res[1][...] = 0. + res[2][...] = 0. + return res + + +# ======= Function to compute initial vorticity ======= +def computeVort(res, x, y, z, t): + res[0][...] = 0. + res[1][...] = 0. + res[2][...] = 0. + return res + + +# ====== Time-dependant required-flowrate (Variable Parameter) ====== +def computeFlowrate(simu): + # === Time-dependant flow rate === + t = simu.tk + Tstart = 3.0 + flowrate = np.zeros(3) + flowrate[0] = uinf * box.length[1] * box.length[2] + if t >= Tstart and t <= Tstart + 1.0: + flowrate[1] = sin(pi * (t - Tstart)) * \ + box.length[1] * box.length[2] + # === Constant flow rate === + # flowrate = np.zeros(3) + # flowrate[0] = uinf * box.length[1] * box.length[2] + return flowrate + + +# ======= Fields ======= +velo = Field(domain=box, formula=computeVel, + name='Velocity', isVector=True) +vorti = Field(domain=box, formula=computeVort, + name='Vorticity', isVector=True) + + +# ========= Simulation setup ========= +simu = Simulation(tinit=0.0, tend=10.0, timeStep=0.0125, iterMax=50) + + +# Adaptative timestep method : dt = min(values(dtCrit)) +# where dtCrit is a list of criterions on which the computation +# of the adaptative time step is based +# ex : dtCrit = ['gradU', 'cfl', 'stretch'], means : +# dt = min (dtAdv, dtCfl, dtStretch), where dtAdv is equal to LCFL / |gradU| +# For dtAdv, the possible choices are the following: +# 'vort' (infinite norm of vorticity) : dtAdv = LCFL / |vort| +# 'gradU' (infinite norm of velocity gradient), dtAdv = LCFL / |gradU| +# 'deform' (infinite norm of deformation tensor), +# dtAdv = LCFL / (0.5(gradU + gradU^T)) +op = {} +iop = IO_params("time_step") +# Default topology (i.e. 3D, with ghosts) +topo_with_ghosts = box.create_topology(d3dg) + + +op['dtAdapt'] = AdaptTimeStep(velo, vorti, simulation=simu, + discretization=topo_with_ghosts, + method={TimeIntegrator: RK3, + SpaceDiscretisation: FD_C_4, + dtCrit: ['gradU', 'stretch']}, + io_params=iop, + lcfl=0.125, + cfl=0.5) + +op['advection'] = Advection(velo, vorti, + discretization=d3d, + method={Scales: 'p_M6', + Splitting: 'classic'} + ) + +op['stretching'] = Stretching(velo, vorti, + discretization=topo_with_ghosts) + +op['diffusion'] = Diffusion(viscosity=VISCOSITY, vorticity=vorti, + discretization=d3d) + + +rate = VariableParameter(formula=computeFlowrate) +op['poisson'] = Poisson(velo, vorti, discretization=d3d, flowrate=rate) + +# ===== Discretization of computational operators ====== +for ope in op.values(): + ope.discretize() + +topofft = op['poisson'].discreteFields[vorti].topology +topoadvec = op['advection'].discreteFields[vorti].topology + +# ===== Penalization of the vorticity on a sphere inside the domain ===== +from hysop.operator.penalize_vorticity import PenalizeVorticity +op['penalVort'] = PenalizeVorticity(velocity=velo, vorticity=vorti, + discretization=topo_with_ghosts, + obstacles=[sphere], coeff=1e8, + method={SpaceDiscretisation: FD_C_4}) +op['penalVort'].discretize() + + +# ==== Operators to map data between the different computational operators === +# (i.e. between topologies) +distr = {} +distr['fft2str'] = RedistributeIntra(source=op['poisson'], + target=op['stretching'], + variables=[velo, vorti]) +distr['str2fft'] = RedistributeIntra(source=op['stretching'], + target=op['diffusion'], + variables=[velo, vorti]) +distr['fft2advec'] = RedistributeIntra(source=op['poisson'], + target=op['advection'], + variables=[velo, vorti]) +distr['advec2fft'] = RedistributeIntra(source=op['advection'], + target=op['poisson'], + variables=[velo, vorti]) +# ========= Monitoring operators ========= + +iop = IO_params('fields', frequency=100) +monitors['writer'] = HDF_Writer(variables={velo: topofft, vorti: topofft}, + io_params=iop) + +io_ener = IO_params('energy_enstrophy') +monitors['energy'] = EnergyEnstrophy(velo, vorti, discretization=topofft, + io_params=io_ener) + +ref_step = topo_with_ghosts.mesh.space_step +cbpos = npw.zeros(dim) +cblength = npw.zeros(dim) +cbpos[...] = boxorigin[...] +cbpos += 15 * ref_step +cblength[...] = boxlength[...] +cblength -= 30 * ref_step +cb = ControlBox(box, cbpos, cblength) +coeffForce = 1. / (0.5 * uinf ** 2 * pi * RADIUS ** 2) + +io_forces=IO_params('drag_and_lift') +monitors['forces'] = DragAndLift(velo, vorti, VISCOSITY, coeffForce, + discretization=topo_with_ghosts, cb, + obstacles=[sphere], io_params=io_forces) + +io_forcesPenal=IO_params('drag_and_lift_penal') +monitors['forcesPenal'] = DragAndLiftPenal(velo, vorti, coeffForce, + discretization=topofft, + obstacles=[sphere], factor=[1e8], + io_params=io_forcesPenal) + +step_dir = ref_step[0] +io_sliceXY = IO_params('sliceXY', frequency=200) +thickSliceXY = ControlBox(box, origin=[-2.0, -2.56, -2.0 * step_dir], + lengths=[10.24, 5.12, 4.0 * step_dir]) +monitors['writerSliceXY'] = HDF_Writer(variables={velo: topofft, vorti: topofft}, + io_params=io_sliceXY, subset=thickSliceXY, + xmfalways=True) + +io_sliceXZ = IO_params('sliceXZ', frequency=2000) +thickSliceXZ = ControlBox(box, origin=[-2.0, -2.0 * step_dir, -2.56], + lengths=[10.24, 4.0 * step_dir, 5.12]) +monitors['writerSliceXZ'] = HDF_Writer(variables={velo: topofft, vorti: topofft}, + io_params=io_sliceXZ, subset=thickSliceXZ, + xmfalways=True) + +io_subBox = IO_params('subBox', frequency=2000) +subBox = ControlBox(box, origin=[-0.7, -2.0, -2.0], lengths=[8.0, 4.0, 4.0]) +monitors['writerSubBox'] = HDF_Writer(variables={velo: topofft, vorti: topofft}, + io_params=io_subBox, subset=subBox, + xmfalways=True) + +## ========= Monitors discretization========= +for monit in monitors.values(): + monit.discretize() + +# ========= Setup for all declared operators/monitors ========= +time_setup = MPI.Wtime() +for ope in op.values(): + ope.setup() +for ope in distr.values(): + ope.setup() +for monit in monitors.values(): + monit.setUp() + +print '[', main_rank, '] total time for setup:', MPI.Wtime() - time_setup + +# ========= Fields initialization ========= +# - initialize velo + vort on topostr +# - penalize vorticity +# - redistribute topostr --> topofft + +time_init = MPI.Wtime() +ind = sphere.discretize(topofft) +def initFields(): + velo.initialize(topo=topo_with_ghosts) + vorti.initialize(topo=topo_with_ghosts) + op['penalVort'].apply(simu) + distr['str2fft'].apply(simu) + distr['str2fft'].wait() + +initFields() +print '[', main_rank, '] total time for init :', MPI.Wtime() - time_init + +fullseq = [] + +def run(sequence): + op['poisson'].apply(simu) # Poisson + op['correction'].apply(simu) # Velo correction + monitors['forcesPenal'].apply(simu) # Forces Heloise + distr['fft2str'].apply(simu) + distr['fft2str'].wait() + op['penalVort'].apply(simu) # Vorticity penalization + op['stretching'].apply(simu) # Stretching + monitors['forces'].apply(simu) # Forces Noca + distr['str2fft'].apply(simu) + distr['str2fft'].wait() + op['diffusion'].apply(simu) # Diffusion + distr['fft2advec'].apply(simu) + distr['fft2advec'].wait() + op['advection'].apply(simu) # Advection (scales) + distr['advec2fft'].apply(simu) + distr['advec2fft'].wait() +# monitors['writerSliceXY'].apply(simu) +# monitors['writerSliceXZ'].apply(simu) +# monitors['writerSubBox'].apply(simu) + monitors['energy'].apply(simu) # Energy/enstrophy + distr['fft2str'].apply(simu) + distr['fft2str'].wait() + op['dtAdapt'].apply(simu) # Update timestep + op['dtAdapt'].wait() + +# ==== Serialize some data of the problem to a "restart" file ==== +# def dump(filename): +# """ +# Serialize some data of the problem to file +# (only data required for a proper restart, namely fields in self.input +# and simulation). +# @param filename : prefix for output file. Real name = filename_rk_N, +# N being current process number. If None use default value from problem +# parameters (self.filename) +# """ +# if filename is not None: +# filename = filename +# filedump = filename + '_rk_' + str(main_rank) +# db = parmesPickle(filedump, mode='store') +# db.dump(simu, 'simulation') +# velo.dump(filename, mode='append') +# vorti.dump(filename, mode='append') + +# ## ====== Load some data of the problem from a "restart" file ====== +# def restart(filename): +# """ +# Load serialized data to restart from a previous state. +# self.input variables and simulation are loaded. +# @param filename : prefix for downloaded file. +# Real name = filename_rk_N, N being current process number. +# If None use default value from problem +# parameters (self.filename) +# """ +# if filename is not None: +# filename = filename +# filedump = filename + '_rk_' + str(main_rank) +# db = parmesPickle(filedump, mode='load') +# simu = db.load('simulation')[0] +# simu.start = simu.time - simu.timeStep +# ite = simu.currentIteration +# simu.initialize() +# simu.currentIteration = ite +# print 'simu', simu +# print ("load ...", filename) +# velo.load(filename) +# vorti.load(filename) +# return simu + +seq = fullseq + +simu.initialize() +#doDump = False +#doRestart = False +#dumpFreq = 5000 +#io_default={"filename":'restart'} +#dump_filename = io.Writer(params=io_default).filename +#===== Restart (if needed) ===== +# if doRestart: +# simu = restart(dump_filename) +# # Set up for monitors and redistribute +# for ope in distr.values(): +# ope.setUp() +# for monit in monitors.values(): +# monit.setUp() + +# ======= Time loop ======= +time_run = MPI.Wtime() +while not simu.isOver: + if topofft.rank == 0: + simu.printState() + run(seq) + simu.advance() +# # testdump = simu.currentIteration % dumpFreq is 0 +# # if doDump and testdump: +# # dump(dump_filename) +print '[', main_rank, '] total time for run :', MPI.Wtime() - time_run + +# ======= Finalize ======= +fftw2py.clean_fftw_solver(box.dimension) +for ope in distr.values(): + ope.finalize() +writer.finalize() +energy.finalize() -- GitLab