diff --git a/hysop/numerics/tests/test_odesolvers.py b/hysop/numerics/tests/test_odesolvers.py index b75b58418116b2d85df91718fbd0260984050f48..48efed05c4cc525b9c63f60b8fbc03271adcc834 100755 --- a/hysop/numerics/tests/test_odesolvers.py +++ b/hysop/numerics/tests/test_odesolvers.py @@ -87,8 +87,8 @@ def integrate_3d(integ, nb_steps): npw.zeros(local_res_3d)] # work = None i = 1 - xref = local_res_3d[0] // 3. - yref = local_res_3d[1] // 2.4 + xref = local_res_3d[0] // 3 + yref = local_res_3d[1] // 2 zref = local_res_3d[2] // 5 ref = npw.zeros((nb_steps, 4)) ref[0, 1] = y[0][xref, yref, zref] @@ -112,30 +112,43 @@ def integrate_3d(integ, nb_steps): def run_integ(integrator, order): + """apply 'integrator' (== Euler, RK3 ...) + and check error according to input order. 1D case + """ nb_steps = 100 wk_prop = integrator.get_work_properties(1, topo)['rwork'] work = [] for shape in wk_prop: work.append(npw.zeros(shape)) - dt, err = integrate(integrator(1, topo, f=rhs, rwork=work), nb_steps) + dt, err = integrate(integrator(nb_components=1, topo=topo, + f=rhs, rwork=work), nb_steps) assert err < dt ** order def run_integ_3d(integrator, order): + """apply 'integrator' (== Euler, RK3 ...) + and check error according to input order. 3D case. + + """ nb_steps = 50 wk_prop = integrator.get_work_properties(3, topo3d)['rwork'] work = [] for shape in wk_prop: work.append(npw.zeros(shape)) - dt, err = integrate_3d(integrator(3, topo3d, f=rhs3d, rwork=work), + dt, err = integrate_3d(integrator(nb_components=3, topo=topo3d, + f=rhs3d, rwork=work), nb_steps) for e in err: assert e < dt ** order def run_integ_3d_no_work(integrator, order): + """apply 'integrator' (== Euler, RK3 ...) + and check error according to input order. 3D case. + """ nb_steps = 50 - dt, err = integrate_3d(integrator(3, topo3d, f=rhs3d), nb_steps) + dt, err = integrate_3d(integrator(nb_components=3, topo=topo3d, + f=rhs3d), nb_steps) for e in err: assert e < dt ** order @@ -177,6 +190,7 @@ def test_rk4_3d(): def test_user_defined_common_workspace(): + """One work space for all integrators""" integrators = {Euler: 1, RK2: 2, RK3: 3, RK4: 4} nb_steps = 50 wk_prop = {} @@ -184,7 +198,7 @@ def test_user_defined_common_workspace(): wk_prop[integ] = integ.get_work_properties(3, topo3d)['rwork'] work = WorkSpaceTools.allocate_common_workspaces(wk_prop.values()) for integ in integrators: - dt, err = integrate_3d(integ(3, topo3d, rhs3d, work), nb_steps) + dt, err = integrate_3d(integ(nb_components=3, topo=topo3d, + f=rhs3d, rwork=work), nb_steps) for e in err: assert e < dt ** integrators[integ] - diff --git a/hysop/operator/discrete/poisson_fft.py b/hysop/operator/discrete/poisson_fft.py index 3027058fd38e52f41f047fc9b46a61bdfe3ac1d5..c26dfb106163d04e8fba4ea1770f0f5f48abaac7 100644 --- a/hysop/operator/discrete/poisson_fft.py +++ b/hysop/operator/discrete/poisson_fft.py @@ -13,7 +13,6 @@ if __FFTW_ENABLED__: from hysop.f2hysop import fftw2py - class PoissonFFT(DiscreteOperator): """ Discretized Poisson operator based on FFTW. diff --git a/hysop/operator/discrete/spectrum.py b/hysop/operator/discrete/spectrum.py index defda637093bb1f59baf41de513731f898a10fb9..2bc03cbd5743b17753b18d8c1d3717523564baf7 100755 --- a/hysop/operator/discrete/spectrum.py +++ b/hysop/operator/discrete/spectrum.py @@ -1,12 +1,6 @@ # -*- coding: utf-8 -*- +"""Discrete Spectrum operator using FFTW """ -@file spectrum.py -Discrete Spectrum operator using FFTW (fortran) -""" -try: - from hysop.f2hysop import fftw2py -except ImportError: - from hysop.fakef2py import fftw2py from hysop.operator.discrete.discrete import DiscreteOperator from hysop.constants import debug, np, HYSOP_MPI_REAL from hysop.tools.profiler import profile @@ -14,22 +8,28 @@ from hysop.tools.io_utils import IO import hysop.tools.numpywrappers as npw from hysop.mpi import MPI import os +from hysop import __FFTW_ENABLED__ +if __FFTW_ENABLED__: + from hysop.f2hysop import fftw2py -class FFTSpectrum(DiscreteOperator): - """ - Discretized Spectrum operator based on FFTW. +class FFTSpectrum(DiscreteOperator): + """Discretized Spectrum operator based on FFTW. """ @debug - def __init__(self, field, prefix=None, **kwds): + def __init__(self, field, **kwds): """ - Constructor. - @param[in] vorticity : field to compute. + + Parameters + ---------- + field: :class:`~hysop.fields.discrete.DiscreteField` + the input field for which spectrum will be computed """ # Discretisation of the input field self.field = field - + msg = 'Spectrum error: implemented only for 3D problems.' + assert self.field.dimension == 3, msg if self.field.nb_components > 1: raise AttributeError("Vector case not yet implemented.") # Base class initialisation @@ -41,44 +41,32 @@ class FFTSpectrum(DiscreteOperator): self._tmp = npw.zeros(((l - 1) / 2, )) self._kx = npw.zeros(((l - 1) / 2, )) self.res = npw.zeros(((l - 1) / 2, )) - self._prefix = "spectrum" if prefix is None else prefix - IO.check_dir(os.path.join(IO.default_path(), - self._prefix + "_00000.dat")) @debug @profile def apply(self, simulation=None): assert simulation is not None, \ - "Missing dt value for diffusion computation." + "Missing simulation parameter." ite = simulation.current_iteration ghosts = self.field.topology.ghosts() - if self.field.dimension == 3: - fftw2py.spectrum_3d(self.field.data[0], - self._tmp, self._kx, - ghosts, np.min(self.domain.length)) - if self.field.topology.size == 1: - self.res[...] = self._tmp - else: - self.field.topology.comm.Reduce( - [self._tmp, self.res.shape[0], HYSOP_MPI_REAL], - [self.res, self.res.shape[0], HYSOP_MPI_REAL], - op=MPI.SUM, root=0) - if self.field.topology.rank == 0: - _file = open(os.path.join( - IO.default_path(), - self._prefix + "_{0:05d}.dat".format(ite)), 'w') - for i in xrange(self.res.shape[0]): - _file.write("{0} {1}\n".format( - self._kx[i], self.res[i])) - _file.close() + fftw2py.spectrum_3d(self.field.data[0], + self._tmp, self._kx, + ghosts, np.min(self.domain.length)) + if self.field.topology.size == 1: + self.res[...] = self._tmp else: - raise ValueError("invalid problem dimension") + self.field.topology.comm.Reduce( + [self._tmp, self.res.shape[0], HYSOP_MPI_REAL], + [self.res, self.res.shape[0], HYSOP_MPI_REAL], + op=MPI.SUM, root=0) + + if self._writer is not None and self._writer.do_write(ite): + nbc = self.res.shape[0] + self._writer.buffer[0, 0:nbc] = self._kx + self._writer.buffer[0, nbc:] = self.res + self._writer.write() def finalize(self): - """ - Clean memory (fftw plans and so on) + """Clean memory (fftw plans and so on) """ pass - # TODO : fix bug that occurs when several finalize - # of fft operators are called. - # fftw2py.clean_fftw_solver(self.vorticity.dimension) diff --git a/hysop/operator/spectrum.py b/hysop/operator/spectrum.py index 1b4f5c1b05df6221985040e76850cb880dc845a6..9d244a5590ec7312b914eb1d9d707bf94797a66e 100644 --- a/hysop/operator/spectrum.py +++ b/hysop/operator/spectrum.py @@ -1,5 +1,4 @@ -""" -@file spectrum.py +"""Compute the spectrum of a field (fftw based) """ from hysop.operator.computational import Computational from hysop.operator.discrete.spectrum import FFTSpectrum @@ -12,15 +11,17 @@ class Spectrum(Computational): Fourier spectrum computation of a scalar field. """ - def __init__(self, field, prefix=None, **kwds): + def __init__(self, field, **kwds): """ - Constructor for Spectrum operator - @param[in] field : field to compute + + Parameters + ---------- + field: :class:`~hysop.fields.continuous.Field` + the input field for which spectrum will be computed """ super(Spectrum, self).__init__(variables=[field], **kwds) self.field = field self.input = [field] - self._prefix = prefix def discretize(self): super(Spectrum, self)._fftw_discretize() @@ -29,6 +30,11 @@ class Spectrum(Computational): @opsetup def setup(self, rwork=None, iwork=None): self.discrete_op = FFTSpectrum(self.discreteFields[self.field], - method=self.method, - prefix=self._prefix) + method=self.method) + nbc = self.discrete_op.res.size + self._set_io('spectrum', (1, 2 * nbc)) + self.discrete_op.set_writer(self._writer) self._is_uptodate = True + + def get_work_properties(self): + return {'rwork': None, 'iwork': None} diff --git a/hysop/operator/tests/test_differential.py b/hysop/operator/tests/test_differential.py index 2a9c983dcea199c5355c746ba0cd6ace9d16d279..f5520a4dd46cd405d9719a902f8936d22d40d702 100755 --- a/hysop/operator/tests/test_differential.py +++ b/hysop/operator/tests/test_differential.py @@ -134,9 +134,10 @@ def call_op(class_name, ref_formula, topo, use_work=False, if use_work: work_prop = op.get_work_properties()['rwork'] work = [] - for l in xrange(len(work_prop)): - shape = work_prop[l] - work.append(npw.zeros(shape)) + if work_prop is not None: + for l in xrange(len(work_prop)): + shape = work_prop[l] + work.append(npw.zeros(shape)) op.setup(rwork=work) check(op, ref_formula, topo, op_dim, order) diff --git a/hysop/operator/tests/test_spectrum.py b/hysop/operator/tests/test_spectrum.py index 7152e3f65633617b9937967645b80468e6ea26ed..e2404022e8f9f0f7117e1ef3c0cbdfa4492a63d4 100755 --- a/hysop/operator/tests/test_spectrum.py +++ b/hysop/operator/tests/test_spectrum.py @@ -1,23 +1,28 @@ +"""Test fftw spectrum computation +""" from hysop.domain.box import Box from hysop.fields.continuous import Field from hysop.operator.spectrum import Spectrum from hysop.tools.parameters import Discretization from hysop.problem.simulation import Simulation -from hysop.operator.hdf_io import HDF_Writer +from hysop import testsenv import numpy as np -from hysop.tools.io_utils import IO pi = np.pi sin = np.sin cos = np.cos def computeScal(res, x, y, z, t): - res[0][...] = z * sin((3*pi*x)*(2*pi*y)) + """test function, scalar input, 3D""" + res[0][...] = z * sin((3 * pi * x) * (2 * pi * y)) return res +@testsenv.fftw_failed def test_spectrum(): - dom = Box(origin=[0., 0., 0.], length=[1., 1., 1.]) + """build/apply spectrum op + """ + dom = Box() field = Field(domain=dom, name='Field', is_vector=False, formula=computeScal) d3D = Discretization([257, 257, 257])