From 9578a1e3168c32fe072ec977eb0d3f99a07ba700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20P=C3=A9rignon?= <franck.perignon@imag.fr> Date: Fri, 31 Jan 2014 13:33:56 +0000 Subject: [PATCH] Fix hdf5 bug + file output in compute_forces --- .../hysop/operator/monitors/compute_forces.py | 54 ++++++++++++++++++- HySoP/hysop/operator/monitors/printer.py | 37 ++++++++----- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/HySoP/hysop/operator/monitors/compute_forces.py b/HySoP/hysop/operator/monitors/compute_forces.py index 28fd33b9a..da84c6436 100644 --- a/HySoP/hysop/operator/monitors/compute_forces.py +++ b/HySoP/hysop/operator/monitors/compute_forces.py @@ -13,6 +13,8 @@ from parmepy.operator.monitors.monitoring import Monitoring from parmepy.mpi import main_comm, main_rank, MPI from parmepy.tools.timers import timed_function import parmepy.tools.numpywrappers as npw +import scitools.filetable as ft +import os class DragAndLift(Monitoring): @@ -23,14 +25,18 @@ class DragAndLift(Monitoring): Integral inside the obstacle is not taken into account. """ def __init__(self, velocity, vorticity, topo, volumeOfControl, - obstacles=None, frequency=1): + obstacles=None, frequency=1, filename=None, safeOutput=None): """ @param velocity field @param vorticity field@ @param the topology on which forces will be computed @param a volume of control (parmepy.domain.obstacle.controlBox.ControlBox object) + @param obstacles a list of parmepy.domain.obstacles inside + the box @param frequency : output rate + @param filename output file name. Default is None ==> no output. + Full or relative path. """ Monitoring.__init__(self, [velocity, vorticity], topo, frequency) self.velocity = velocity @@ -71,6 +77,41 @@ class DragAndLift(Monitoring): self.vd = None # discrete vorticity field self.wd = None + # Output file + if filename is None: + self._writeOuput = False + self.filename = None + else: + self._writeOuput = True + self.filename = filename + if (self.topo.rank == 0): + # Create output dir if required + d = os.path.dirname(self.filename) + if not os.path.exists(d): + os.makedirs(d) + if safeOutput is None: + ## Defines how often + ## output file is written : + ## True --> open/close file everytime + ## data are written. + ## False --> open at init and close + ## during finalize. Cost less but if simu + ## crashes, data are lost. + self.safeOutput = True + self._writeFile = self._fullwrite + else: + self.safeOutput = False + self._writeFile = self._partialwrite + + self._file = open(self.filename, 'w') + + def _fullwrite(self, data): + self._file = open(self.filename, 'a') + ft.write(self._file, data) + self._file.close() + + def _partialwrite(self, data): + ft.write(self._file, data) def _mpi_allsum(self): """ @@ -113,6 +154,7 @@ class DragAndLift(Monitoring): assert simulation is not None,\ "Simulation parameter is required for DragAndLift apply." dt = simulation.timeStep + ite = simulation.currentIteration # Synchro of ghost points is required for fd schemes self._synchronize(self.vd.data + self.wd.data) @@ -138,6 +180,13 @@ class DragAndLift(Monitoring): # Reduce results over all MPI process in topo self.mpi_sum() + # Print results, if required + if self._writeOuput and self.topo.rank == 0 and (ite % self.freq) == 0: + dataout = npw.zeros((1,4)) + dataout[0,0] = simulation.time + dataout[0,1:] = self.force + self._writeFile(dataout) + return self.force def _integrateOnSurface(self, surf, res): @@ -260,6 +309,9 @@ class DragAndLift(Monitoring): res *= self._dvol return res + def finalize(self): + if not self.safeOutput: + self._file.close() class Forces(Monitoring): """ diff --git a/HySoP/hysop/operator/monitors/printer.py b/HySoP/hysop/operator/monitors/printer.py index 70b2cbc83..0549e6811 100644 --- a/HySoP/hysop/operator/monitors/printer.py +++ b/HySoP/hysop/operator/monitors/printer.py @@ -3,7 +3,7 @@ Classes for handling ouputs. """ -from parmepy.constants import np, S_DIR, PARMES_REAL, debug, VTK, HDF5, DATA +from parmepy.constants import np, S_DIR, debug, VTK, HDF5, DATA from parmepy.operator.monitors.monitoring import Monitoring import parmepy.tools.numpywrappers as npw import os @@ -116,11 +116,9 @@ class Printer(Monitoring): else: name = df.name if len(df.data[d].shape) == 2: - res[name] = np.expand_dims( - df.data[d], axis=2).astype(PARMES_REAL) + res[name] = npw.realarray(df.data[d][:, :, np.newaxis]) else: - res[name] = \ - df.data[d].astype(PARMES_REAL) + res[name] = npw.realarray(df.data[d]) return res def set_get_data_method(self, method): @@ -174,6 +172,7 @@ class Printer(Monitoring): spacing[:dim] = [self.topo.mesh.space_step[i] for i in xrange(dim)] evtk.imageToVTK(filename, origin=orig, spacing=spacing, pointData=self._build_vtk_dict()) + elif self.formattype == HDF5: filename = self.prefix + str(self.topo.size) filename += "procs_iter_{0:03d}".format(ite) + '.h5' @@ -194,8 +193,10 @@ class Printer(Monitoring): g_start = self.topo.mesh.global_start g_end = self.topo.mesh.global_end + 1 - sl = tuple([slice(g_start[i], g_end[i]) - for i in xrange(self.domain.dimension)]) + sl = [slice(g_start[i], g_end[i]) + for i in xrange(self.domain.dimension)] + sl.reverse() + sl = tuple(sl) datasetNames = [] for field in self.variables: df = field.discreteFields[self.topo] @@ -203,14 +204,16 @@ class Printer(Monitoring): # creating datasets for the vector field currentName = df.name + S_DIR[d] datasetNames.append(currentName) + res = list(self.topo.globalMeshResolution - 1) + res.reverse() ds = f.create_dataset(currentName, - self.topo.globalMeshResolution - 1, + res, dtype=np.float64, compression=compression) # In parallel, each proc must write in the proper part # Of the dataset (of site global resolution) - ds[sl] = np.asarray(df.data[d][self.topo.mesh.iCompute], - dtype=np.float64) + ds[sl] = \ + npw.realarray(df.data[d][self.topo.mesh.iCompute].T) f.close() if self.topo.rank == 0: @@ -316,15 +319,21 @@ def _TemporalGridXMF(topo, datasetNames, ite, t, filename): g += " <Time Value=\"{0}\" />\n".format(t) g += " <Topology TopologyType=\"" + str(topoType) + "\"" g += " NumberOfElements=\"" - g += _listFormat(topo.globalMeshResolution - 1) + " \"/>\n" + res = list(topo.globalMeshResolution - 1) + res.reverse() + g += _listFormat(res) + " \"/>\n" g += " <Geometry GeometryType=\"" + geoType + "\">\n" g += " <DataItem Dimensions=\"" + str(topo.mesh.dim) + " \"" g += " NumberType=\"Float\" Precision=\"4\" Format=\"XML\">\n" - g += " " + _listFormat(topo.domain.origin) + "\n" + ori = list(topo.domain.origin) + ori.reverse() + g += " " + _listFormat(ori) + "\n" g += " </DataItem>\n" g += " <DataItem Dimensions=\"" + str(topo.mesh.dim) + " \"" g += " NumberType=\"Float\" Precision=\"4\" Format=\"XML\">\n" - g += " " + _listFormat(topo.mesh.space_step) + "\n" + step = list(topo.mesh.space_step) + step.reverse() + g += " " + _listFormat(step) + "\n" g += " </DataItem>\n" g += " </Geometry>\n" for name in datasetNames: @@ -332,7 +341,7 @@ def _TemporalGridXMF(topo, datasetNames, ite, t, filename): g += name + "\"" g += " AttributeType=\"Scalar\" Center=\"Node\">\n" g += " <DataItem Dimensions=\"" - g += _listFormat(topo.globalMeshResolution - 1) + " \"" + g += _listFormat(res) + " \"" g += " NumberType=\"Float\" Precision=\"8\" Format=\"HDF\"" g += " Compression=\"Raw\">\n" # g += " " + filename.split('/')[-1] -- GitLab