diff --git a/python/tamaas/dumpers/_helper.py b/python/tamaas/dumpers/_helper.py index 6568b85..2b57abc 100644 --- a/python/tamaas/dumpers/_helper.py +++ b/python/tamaas/dumpers/_helper.py @@ -1,33 +1,90 @@ from .. import ModelDumper import numpy as np +import os -__all__ = ["makePeriodic", "makeTractionPeriodic"] +__all__ = ["makePeriodic", "makeTractionPeriodic", + "step_dump", "directory_dump"] def makePeriodic(data): data = np.append(data, np.expand_dims(data[:, 0, ...], axis=1), axis=1) data = np.append(data, np.expand_dims(data[:, :, 0, ...], axis=2), axis=2) return data def makeTractionPeriodic(data): data = np.append(data, np.expand_dims(data[0, ...], axis=0), axis=0) data = np.append(data, np.expand_dims(data[:, 0, ...], axis=1), axis=1) return data class FieldDumper(ModelDumper): """Abstract dumper for python classes using fields""" def __init__(self, basename, default_fields, *fields): super().__init__() self.basename = basename if len(fields): self.fields = fields else: self.fields = default_fields self.make_periodic = {field: makePeriodic for field in self.fields if field != 'traction'} self.make_periodic['traction'] = makeTractionPeriodic + + +def step_dump(cls): + """ + Decorator for dumper with counter for steps + """ + orig_init = cls.__init__ + orig_dump = cls.dump + + def __init__(obj, *args, **kwargs): + orig_init(obj, *args, **kwargs) + obj.count = 0 + + def postfix(obj): + return "_{:04d}".format(obj.count) + + def dump(obj, *args, **kwargs): + orig_dump(obj, *args, **kwargs) + obj.count += 1 + + cls.__init__ = __init__ + cls.dump = dump + cls.postfix = postfix + + return cls + + +class directory_dump: + """ + Decorator for dumper in a directory + """ + + def __init__(self, directory=""): + self.directory = directory + + def __call__(self, cls): + directory = self.directory + orig_init = cls.__init__ + + def __init__(obj, *args, **kwargs): + orig_init(obj, *args, **kwargs) + + if not os.path.exists(directory): + os.mkdir(directory) + + if not os.path.isdir(directory): + raise Exception('{} is not a directory'.format(directory)) + + def dirname(obj): + return directory + + cls.__init__ = __init__ + cls.dirname = dirname + + return cls diff --git a/python/tamaas/dumpers/numpy_dumper.py b/python/tamaas/dumpers/numpy_dumper.py index 0d16223..0df8618 100644 --- a/python/tamaas/dumpers/numpy_dumper.py +++ b/python/tamaas/dumpers/numpy_dumper.py @@ -1,56 +1,53 @@ """ @author Lucas Frérot @section LICENSE Copyright (©) 2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) Tamaas is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Tamaas is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Tamaas. If not, see . """ -from ._helper import FieldDumper +from ._helper import FieldDumper, step_dump, directory_dump import os import numpy as np __all__ = ['NumpyDumper'] +@directory_dump('numpys') +@step_dump class NumpyDumper(FieldDumper): """Dumper to compressed numpy files""" def __init__(self, basename, *fields): default_fields = ['traction', 'displacement', 'stress', 'plastic_strain'] super().__init__(basename, default_fields, *fields) - if not os.path.exists('numpys'): - os.mkdir('numpys') - - self.count = 0 - def dump(self, model): dump_fields = { field: self.make_periodic[field](model.getField(field)) for field in self.fields } - np.savez_compressed('numpys/{}_{:04d}.npz'.format(self.basename, - self.count), - **dump_fields) + np.savez_compressed(self.file_path(), **dump_fields) - self.count += 1 + def file_path(self): + return os.path.join(self.dirname(), "{}{}.npz".format(self.basename, + self.postfix())) diff --git a/python/tamaas/dumpers/uvw_dumper.py b/python/tamaas/dumpers/uvw_dumper.py index 646c51f..9a7dc20 100644 --- a/python/tamaas/dumpers/uvw_dumper.py +++ b/python/tamaas/dumpers/uvw_dumper.py @@ -1,73 +1,71 @@ # @author Lucas Frérot # # @section LICENSE # # Copyright (©) 2018 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Tamaas is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Tamaas is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Tamaas. If not, see . -from ._helper import FieldDumper +from ._helper import FieldDumper, step_dump, directory_dump import os import uvw import numpy as np __all__ = ["UVWDumper"] +@directory_dump('paraview') +@step_dump class UVWDumper(FieldDumper): """Dumper for elasto-plastic calculations""" def __init__(self, basename, *fields): default_fields = ['displacement', 'stress', 'plastic_strain'] super().__init__(basename, default_fields, *fields) - if not os.path.exists('paraview'): - os.mkdir('paraview') - - self.count = 0 - def dump(self, model): """Dump displacements, plastic deformations and stresses""" discretization = model.getDiscretization().copy() discretization[1] += 1 discretization[2] += 1 coordinates = [np.linspace(0, L, N) for L, N in zip(model.getSystemSize(), discretization)] # Correct order of coordinate dimensions dimension_indices = [1, 2, 0] # Creating rectilinear grid with correct order for components - grid = uvw.RectilinearGrid( - "paraview/{}_{:04d}.vtr".format(self.basename, self.count), - (coordinates[i] for i in dimension_indices)) + grid = uvw.RectilinearGrid(self.file_path(), + (coordinates[i] for i in dimension_indices)) dump_fields = { field: uvw.DataArray(self.make_periodic[field](model.getField(field)), dimension_indices, field) for field in self.fields } for array in dump_fields.values(): grid.addPointData(array) grid.write() - self.count += 1 + def file_path(self): + return os.path.join(self.dirname(), "{}{}.vtr".format(self.basename, + self.postfix())) diff --git a/tests/test_dumper.py b/tests/test_dumper.py index 4bad5ee..dc2b419 100644 --- a/tests/test_dumper.py +++ b/tests/test_dumper.py @@ -1,81 +1,87 @@ #!/usr/bin/env python # coding: utf-8 # ----------------------------------------------------------------------------- # @author Lucas Frérot # # @section LICENSE # # Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de # Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des # Solides) # # Tamaas is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Tamaas is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Tamaas. If not, see . # ----------------------------------------------------------------------------- from __future__ import print_function, division import tamaas as tm import numpy as np import os import shutil from tamaas.dumpers import NumpyDumper class Dumper(tm.ModelDumper): """Simple numpy dumper""" def __init__(self): tm.ModelDumper.__init__(self) def dump(self, model): np.savetxt('tractions.txt', np.ravel(model.getField('traction'))) np.savetxt('displacement.txt', np.ravel(model.getField('displacement'))) +def cleanup(): + for name in ['tractions.txt', + 'displacement.txt', + 'numpys']: + if os.path.exists(name) and os.path.isdir(name): + shutil.rmtree(name) + elif os.path.exists(name): + os.remove(name) + + def test_dumpers(tamaas_fixture): model = tm.ModelFactory.createModel(tm.model_type.volume_2d, [1., 1., 1.], [16, 4, 8]) dumper = Dumper() np_dumper = NumpyDumper('test_dump', 'traction', 'displacement') model.addDumper(dumper) model.addDumper(np_dumper) model.dump() + model.dump() tractions = np.loadtxt('tractions.txt') displacements = np.loadtxt('displacement.txt') assert tractions.size == model.getTraction().size assert displacements.size == model.getDisplacement().size with np.load('numpys/test_dump_0000.npz') as npfile: tractions = npfile['traction'] displacements = npfile['displacement'] t_shape = list(model.getTraction().shape) t_shape[0] += 1 t_shape[1] += 1 d_shape = list(model.getDisplacement().shape) d_shape[1] += 1 d_shape[2] += 1 assert tractions.shape == tuple(t_shape) assert displacements.shape == tuple(d_shape) - for name in ['tractions.txt', - 'displacement.txt', - 'numpys']: - if os.path.exists(name) and os.path.isdir(name): - shutil.rmtree(name) - elif os.path.exists(name): - os.remove(name) + assert os.path.isfile('numpys/test_dump_0001.npz') + cleanup()