Commit 8fdaf52b authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Merge branch 'feature/add-dune-vtk-bindings' into 'master'

Feature/add dune vtk bindings

See merge request extensions/dune-vtk!11
parents b2687dc3 1ed3b74a
......@@ -28,5 +28,11 @@ add_subdirectory(doc)
add_subdirectory(lib)
add_subdirectory(cmake/modules)
# if Python bindings are enabled, include necessary sub directories.
if( DUNE_ENABLE_PYTHONBINDINGS )
add_subdirectory(python)
dune_python_install_package(PATH python)
endif()
# finalize the dune project, e.g. generating config.h etc.
finalize_dune_project(GENERATE_CONFIG_H_CMAKE)
......@@ -5,7 +5,15 @@
#Name of the module
Module: dune-vtk
Version: 0.2
#meta data
Author: Simon Praetorius
Maintainer: simon.praetorius@tu-dresden.de
Description: File reader and writer for the VTK Format
URL: https://gitlab.dune-project.org/extensions/dune-vtk
#depending on
Depends: dune-grid (>= 2.7) dune-localfunctions (>= 2.7)
Suggests: dune-functions dune-spgrid dune-polygongrid dune-alugrid dune-foamgrid dune-uggrid
Python-Requires:
Whitespace-Hook: Yes
add_subdirectory(vtk)
# if Python bindings are enabled, include necessary sub directories.
if( DUNE_ENABLE_PYTHONBINDINGS )
add_subdirectory("python")
endif()
add_subdirectory(vtk)
add_subdirectory(test)
import math
from dune.grid import structuredGrid, gridFunction
from dune.vtk import vtkUnstructuredGridWriter, vtkWriter, RangeTypes, FieldInfo
grid = structuredGrid([0,0],[1,1],[5,5])
def test1(writer):
@gridFunction(grid)
def f(x):
return x[0]*x[1]
writer.addPointData(f, name="f")
del f
@gridFunction(grid)
def g(x):
return [math.sin(2*math.pi*x[0]*x[1]), x[0]*x[1]]
writer1 = vtkUnstructuredGridWriter(grid)
test1(writer1)
writer1.write("test1")
writer2 = vtkUnstructuredGridWriter(grid)
writer2.addPointData(g, name="g")
writer2.write("test2")
@gridFunction(grid)
def g(x):
return [math.sin(2*math.pi*x[0]*x[1]), x[0]*x[1]]*5
writer3 = vtkUnstructuredGridWriter(grid)
test1(writer3)
writer3.addPointData(g, name="g")
writer3.write("test3")
writer4 = vtkUnstructuredGridWriter(grid)
writer4.addPointData(g, name="g10", components=(0,1)) # neither
writer4.addPointData(g, name="g012", components=[0,1,2]) # is vector
writer4.addPointData(g, name="g23", components=[2,3]) # neiter
writer4.addPointData(g, name="g2", components=[2]) # is scalar
writer4.addPointData(g, name="g23V", range=RangeTypes.vector,
components=[2,3]) # is vector
writer4.addPointData(g, name="g23S", range=RangeTypes.scalar,
components=[2,3]) # is scalar
writer4.addPointData(g, info=FieldInfo(name="g2S", range=RangeTypes.scalar),
components=[2]) # is scalar
writer4.addPointData(g, info=FieldInfo(name="g2V", range=RangeTypes.vector),
components=[2]) # is vector
writer4.write("test4")
@gridFunction(grid)
def f(x):
return math.sin(2*math.pi*x[0]*x[1]/(1+x[0]*x[0]))
"""
def vtkWriter(grid, name,
version="unstructured",
cellScalar=None, pointScalar=None,
cellVector=None, pointVector=None,
number=None, outputType=OutputType.appendedbase64,
write=True,
**kwargs # additional ctor arguments for writer
"""
# Note: {"gV":g} has only one components in the data file although the range is auto
writer = vtkWriter( grid, "test",
pointData = { "gV":g, ("g43V",(4,3)):g, ("g435V",(4,3,5)):g },
pointScalar = { "fS":f, "gS":g, ("g23S",(2,3)):g },
)
writer = vtkWriter( grid, "testLagrange",
version="lagrange", order=3,
pointData = {"gV":g, ("g43V",(4,3)):g},
pointScalar = {("g435V",(4,3,5)):g},
cellData = {("g23V",(2,3)):g, ("g234V",(2,3,4)):g},
cellScalar = { "fS":f, "gS":g}
)
set(HEADERS
writer.hh
)
install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/python/vtk)
// -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_PYTHON_VTK_WRITER_HH
#define DUNE_PYTHON_VTK_WRITER_HH
#include <dune/vtk/vtkwriter.hh>
#include <dune/python/pybind11/pybind11.h>
#include <dune/python/pybind11/stl.h>
namespace Dune
{
namespace Vtk
{
// registerVTKWriter
// -----------------
template< class Writer, class... options >
inline static void registerVtkWriter ( pybind11::handle scope,
pybind11::class_< Writer, options... > cls )
{
using GridView = typename Writer::GridView;
using VirtualizedGF = Dune::Vtk::Function<GridView>;
cls.def( pybind11::init( [] ( GridView &grid,
Vtk::FormatTypes format,
Vtk::DataTypes datatype,
Vtk::DataTypes headertype,
pybind11::kwargs kwargs) {
return new Writer( grid, format, datatype, headertype );
}), pybind11::arg("grid"),
pybind11::arg("format") = Vtk::FormatTypes::BINARY,
pybind11::arg("datatype") = Vtk::DataTypes::FLOAT32,
pybind11::arg("headertype") = Vtk::DataTypes::UINT32,
pybind11::keep_alive< 1, 2 >());
cls.def( "write",
[] ( Writer &writer, const std::string &name ) {
writer.write( name );
},
pybind11::arg("name") );
cls.def( "write",
[] ( Writer &writer, const std::string &name, int number ) {
std::stringstream s; s << name << std::setw(5) << std::setfill('0') << number;
writer.write( s.str());
},
pybind11::arg("name"),
pybind11::arg("number") );
cls.def( "addPointData",
[] ( Writer &writer, VirtualizedGF &f,
RangeTypes range, DataTypes data
) {
f.setRangeType(range);
f.setDataType(data);
writer.addPointData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32
);
cls.def( "addPointData",
[] ( Writer &writer, VirtualizedGF &f,
std::string &name,
RangeTypes range, DataTypes data
) {
f.setName(name);
f.setRangeType(range);
f.setDataType(data);
writer.addPointData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("name"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32
);
cls.def( "addPointData",
[] ( Writer &writer, VirtualizedGF &f,
std::string &name,
std::vector<int> &components,
RangeTypes range, DataTypes data
) {
f.setName(name);
f.setRangeType(range);
f.setDataType(data);
f.setComponents(components);
writer.addPointData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("name"),
pybind11::arg("components"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32
);
cls.def( "addPointData",
[] ( Writer &writer, VirtualizedGF &f,
FieldInfo &info) {
f.setFieldInfo(info);
writer.addPointData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("info") );
cls.def( "addPointData",
[] ( Writer &writer, VirtualizedGF &f,
std::vector<int> &components, FieldInfo &info ) {
f.setFieldInfo(info);
f.setComponents(components);
writer.addPointData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("components"), pybind11::arg("info") );
cls.def( "addCellData",
[] ( Writer &writer, VirtualizedGF &f,
RangeTypes range, DataTypes data
) {
f.setRangeType(range);
f.setDataType(data);
writer.addCellData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32
);
cls.def( "addCellData",
[] ( Writer &writer, VirtualizedGF &f,
std::string &name,
RangeTypes range, DataTypes data
) {
f.setName(name);
f.setRangeType(range);
f.setDataType(data);
writer.addCellData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("name"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32
);
cls.def( "addCellData",
[] ( Writer &writer, VirtualizedGF &f,
std::string &name,
std::vector<int> &components,
RangeTypes range, DataTypes data
) {
f.setName(name);
f.setRangeType(range);
f.setDataType(data);
f.setComponents(components);
writer.addCellData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("name"),
pybind11::arg("components"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32
);
cls.def( "addCellData",
[] ( Writer &writer, VirtualizedGF &f,
FieldInfo &info) {
f.setFieldInfo(info);
writer.addCellData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("info") );
cls.def( "addCellData",
[] ( Writer &writer, VirtualizedGF &f,
std::vector<int> &components, FieldInfo &info ) {
f.setFieldInfo(info);
f.setComponents(components);
writer.addCellData(f);
},
pybind11::keep_alive< 1, 2 >(),
pybind11::arg("f"), pybind11::arg("components"), pybind11::arg("info") );
}
} // namespace Vtk
} // namespace Dune
#endif // DUNE_PYTHON_VTK_WRITER_HH
......@@ -78,6 +78,7 @@ Vtk::RangeTypes rangeTypeOf (int ncomps)
std::string to_string (Vtk::DataTypes type)
{
switch (type) {
case Vtk::DataTypes::UNKNOWN: return "unknown";
case Vtk::DataTypes::INT8: return "Int8";
case Vtk::DataTypes::UINT8: return "UInt8";
case Vtk::DataTypes::INT16: return "Int16";
......
......@@ -25,6 +25,7 @@ namespace Dune
APPENDED = BINARY | COMPRESSED
};
std::string to_string (Vtk::FormatTypes);
inline auto formatTypesList = {FormatTypes::ASCII, FormatTypes::BINARY, FormatTypes::COMPRESSED, FormatTypes::APPENDED};
/// Map the dune-grid OutputType to FormatTypes
Vtk::FormatTypes formatTypeOf(Dune::VTK::OutputType);
......@@ -39,6 +40,7 @@ namespace Dune
TENSOR //< Use exactly 9 components
};
std::string to_string (Vtk::RangeTypes);
inline auto rangeTypesList = { RangeTypes::UNSPECIFIED, RangeTypes::AUTO, RangeTypes::SCALAR, RangeTypes::VECTOR, RangeTypes::TENSOR };
// Map a dune-grid FieldInfo::Type to ValueTypes
Vtk::RangeTypes rangeTypeOf (Dune::VTK::FieldInfo::Type);
......@@ -57,6 +59,14 @@ namespace Dune
FLOAT64 = 64
};
std::string to_string (Vtk::DataTypes);
inline auto dataTypesLists = {
DataTypes::UNKNOWN,
DataTypes::INT8, DataTypes::UINT8,
DataTypes::INT16, DataTypes::UINT16,
DataTypes::INT32, DataTypes::UINT32,
DataTypes::INT64, DataTypes::UINT64,
DataTypes::FLOAT32, DataTypes::FLOAT64
};
// Map a dune-grid Precision type to DataTypes
Vtk::DataTypes dataTypeOf (Dune::VTK::Precision);
......
[build-system]
requires = ['setuptools', 'wheel', 'scikit-build', 'cmake', 'ninja', 'requests', 'dune-common<=2.8.0.dev', 'dune-geometry<=2.8.0.dev', 'dune-grid<=2.8.0.dev', 'dune-localfunctions<=2.8.0.dev']
build-backend = 'setuptools.build_meta'
add_subdirectory(dune)
configure_file(setup.py.in setup.py)
add_subdirectory(vtk)
add_python_targets(dune
__init__
)
__import__('pkg_resources').declare_namespace(__name__)
add_python_targets(vtk
__init__
)
dune_add_pybind11_module(NAME _vtk)
set_property(TARGET _vtk PROPERTY LINK_LIBRARIES dunecommon dunegeometry dunegrid dunevtk APPEND)
import hashlib
from dune.generator.generator import SimpleGenerator
from ._vtk import *
from dune.grid import OutputType
from dune.grid.grid_generator import _writeVTKDispatcher as addDispatcher
generator = SimpleGenerator("VtkWriter", "Dune::Vtk")
def load(includes, typeName):
includes += ["dune/python/vtk/writer.hh"]
moduleName = "vtkwriter_" + hashlib.md5(typeName.encode('utf-8')).hexdigest()
module = generator.load(includes, typeName, moduleName)
return module.VtkWriter
######################################################################
allCollectors = {
"continuous":
lambda grid:
"ContinuousDataCollector<"+grid._typeName+">",
"lagrange":
lambda grid, **kwargs:
"Dune::Vtk::LagrangeDataCollector<"+grid._typeName+","+str(kwargs["order"])+">"
}
allWriters = {
"default": [ lambda grid:
"Dune::VtkUnstructuredGridWriter<"+grid._typeName+">",
["dune/vtk/writers/vtkunstructuredgridwriter.hh"] ],
"lagrange": [ lambda grid, **kwargs:
"Dune::VtkUnstructuredGridWriter<"+grid._typeName+","+\
allCollectors["lagrange"](grid,**kwargs)+">",
["dune/vtk/writers/vtkunstructuredgridwriter.hh",
"dune/vtk/datacollectors/lagrangedatacollector.hh"] ]
}
def vtkWriter(grid, name,
version="default",
pointData=None, pointScalar=None,
cellData=None, cellScalar=None,
number=None, write=True,
format = FormatTypes.binary,
datatype = DataTypes.Float32, headertype = DataTypes.UInt32,
**kwargs # additional ctor arguments for dataContainer or Writer
):
writer = load( allWriters[version][1],
allWriters[version][0](grid,**kwargs) )\
(grid, format, datatype, headertype, **kwargs)
# method to extract the range dimension from a given grid function
def rangeDimension(f):
try: return len(f)
except: pass
try: return f.ufl_shape[0]
except: pass
try: return f.dimRange
except: pass
return None
# reinterpret `functions` argument list as list of the form
# return list with entries [f,{name,components}] or [f,{name}]
def extract(functions, toScalar):
ret = []
if type(functions)==dict: # form name:function, or (name,components):function
for k,v in functions.items():
if type(k) == str:
ret += [ [v,{"name":k}] ]
else: # name component pair assumed
ret += [ [v,{"name":k[0], "components":k[1]}] ]
elif type(functions)==list: # each entry is a function with a 'name'
# and possibly a 'components' attribute
for v in functions:
try:
ret += [ [v,{"name":v.name, "components":v.components}] ]
except AttributeError:
ret += [ [v,{"name":v.name}] ]
if toScalar: # convert scalar functions with multiply components
scalarRet = []
for r in ret:
# can we extract range dimension from a grid function?
dimR = rangeDimension(r[0])
comp = r[1].get("components",range(dimR))
if dimR is None or len(comp)==1:
scalarRet += [ [ r[0], {"name":r[1]["name"],
"components":comp} ] ]
else:
for i, c in enumerate(comp):
scalarRet += [ [ r[0], {"name":r[1]["name"]+"_"+str(i),
"components":[c]} ] ]
return scalarRet
else:
return ret
# call the actual `add` method on the writer here other packages can
# add dispatch method to convert `f` into a `Vtk::Function`, i.e., a
# ufl expression.
def addDefault(addMethod, f, **kwargs):
try:
addMethod(f,**kwargs)
return
except TypeError:
pass
for dispatch in addDispatcher:
func = dispatch(grid,f)
if func is not None:
addMethod(func,**kwargs)
return
raise AttributeError("coundn't find a way to add function "+str(f)+
" of type "+str(type(f))+" to the VtkWriter")
# add all the functions provided as arguments to the writer
for f in extract(pointData, toScalar=False):
addDefault( writer.addPointData, f[0], **f[1], range=RangeTypes.auto)
for f in extract(pointScalar, toScalar=True):
addDefault( writer.addPointData, f[0], **f[1], range=RangeTypes.scalar)
for f in extract(cellData,False):
addDefault( writer.addCellData, f[0], **f[1], range=RangeTypes.vector)
for f in extract(cellScalar,True):
addDefault( writer.addCellData, f[0], **f[1], range=RangeTypes.scalar)
# the class is returned. It doesn't allow for adding additional data
# since after the first `write` this doesn't make sense. The name is
# fixed by the provided argument and in addition a consecutive number
# is added for each execution of __call__.
class _Writer:
def __init__(self,writer,name,number):
self.writer = writer
self.name = name
self.number = number
def __call__(self):
if self.number is None:
self.writer.write(self.name)
else:
self.writer.write(self.name,self.number)
self.number += 1
_writer = _Writer(writer,name,number)
if write:
_writer()
return _writer
#######################################################
def vtkUnstructuredGridWriter(grid):
"""create a VtkWriter for unstructured grids
Args:
grid: grid view to use for the vtk file
Returns:
vtkWriter: the constructed writer
"""
return load( allWriters["default"][1],
allWriters["default"][0](grid) )(grid)
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#include <dune/vtk/types.hh>
#include <dune/python/pybind11/pybind11.h>
PYBIND11_MODULE( _vtk, module )
{
{
using namespace Dune::Vtk;
pybind11::enum_< FormatTypes > formatTypes( module, "FormatTypes" );
for (const auto e : formatTypesList)
formatTypes.value( to_string(e).c_str(), e );
pybind11::enum_< RangeTypes > rangeTypes( module, "RangeTypes" );
for (const auto e : rangeTypesList)
rangeTypes.value( to_string(e).c_str(), e );
pybind11::enum_< DataTypes > dataTypes( module, "DataTypes" );
for (const auto e : dataTypesLists)
dataTypes.value( to_string(e).c_str(), e );
pybind11::class_<FieldInfo> fieldInfo(module, "FieldInfo" );
fieldInfo.def( pybind11::init(
[](std::string name, RangeTypes range, DataTypes data)
{ return new FieldInfo(name, range, data); }
), pybind11::arg("name"),
pybind11::arg("range")=RangeTypes::AUTO,
pybind11::arg("data")=DataTypes::FLOAT32 );
}
}
from setuptools import setup, find_packages
pkg = [m for m in "${ProjectPythonRequires}".split(' ') if "dune" not in m]
setup(name="${ProjectName}",
namespace_packages=['dune'],
description="${ProjectDescription}",
version="${ProjectVersionString}",
author="${ProjectAuthor}",
author_email="${ProjectMaintainerEmail}",
packages = find_packages(),
zip_safe = 0,
package_data = {'': ['*.so']},
install_requires = pkg
)
try:
from dune.packagemetadata import metaData
except ImportError:
from packagemetadata import metaData
from skbuild import setup
setup(**metaData()[1])
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment