From 5227f5edf5d8d9628dbd045cc86f720ceaf0978a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20P=C3=A9rignon?= <franck.perignon@imag.fr> Date: Wed, 22 May 2013 15:59:35 +0000 Subject: [PATCH] Operators review (Jean-Matthieu approved ...) --- HySoP/hysop/domain/obstacle/cylinder2d.py | 4 +- HySoP/hysop/domain/obstacle/sphere.py | 8 +- HySoP/hysop/fields/continuous.py | 11 +- HySoP/hysop/operator/advection.py | 5 +- HySoP/hysop/operator/analytic.py | 1 + HySoP/hysop/operator/continuous.py | 13 +-- HySoP/hysop/operator/diffusion.py | 2 + HySoP/hysop/operator/discrete/analytic.py | 18 ++- .../operator/discrete/curlAndDiffusion_fft.py | 4 - .../hysop/operator/discrete/diffusion_fft.py | 18 +-- HySoP/hysop/operator/discrete/discrete.py | 15 ++- HySoP/hysop/operator/discrete/multiphase.py | 23 ++-- .../operator/discrete/particle_advection.py | 7 +- HySoP/hysop/operator/discrete/penalization.py | 12 +- HySoP/hysop/operator/discrete/poisson_fft.py | 9 +- .../operator/discrete/scales_advection.py | 104 ++---------------- HySoP/hysop/operator/discrete/stretching.py | 32 +++--- HySoP/hysop/operator/monitors/monitoring.py | 6 +- HySoP/hysop/operator/monitors/printer.py | 37 ++++--- HySoP/hysop/operator/multiphase.py | 2 + HySoP/hysop/operator/penalization.py | 1 + HySoP/hysop/operator/redistribute.py | 3 +- HySoP/hysop/operator/stretching.py | 4 +- HySoP/hysop/problem/problem.py | 88 ++++----------- HySoP/hysop/problem/tests/test_transport.py | 6 +- HySoP/hysop/problem/transport.py | 5 +- 26 files changed, 157 insertions(+), 281 deletions(-) diff --git a/HySoP/hysop/domain/obstacle/cylinder2d.py b/HySoP/hysop/domain/obstacle/cylinder2d.py index 5d7f8b978..dbded5d02 100644 --- a/HySoP/hysop/domain/obstacle/cylinder2d.py +++ b/HySoP/hysop/domain/obstacle/cylinder2d.py @@ -20,8 +20,8 @@ class Cylinder2D(Sphere): @param radius : sphere radius, default = 1 @param porousLayers : a list of thicknesses for successive porous layers - radius is the outside sphere radius and thicknesses are given from - outside layer to inside one. + radius is the inside sphere radius and thicknesses are given from + inside layer to outside one. @param vd : velocity of the disk (considered as a rigid body), default = 0. """ diff --git a/HySoP/hysop/domain/obstacle/sphere.py b/HySoP/hysop/domain/obstacle/sphere.py index 99fa9cb31..ae2420223 100644 --- a/HySoP/hysop/domain/obstacle/sphere.py +++ b/HySoP/hysop/domain/obstacle/sphere.py @@ -21,8 +21,8 @@ class Sphere(Obstacle): @param radius : sphere radius, default = 1 @param porousLayers : a list of thicknesses for successive porous layers - radius is the outside sphere radius and thicknesses are given from - outside layer to inside one. + radius is the inside sphere radius and thicknesses are given from + inside layer to outside one. @param vd : velocity of the sphere (considered as a rigid body), default = 0. """ @@ -89,8 +89,8 @@ class HemiSphere(Sphere): @param radius : sphere radius, default = 1 @param porousLayers : a list of thicknesses for successive porous layers - radius is the outside sphere radius and thicknesses are given from - outside layer to inside one. + radius is the inside sphere radius and thicknesses are given from + inside layer to outside one. @param vd : velocity of the sphere (considered as a rigid body), default = 0. """ diff --git a/HySoP/hysop/fields/continuous.py b/HySoP/hysop/fields/continuous.py index a5ad06085..521f79235 100644 --- a/HySoP/hysop/fields/continuous.py +++ b/HySoP/hysop/fields/continuous.py @@ -67,6 +67,8 @@ class Field(object): self.isVector = isVector ## Analytic formula. self._formula = formula + ## A list of extra parameters, used in _formula + self.extraParameters = tuple([]) @debug def discretize(self, topo): @@ -114,7 +116,7 @@ class Field(object): @param *args : see parmepy.fields """ for dF in self.discreteFields.values(): - dF.initialize(self._formula, *args) + dF.initialize(self._formula, *(args + self.extraParameters)) def value(self, *pos): """ @@ -160,6 +162,13 @@ class Field(object): else: return self.discreteFields.values()[0].norm() + def setExtraParameters(self, *args): + """ + Set values for (optional) list of extra parameters + that may be required in formula. + """ + self.extraParameters = args + if __name__ == "__main__": print __doc__ print "- Provided class : ContinuousField" diff --git a/HySoP/hysop/operator/advection.py b/HySoP/hysop/operator/advection.py index 03ff69959..c0dd4da43 100644 --- a/HySoP/hysop/operator/advection.py +++ b/HySoP/hysop/operator/advection.py @@ -1,7 +1,7 @@ """ @file advection.py -Advection of a scalar or vector field. +Advection of a field. """ from parmepy.constants import debug, np, PARMES_INDEX from parmepy.operator.continuous import Operator @@ -31,8 +31,10 @@ class Advection(Operator): v = [velocity] if isinstance(advectedFields, list): [v.append(f) for f in advectedFields] + self.output = advectedFields else: v.append(advectedFields) + self.output = [advectedFields] Operator.__init__(self, v, method) ## Transport velocity self.velocity = velocity @@ -45,6 +47,7 @@ class Advection(Operator): self.resolutions = resolutions ## Extra parameters (depend on the method) self.config = other_config + self.input = [self.velocity] @debug def setUp(self): diff --git a/HySoP/hysop/operator/analytic.py b/HySoP/hysop/operator/analytic.py index e7c23ea0b..202695b57 100644 --- a/HySoP/hysop/operator/analytic.py +++ b/HySoP/hysop/operator/analytic.py @@ -43,6 +43,7 @@ class Analytic(Operator): ## Dict of resolutions (one per variable) self.resolutions = resolutions self.config = other_config + self.output = self.variables @debug def setUp(self): diff --git a/HySoP/hysop/operator/continuous.py b/HySoP/hysop/operator/continuous.py index dd2ca52c2..9ed546a13 100644 --- a/HySoP/hysop/operator/continuous.py +++ b/HySoP/hysop/operator/continuous.py @@ -85,15 +85,14 @@ class Operator(object): self.discreteOperator.finalize() @debug - def apply(self, t=None, dt=None, ite=None): + def apply(self, simulation=None): """ - apply the operator on its variables. - @param t : Current simulation time. - @param dt : Time step - @param ite : Iteration number - @return duration of computation. + Apply this operator to its variables. + @param simulation : object that describes the simulation + parameters (time, time step, iteration number ...), see + parmepy.problem.simulation.Simulation for details. """ - return self.discreteOperator.apply(t, dt, ite) + return self.discreteOperator.apply(simulation) def printComputeTime(self): """ Time monitoring.""" diff --git a/HySoP/hysop/operator/diffusion.py b/HySoP/hysop/operator/diffusion.py index e334b65ca..2c7bffaef 100644 --- a/HySoP/hysop/operator/diffusion.py +++ b/HySoP/hysop/operator/diffusion.py @@ -44,6 +44,8 @@ class Diffusion(Operator): # The only available method at the time is fftw if method is None: self.method = 'fftw' + self.input = [self.vorticity] + self.output = [self.vorticity] @debug def setUp(self): diff --git a/HySoP/hysop/operator/discrete/analytic.py b/HySoP/hysop/operator/discrete/analytic.py index 575c9fd09..80fcc6d7a 100644 --- a/HySoP/hysop/operator/discrete/analytic.py +++ b/HySoP/hysop/operator/discrete/analytic.py @@ -1,5 +1,5 @@ """ -@file operator/discrete/analytic.py +@file analytic.py Apply user-defined formula to a set of discrete variables. """ @@ -25,21 +25,19 @@ class Analytic_D(DiscreteOperator): else: DiscreteOperator.__init__(self, [variables], method) - self.input = variables self.output = variables self.name = "analytic" - self.formula = formula + self.vformula = np.vectorize(formula) @debug - def setUp(self): - # numpy formula vectorization - self.vformula = np.vectorize(self.formula) - - @debug - def apply(self, t, dt, ite): + def apply(self, simulation): + """ + Initialize is always called with coords + current time. + Any extra parameters must be set using field.setExtraParameters. + """ self.compute_time = MPI.Wtime() for df in self.variables: - df.initialize(self.vformula, t, dt, ite) + df.initialize(self.vformula, simulation.time) for df in self.output: df.contains_data = True diff --git a/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py b/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py index e546f2f49..6bede01e0 100644 --- a/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py +++ b/HySoP/hysop/operator/discrete/curlAndDiffusion_fft.py @@ -34,10 +34,6 @@ class DiffusionFFT(DiscreteOperator): self.with_curl = with_curl self.compute_time = 0. - @debug - def setUp(self): - pass - @debug def apply(self, t=None, dt=None, ite=None): """ diff --git a/HySoP/hysop/operator/discrete/diffusion_fft.py b/HySoP/hysop/operator/discrete/diffusion_fft.py index d43d54174..0da5487b4 100644 --- a/HySoP/hysop/operator/discrete/diffusion_fft.py +++ b/HySoP/hysop/operator/discrete/diffusion_fft.py @@ -31,22 +31,16 @@ class DiffusionFFT(DiscreteOperator): raise AttributeError("Wrong problem dimension: only 2D \ and 3D cases are implemented.") # Base class initialisation - DiscreteOperator.__init__(self, [vorticity], method) + DiscreteOperator.__init__(self, [self.vorticity], method) + self.input = [self.vorticity] + self.output = [self.vorticity] @debug - def setUp(self): - pass - - @debug - def apply(self, t, dt, ite): - """ - Apply operator. - @param dt : current time step - """ + def apply(self, simulation): self.compute_time = MPI.Wtime() - if dt is None: + if simulation is None: raise ValueError("Missing dt value for diffusion computation.") - + dt = simulation.timeStep if (self.vorticity.dimension == 2): self.vorticity.data = fftw2py.solve_diffusion_2d( self.viscosity * dt, self.vorticity.data) diff --git a/HySoP/hysop/operator/discrete/discrete.py b/HySoP/hysop/operator/discrete/discrete.py index 0fb1d4d81..ff6ab109d 100644 --- a/HySoP/hysop/operator/discrete/discrete.py +++ b/HySoP/hysop/operator/discrete/discrete.py @@ -57,12 +57,21 @@ class DiscreteOperator(object): s += str(self.compute_time) print s + def setUp(self): + """ + Update the operator --> after calling this function, + the operator is ready to use. + """ + pass + @debug @abstractmethod - def apply(self, t, dt, ite): + def apply(self, simulation=None): """ - Abstract method, apply operaton on the of discrete variables of - this operator. + Apply this operator to its variables. + @param simulation : object that describes the simulation + parameters (time, time step, iteration number ...), see + parmepy.problem.simulation.Simulation for details. """ @debug diff --git a/HySoP/hysop/operator/discrete/multiphase.py b/HySoP/hysop/operator/discrete/multiphase.py index 14fbcb283..172aaf677 100644 --- a/HySoP/hysop/operator/discrete/multiphase.py +++ b/HySoP/hysop/operator/discrete/multiphase.py @@ -14,7 +14,7 @@ class Pressure_d(DiscreteOperator): """ @debug - def __init__(self, velocity, vorticity, density, method=''): + def __init__(self, velocity, vorticity, density, method=None): """ Constructor. Create the old velocity field to compute the -Dp/rho @@ -28,25 +28,16 @@ class Pressure_d(DiscreteOperator): self.vorticity = vorticity self.density = density self.compute_time = 0. + self.input = [self.velocity_new, self.vorticity, self.density] + self.output = [self.vorticity] @debug - def setUp(self): - pass - ## La topologie se recupere depuis les variables discretes - ## self.topology = self.velocity_old.topology - ## self.topology = self.velocity_new.topology - ## self.topology = self.vorticity.topology - ## self.topology = self.vorticity.density + def apply(self, simulation=None): + if simulation is None: + raise ValueError("Missing dt value for diffusion computation.") - ## self.resolution = self.topology.mesh.resolution - ## self.meshSize = self.topology.mesh.size - - @debug - def apply(self, t=None, dt=None, ite=None): - """ - Apply operator. - """ self.compute_time = time.time() + dt = simulation.timeStep result = (self.velocity_new - self.velocity_old) / dt gradU = DifferentialOperator(self.velocity_new, self.velocity_new, choice='gradV', diff --git a/HySoP/hysop/operator/discrete/particle_advection.py b/HySoP/hysop/operator/discrete/particle_advection.py index ed760bfcd..aa8b05b86 100644 --- a/HySoP/hysop/operator/discrete/particle_advection.py +++ b/HySoP/hysop/operator/discrete/particle_advection.py @@ -147,8 +147,11 @@ class ParticleAdvection(DiscreteOperator): p_adF.data[...], d) @debug - def apply(self, t=None, dt=None, ite=None): - self.numMethod(t, dt) + def apply(self, simulation=None): + if simulation is None: + raise ValueError("Missing dt value for diffusion computation.") + + self.numMethod(simulation.time, simulation.timeStep) if __name__ == "__main__": diff --git a/HySoP/hysop/operator/discrete/penalization.py b/HySoP/hysop/operator/discrete/penalization.py index eeca52502..2b8b94702 100644 --- a/HySoP/hysop/operator/discrete/penalization.py +++ b/HySoP/hysop/operator/discrete/penalization.py @@ -50,22 +50,20 @@ class Penalization_d(DiscreteOperator): for c in xrange(lsize + 1, len(cond)): self.cond[c] = cond[c] assert self.factor.size == len(self.cond) + self.input = self.output = self.variables @debug - def setUp(self): - pass - - @debug - def apply(self, t=None, dt=0.0, ite=None): + def apply(self, simulation): + if simulation is None: + raise ValueError("Missing dt value for penalization computation.") self.compute_time = MPI.Wtime() - + dt = simulation.timeStep coef = 1.0 / (1.0 + dt * self.factor) for v in self.variables: i = 0 for cond in self.cond: - #i = self.cond.index(cond) v[cond] *= coef[i] i += 1 diff --git a/HySoP/hysop/operator/discrete/poisson_fft.py b/HySoP/hysop/operator/discrete/poisson_fft.py index e3b878d93..ac679e22d 100644 --- a/HySoP/hysop/operator/discrete/poisson_fft.py +++ b/HySoP/hysop/operator/discrete/poisson_fft.py @@ -46,16 +46,9 @@ class PoissonFFT(DiscreteOperator): self.input = [self.vorticity] self.output = [self.velocity] - @debug - def setUp(self): - pass - @debug @prof - def apply(self, t, dt, ite): - """ - Apply operator. - """ + def apply(self, simulation=None): self.compute_time = MPI.Wtime() if self.case is '2D': diff --git a/HySoP/hysop/operator/discrete/scales_advection.py b/HySoP/hysop/operator/discrete/scales_advection.py index 26ba0e2f7..3c4aaa9b6 100644 --- a/HySoP/hysop/operator/discrete/scales_advection.py +++ b/HySoP/hysop/operator/discrete/scales_advection.py @@ -40,20 +40,12 @@ class ScalesAdvection(DiscreteOperator): self.compute_time = 0. @debug - def setUp(self): - pass - #self.stab_coeff = stab_coeff -# self.topology = self.velocity.topology -# self.ghosts = self.topology.ghosts -# self.resolution = self.topology.mesh.resolution -# self.dim = self.topology.dim + def apply(self, simulation=None): + if simulation is None: + raise ValueError("Missing dt value for diffusion computation.") - @debug - def apply(self, t=None, dt=None, ite=None): - """ - Apply operator. - """ self.compute_time = time.time() + dt = simulation.timeStep for adF in self.advectedFields: if isinstance(adF, VectorField): for d in xrange(adF.dimension): @@ -68,93 +60,15 @@ class ScalesAdvection(DiscreteOperator): self.velocity.data[1], self.velocity.data[2], adF.data) - # ind0a = self.ghosts[0] - # ind0b = self.resolution[0] - self.ghosts[0] - # ind1a = self.ghosts[1] - # ind1b = self.resolution[1] - self.ghosts[1] - # ind2a = self.ghosts[2] - # ind2b = self.resolution[2] - self.ghosts[2] - - # velocityNoG = [np.zeros((self.resolution - 2 * self.ghosts), - # dtype=PARMES_REAL, order=ORDER) - # for d in xrange(self.dim)] - # for i in xrange(self.dim): - # velocityNoG[i][...] = self.velocity[i][ind0a:ind0b, - # ind1a:ind1b, - # ind2a:ind2b] - # if self.advectedField.vector: - - # advecFieldNoG = [np.zeros((self.resolution - 2 * self.ghosts), - # dtype=PARMES_REAL, order=ORDER) - # for d in xrange(self.dim)] - # for i in xrange(self.dim): - # advecFieldNoG[i][...] = self.advectedField[i][ind0a:ind0b, - # ind1a:ind1b, - # ind2a:ind2b] - - # # Vector field advection - # advecFieldNoG[0][...] = \ - # scales2py.solve_advection(dt, velocityNoG[0][...], - # velocityNoG[1][...], - # velocityNoG[2][...], - # advecFieldNoG[0][...]) - # advecFieldNoG[1][...] = \ - # scales2py.solve_advection(dt, velocityNoG[0][...], - # velocityNoG[1][...], - # velocityNoG[2][...], - # advecFieldNoG[1][...]) - # advecFieldNoG[2][...] = \ - # scales2py.solve_advection(dt, velocityNoG[0][...], - # velocityNoG[1][...], - # velocityNoG[2][...], - # advecFieldNoG[2][...]) - - # for i in xrange(self.dim): - # self.advectedField[i][ind0a:ind0b, - # ind1a:ind1b, ind2a:ind2b] = \ - # advecFieldNoG[i][...] - - # # Computation of advected vector field norm --> addField : - # self.addField[ind0a:ind0b, - # ind1a:ind1b, ind2a:ind2b] = \ - # np.sqrt(advecFieldNoG[0][...] ** 2 + \ - # advecFieldNoG[1][...] ** 2 + \ - # advecFieldNoG[2][...] ** 2) - - # addFieldNoG = np.zeros((self.resolution - 2 * self.ghosts), - # dtype=PARMES_REAL, order=ORDER) - # addFieldNoG[...] = self.addField[ind0a:ind0b, - # ind1a:ind1b, - # ind2a:ind2b] - - # # Added Scalar field advection - # addFieldNoG[...] = \ - # scales2py.solve_advection(dt, velocityNoG[0][...], - # velocityNoG[1][...], - # velocityNoG[2][...], - # addFieldNoG[...]) - - # self.addField[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = \ - # addFieldNoG[...] - - # else: - # advecFieldNoG = np.zeros((self.resolution - 2 * self.ghosts), - # dtype=PARMES_REAL, order=ORDER) - # advecFieldNoG[...] = self.advectedField[ind0a:ind0b, - # ind1a:ind1b, - # ind2a:ind2b] - # # Scalar field advection - # advecFieldNoG[...] = \ - # scales2py.solve_advection(dt, velocityNoG[0][...], - # velocityNoG[1][...], - # velocityNoG[2][...], - # advecFieldNoG[...]) - # self.advectedField[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = \ - # advecFieldNoG[...] self.compute_time = time.time() - self.compute_time self.total_time += self.compute_time return self.compute_time + def finalize(self): + """ + \todo check memory deallocation in scales??? + """ + pass if __name__ == "__main__": print __doc__ diff --git a/HySoP/hysop/operator/discrete/stretching.py b/HySoP/hysop/operator/discrete/stretching.py index b7169629f..b26a9419a 100755 --- a/HySoP/hysop/operator/discrete/stretching.py +++ b/HySoP/hysop/operator/discrete/stretching.py @@ -40,10 +40,9 @@ class Stretching_d(DiscreteOperator): # ## input fields # self.input = [self.velocity, self.vorticity] self.propertyOp = propertyOp - self.input = [velocity, vorticity] + self.input = [self.velocity, self.vorticity] + self.output = [self.vorticity] - @debug - def setUp(self): self.cststretch = 0. if self.method.find('Euler') >= 0: self.num_method = Euler @@ -63,7 +62,7 @@ class Stretching_d(DiscreteOperator): self.cststretch = self.cststretch / 2. @debug - def apply(self, t=None, dt=None, ite=None): + def apply(self, simulation): """ Apply Stretching operator. @@ -79,13 +78,16 @@ class Stretching_d(DiscreteOperator): -define the function of ODEsolver as the result of the first step -integrate with the chosen method (RK4. RK2. euler) """ - self.compute_time = time.time() + if simulation is None: + raise ValueError("Missing dt value for diffusion computation.") + self.compute_time = time.time() + dt = simulation.timeStep if self.num_method is not None: - - if (self.propertyOp.find('divConservation') < 0 - and self.propertyOp.find('massConservation') < 0): - print 'No or wrong stretching operator property specified, use default divConservation' + condA = self.propertyOp.find('divConservation') < 0 + if condA and self.propertyOp.find('massConservation') < 0: + print 'No or wrong stretching operator property specified, \ + use default divConservation' self.propertyOp = 'divConservation' if self.propertyOp == 'massConservation': @@ -99,7 +101,7 @@ class Stretching_d(DiscreteOperator): choice='divWU', topology=self.velocity.topology) - else: # self.propertyOp == 'divConservation' + else: # self.propertyOp == 'divConservation' ## Space discretization of grad(u) self.stretchOp = DifferentialOperator( @@ -113,7 +115,8 @@ class Stretching_d(DiscreteOperator): print "dtAdvec", 0.5 / maxgersh[1] ## Determination of Stretching time step (stability condition) - self.ndt = self.stabilityTest(dt, maxgersh[0], self.num_method, self.cststretch) + self.ndt = self.stabilityTest(dt, maxgersh[0], + self.num_method, self.cststretch) self.dtstretch = dt / float(self.ndt) ## fct2Op @@ -124,11 +127,12 @@ class Stretching_d(DiscreteOperator): topology=self.vorticity.topology) ## Time integration + t = simulation.time for i in range(self.ndt): methodInt = self.num_method(self.function) - self.vorticity.data = methodInt(self.function.apply, - t, self.dtstretch, - self.vorticity.data) + self.vorticity.data[...] = methodInt(self.function.apply, + t, self.dtstretch, + self.vorticity.data) # print 'norm omega', LA.norm(self.vorticity.data) self.compute_time = time.time() - self.compute_time diff --git a/HySoP/hysop/operator/monitors/monitoring.py b/HySoP/hysop/operator/monitors/monitoring.py index 750913167..35d7a1870 100644 --- a/HySoP/hysop/operator/monitors/monitoring.py +++ b/HySoP/hysop/operator/monitors/monitoring.py @@ -1,19 +1,21 @@ """ @file monitoring.py +Global interface for monitors. """ from abc import ABCMeta, abstractmethod from parmepy.operator.continuous import Operator class Monitoring(Operator): - """Abstract description a monitor. """ + """Abstract interface to monitoring operators.""" __metaclass__ = ABCMeta @abstractmethod def __init__(self, variables, frequency): """ Constructor - @param dimension integer : domain dimension. + @param variables : list of fields to monitor + @param frequency : output rate """ Operator.__init__(self, variables) ## Monitor frequency diff --git a/HySoP/hysop/operator/monitors/printer.py b/HySoP/hysop/operator/monitors/printer.py index 524a908ce..89ccb20e8 100644 --- a/HySoP/hysop/operator/monitors/printer.py +++ b/HySoP/hysop/operator/monitors/printer.py @@ -7,7 +7,7 @@ from parmepy.constants import np, S_DIR, PARMES_REAL from parmepy.operator.monitors.monitoring import Monitoring import evtk.hl as evtk from parmepy.mpi import main_rank -import time +from parmepy.mpi import MPI class Printer(Monitoring): @@ -17,18 +17,19 @@ class Printer(Monitoring): Performs outputs in VTK images. """ - def __init__(self, frequency=0, fields=[], outputPrefix='./out_'): + def __init__(self, frequency=0, fields=[], prefix='./out_', ext='.vtk'): """ Create a results printer for given fields, filename prefix (relative path) and an output frequency. - @param fields : Fields to output. - @param frequency : output file producing frequency. - @param outputPrefix : file name prefix, contains relative path. + @param fields : list of variables to export. + @param frequency : output rate (output every freq iteration) + @param prefix : output file name prefix. + @param ext : output file extension, default=.vtk. """ Monitoring.__init__(self, fields, frequency) - ## Filename prefix - self.outputPrefix = outputPrefix + str(main_rank) + ## output file name prefix + self.prefix = prefix + str(main_rank) ## Method to collect data in case of distributed data self.get_data_method = None if self.freq != 0: @@ -38,7 +39,8 @@ class Printer(Monitoring): self.step = self._passStep ## Printing compute time self.compute_time = 0. - self.call_number = 0 + ## Internal counter + self._call_number = 0 def apply(self, t=None, dt=None, ite=None): self.step(ite) @@ -78,21 +80,20 @@ class Printer(Monitoring): def _printStep(self, ite): """ - Printer core method. - - Write fields data to file on necessary.\n - VTK images are writed. If fails, classical ascii output is performed. + Try to write data into VTK files. + If fails, turn to classical ascii output. """ - t = time.time() + t = MPI.Wtime() if (ite % self.freq) == 0: - self.call_number += 1 - print "== IO" + self._call_number += 1 + # Transfer from GPU to CPU if required for f in self.variables: for df in f.discreteFields.values(): try: df.toHost() except AttributeError: pass + # Set output file name filename = self.outputPrefix + "results_{0:05d}.dat".format(ite) print "Print file : " + filename ## VTK output \todo: Need fix in 2D, getting an IOError. @@ -149,10 +150,10 @@ class Printer(Monitoring): def printComputeTime(self): self.time_info[0] = "\"IO\" " self.time_info[1] = str(self.compute_time) + " " - print "IO total time : ", self.compute_time, self.call_number + print "IO total time : ", self.compute_time, self._call_number if __name__ == "__main__": print __doc__ - print "- Provided class : " + providedClass - print eval(providedClass).__doc__ + print "- Provided class : " + Printer + print Printer.__doc__ diff --git a/HySoP/hysop/operator/multiphase.py b/HySoP/hysop/operator/multiphase.py index 3d896572d..82e38078d 100644 --- a/HySoP/hysop/operator/multiphase.py +++ b/HySoP/hysop/operator/multiphase.py @@ -32,6 +32,8 @@ class Pressure(Operator): self.viscosity = viscosity self.resolutions = resolutions self.config = other_config + self.input = [self.velocity, self.vorticity, self.density] + self.output = [self.vorticity] @debug def setUp(self): diff --git a/HySoP/hysop/operator/penalization.py b/HySoP/hysop/operator/penalization.py index a25ab4fb6..a1da8d482 100644 --- a/HySoP/hysop/operator/penalization.py +++ b/HySoP/hysop/operator/penalization.py @@ -52,6 +52,7 @@ class Penalization(Operator): for resol in resolutions.values(): assert resol == self.resolution self.config = other_config + self.input = self.output = self.variables @debug def setUp(self): diff --git a/HySoP/hysop/operator/redistribute.py b/HySoP/hysop/operator/redistribute.py index 3cee0259a..33a415591 100644 --- a/HySoP/hysop/operator/redistribute.py +++ b/HySoP/hysop/operator/redistribute.py @@ -62,6 +62,7 @@ class Redistribute(Operator): assert v in opFrom.variables and v in opTo.variables, \ 'Redistribute error : one of the variable is not present\ in both source and target operator.' + self.input = self.output = self.variables @debug def setUp(self): @@ -81,7 +82,7 @@ class Redistribute(Operator): self._isUpToDate = True - def apply(self): + def apply(self, simulation=None): """ Proceed with data redistribution from opFrom to opTo """ diff --git a/HySoP/hysop/operator/stretching.py b/HySoP/hysop/operator/stretching.py index dd3cd807c..d7d060577 100755 --- a/HySoP/hysop/operator/stretching.py +++ b/HySoP/hysop/operator/stretching.py @@ -15,6 +15,7 @@ import numpy as np class Stretching(Operator): """ Stretching operator representation + \todo write latex formulas """ @debug @@ -36,6 +37,8 @@ class Stretching(Operator): self.vorticity = vorticity self.resolutions = resolutions self.config = other_config + self.input = [self.velocity, self.vorticity] + self.output = [self.vorticity] @debug def setUp(self): @@ -51,7 +54,6 @@ class Stretching(Operator): space : (FD_order2, FD_order4, ..) default : FD_order4 and time : (Euler, RK, ..) default : RK3 """ - Operator.setUp(self) print '================ Stretching scheme =====================' print ' Space discretization and integr. scheme:', self.method print '========================================================' diff --git a/HySoP/hysop/problem/problem.py b/HySoP/hysop/problem/problem.py index ca3593b82..d5d961c63 100644 --- a/HySoP/hysop/problem/problem.py +++ b/HySoP/hysop/problem/problem.py @@ -1,9 +1,8 @@ """ -@package parmepy.problem.problem +@file problem.py Complete problem description. """ -from abc import ABCMeta, abstractmethod from parmepy.constants import debug from parmepy import __VERBOSE__ from parmepy.operator.monitors.monitoring import Monitoring @@ -25,19 +24,18 @@ class Problem(object): OpenGLRendering object), The loop over time-steps is passed to Qt4 """ - __metaclass__ = ABCMeta - @debug def __new__(cls, *args, **kw): return object.__new__(cls, *args, **kw) @debug - @abstractmethod - def __init__(self, operators, monitors=[]): + def __init__(self, operators, simulation, monitors=[]): """ Create a transport problem instance. @param operators : list of operators. + @param simulation : a parmepy.simulation.Simulation object + to describe simulation parameters. @param monitors : list of monitors. """ ## Problem operators @@ -45,7 +43,7 @@ class Problem(object): for m in monitors: self.operators.append(m) ## Computes time step and manage iterations - self.timer = None + self.simulation = simulation ## Timings informations self.time_info = ["", ""] self.domain = self.operators[0].variables[0].domain @@ -54,13 +52,14 @@ class Problem(object): if not self.domain is v.domain: raise ValueError("Problem must have only one " + "domain for variables.") + ## A list of variables that must be initialized before + ## any call to op.apply() + self.input = [] @debug - def setUp(self, t_end, dt): + def setUp(self): """ Set solver. - @param t_end : duration of the simulation. - @param dt : simulation time step. """ for op in self.operators: if not isinstance(op, Monitoring): @@ -72,16 +71,13 @@ class Problem(object): if isinstance(op, Redistribute): op.setUp() - self.timer = Timer(t_end, dt) if __VERBOSE__: print "==== Variables initialization ====" - var_list = [] - for op in self.operators: - for v in op.variables: - var_list.append(v) - # List of unique elements (initialize once each variable) - for v in set(var_list): + + # \todo find a way to set self.input properly. + for v in self.input: v.initialize() + if __VERBOSE__: print "====" for op in self.operators: @@ -105,19 +101,18 @@ class Problem(object): print "\n\n Start solving ..." for op in self.operators: if isinstance(op, Monitoring): - op.apply(self.timer.t, self.timer.dt, ite=0) + op.apply(self.simulation) try: ## Pass the main loop to the OpenGL viewer if not self.glRenderer is None: self.glRenderer.startMainLoop() except AttributeError: - while not self.timer.end: - if (self.domain.topologies.values()[0].rank == 0): - print "==== Iteration : {0:3d} t={1:6.3f} ====".format( - self.timer.ite, self.timer.t + self.timer.dt) + while not self.simulation.isOver: + self.simulation.printState() for op in self.operators: - op.apply(self.timer.t, self.timer.dt, self.timer.ite) - self.timer.step() + op.apply(self.simulation) + self.simulation.advance() + print "\n\n End solving\n" print "=== Timings ===" if (self.domain.topologies.values()[0].rank == 0): @@ -160,50 +155,7 @@ class Problem(object): return s - -class Timer: - """ - Manage time steps and simulation end. - - """ - - def __init__(self, t_end, dt, t_init=0.): - """ - Creates a Timer. - - @param t_end : Simulation final time. - @param dt : Time step. - @param t_init : Simulation starting time. - """ - ## Simulation final time - self.t_end = t_end - ## Simulation time step - self.dt = dt - ## Simulation current time - self.t = t_init - ## Is simulation is terminated - self.end = False - ## Iteration counter - self.ite = 1 - ## Max iteration - self.ite_max = int(round(self.t_end / self.dt)) - - def step(self): - """ - Update current time. - """ - if self.ite < self.ite_max: - self.ite += 1 - self.t += self.dt - else: - self.end = True - - def __str__(self): - s = "Timer (DiscreteOperator). " - return s - if __name__ == "__main__": print __doc__ - print "- Provided class : problem, Timer" + print "- Provided class : problem" print Problem.__doc__ - print Timer.__doc__ diff --git a/HySoP/hysop/problem/tests/test_transport.py b/HySoP/hysop/problem/tests/test_transport.py index b0df7fe42..cb4885251 100644 --- a/HySoP/hysop/problem/tests/test_transport.py +++ b/HySoP/hysop/problem/tests/test_transport.py @@ -7,6 +7,7 @@ from parmepy.domain.box import Box from parmepy.fields.continuous import Field from parmepy.operator.advection import Advection from parmepy.problem.transport import TransportProblem +from parmepy.problem.simulation import Simulation def cosinus_product_2D(x, y): @@ -54,8 +55,9 @@ def assert_nullVelocity(dim, boxLength, boxMin, nbElem, finalTime, timeStep, resolutions={velo: nbElem, scal: nbElem}, ) - pb = TransportProblem([advec]) - pb.setUp(finalTime, timeStep) + simu = Simulation(tend=finalTime, nbiter=1) + pb = TransportProblem([advec], simu) + pb.setUp() initial_scalar = scal.discreteFields.values()[0].data.copy() pb.solve() return np.allclose(initial_scalar, scal.discreteFields.values()[0].data, diff --git a/HySoP/hysop/problem/transport.py b/HySoP/hysop/problem/transport.py index 1eda4cbd7..3a1f8cdff 100644 --- a/HySoP/hysop/problem/transport.py +++ b/HySoP/hysop/problem/transport.py @@ -10,8 +10,8 @@ class TransportProblem(Problem): """ Transport problem description. """ - def __init__(self, operators, monitors=[]): - Problem.__init__(self, operators, monitors) + def __init__(self, operators, simulation, monitors=[]): + Problem.__init__(self, operators, simulation, monitors) self.advection, self.velocity = None, None for op in self.operators: if isinstance(op, Advection): @@ -20,4 +20,3 @@ class TransportProblem(Problem): self.velocity = op if self.advection is None: raise ValueError("Transport problem with no Advection operator") - -- GitLab