diff --git a/src/pystencils_autodiff/walberla.py b/src/pystencils_autodiff/walberla.py new file mode 100644 index 0000000000000000000000000000000000000000..9d272eaf9e7df12a1b4a16d9a8bd734b5bd45d68 --- /dev/null +++ b/src/pystencils_autodiff/walberla.py @@ -0,0 +1,183 @@ +# +# Copyright © 2020 Stephan Seitz <stephan.seitz@fau.de> +# +# Distributed under terms of the GPLv3 license. + +""" + +""" + + +from os.path import dirname, join + +import jinja2 + +from pystencils.data_types import TypedSymbol +from pystencils_autodiff._file_io import read_template_from_file +from pystencils_autodiff.framework_integration.astnodes import JinjaCppFile + + +class WalberlaModule(JinjaCppFile): + TEMPLATE = read_template_from_file(join(dirname(__file__), 'walberla_main.tmpl.cpp')) + + def __init__(self, main): + ast_dict = {'main': main} + JinjaCppFile.__init__(self, ast_dict) + + +class WalberlaMain(JinjaCppFile): + + TEMPLATE = jinja2.Template(""" +int main( int argc, char ** argv ) +{ + using namespace walberla; + Environment {{ walberl_env }}( argc, argv ); + + {{ body | indent(3) }} + + return EXIT_SUCCESS; +} + """) + + headers = ['"core/Environment.h"', + '<cstdlib>', + '"UserDefinitions.h"'] + + def __init__(self, body, walberl_env="walberlaEnv"): + + ast_dict = { + 'body': body, + 'walberl_env': TypedSymbol(walberl_env, "Environment") + } + + super().__init__(ast_dict) + + @property + def symbols_defined(self): + return {self.ast_dict.walberl_env} + + +class BlockForrestCreation(JinjaCppFile): + TEMPLATE = jinja2.Template("""auto {{ blocks }} = walberla_user::createBlockForrest(walberlaEnv);""") + def __init__(self, block_forrest_name): + + ast_dict = { + 'blocks': TypedSymbol(block_forrest_name, "auto") + } + + super().__init__(ast_dict) + + @property + def symbols_defined(self): + return {self.ast_dict.blocks} + + +class UniformBlockForrestFromConfig(BlockForrestCreation): + TEMPLATE = jinja2.Template( + """auto {{ blocks }} = blockforest::createUniformBlockGridFromConfig( walberlaEnv.config() );""") + headers = ['"blockforest/Initialization.h"'] + + def __init__(self): + super().__init__('blocks') + + @property + def config_required(self): + return {"DomainSetup": {"blocks": [1, 1, 1], "cellsPerBlock": [100, 100, 100]}} + + @property + def blocks(self): + return self.ast_dict.blocks + + +class DefinitionsHeader(JinjaCppFile): + TEMPLATE = read_template_from_file(join(dirname(__file__), 'walberla_user_defintions.tmpl.hpp')) + + def __init__(self, walberla_module): + self.main_module = walberla_module + super().__init__({}) + + @property + def config_required(self): + return {"DomainSetup": {"blocks": [1, 1, 1], "cellsPerBlock": [100, 100, 100]}} + + +class Using(JinjaCppFile): + TEMPLATE = jinja2.Template("using {{ new_type }} = {{ definition }};\n") + + def __init__(self, new_type, definition): + ast_dict = { + 'new_type': new_type, + 'definition': definition, + } + super().__init__(ast_dict) + + @property + def symbols_defined(self): + return {self.ast_dict.new_type} + + +class GetParameter(JinjaCppFile): + + TEMPLATE = jinja2.Template( + 'walberlaEnv.config()->getOneBlock("{{ block }}").getParameter<{{ key.dtype }}>("{{ key }}"{% if default %}, {{ default }}{% endif %})' # noqa + ) + + def __init__(self, block: str, key, default_value=None): + ast_dict = { + 'key': key, + 'block': block, + 'default': default_value + } + super().__init__(ast_dict) + + @property + def config_required(self): + return {self.ast_dict.block: {self.ast_dict.symbol: self.ast_dict.default_value}} + + def __sympy__(self): + return TypedSymbol(self.ast_dict.key.name + "Config", str(self.ast_dict.key.dtype)) + + +class FieldAllocation(JinjaCppFile): + """ + .. code:: cpp + + BlockDataID addToStorage(const shared_ptr < BlockStorage_T > & blocks, + const std:: string & identifier, + const typename GhostLayerField_T:: value_type & initValue = typename GhostLayerField_T: : value_type(), + const Layout layout=zyxf, + const uint_t nrOfGhostLayers=uint_t(1), + const bool alwaysInitialize=false, + const std:: function < void (GhostLayerField_T * field, IBlock * const block ) > & initFunction = + std: : function < void (GhostLayerField_T * field, IBlock * const block ) > (), + const Set < SUID > & requiredSelectors = Set < SUID > : : emptySet(), + const Set < SUID > & incompatibleSelectors = Set < SUID > : : emptySet() ) + + """ # noqa + + TEMPLATE = jinja2.Template("""BlockDataID {{ field_name }}_data = field::addToStorage<{{ field_type }}>( {{ block_forrest }}, + {{ field_name }} + {%- if init_value %} , {{ init_value }} {% endif %} + {%- if layout_str %} , {{ layout_str }} {% endif %} + {%- if num_ghost_layers %}, {{ num_ghost_layers }} {% endif %} + {%- if always_initialize %}, {{ always_initialize }} {% endif %}) + """) # noqa + + def __init__(self, block_forrest, field): + self._symbol = TypedSymbol(field.name + '_data', 'BlockDataID') + ast_dict = { + 'block_forrest': block_forrest, + 'field_name': field.name, + 'field_type': f'GhostLayerField< {field.dtype}, {field.index_shape[0] if field.index_shape else 1} >' + } + super().__init__(ast_dict) + + headers = ['"fields/GhostLayerField.h"'] + + @property + def symbol(self): + return self._symbol + + @property + def symbols_defined(self): + return {self.symbol} diff --git a/src/pystencils_autodiff/walberla_main.tmpl.cpp b/src/pystencils_autodiff/walberla_main.tmpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83968b619b3c20fcb40e794c4cc0d54c709f4b89 --- /dev/null +++ b/src/pystencils_autodiff/walberla_main.tmpl.cpp @@ -0,0 +1,13 @@ +/* + * Automatically generated waLBerla main + * + */ + +{% for header in headers -%} +#include {{ header }} +{% endfor %} +{% for global in globals -%} +{{ global }} +{% endfor %} + +{{ main }} diff --git a/src/pystencils_autodiff/walberla_user_defintions.tmpl.hpp b/src/pystencils_autodiff/walberla_user_defintions.tmpl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dc6d4e5d2f623b60b92a86fb8df4682198152e12 --- /dev/null +++ b/src/pystencils_autodiff/walberla_user_defintions.tmpl.hpp @@ -0,0 +1,28 @@ +/* + * walberla_user_defintions.tmpl.hpp + * Copyright (C) 2020 Stephan Seitz <stephan.seitz@fau.de> + * + * Distributed under terms of the GPLv3 license. + */ + +#pragma once + +#include "lbm/communication/PdfFieldPackInfo.h" +#include "lbm/field/AddToStorage.h" +#include "lbm/field/PdfField.h" +#include "lbm/gui/Connection.h" +#include "lbm/vtk/VTKOutput.h" + +namespace walberla_user { +using namespace walberla; +using LatticeModel_T = lbm::LbCodeGenerationExample_LatticeModel; +using Stencil_T = LatticeModel_T::Stencil; +using CommunicationStencil_T = LatticeModel_T::CommunicationStencil_T; +using lPdfField_T = bm::PdfField<LatticeModel_T>; +using flag_t = walberla::uint8_t; +using FlagField_T FlagField<flag_t>; + +using PdfField_T = lbm::PdfField<LatticeModel_T>; +typedef VectorField_T = GhostLayerField<real_t, LatticeModel_T::Stencil::D>; +typedef ScalarField_T GhostLayerField<real_t, 1>; +} // namespace walberla_user diff --git a/tests/test_walberla.py b/tests/test_walberla.py new file mode 100644 index 0000000000000000000000000000000000000000..9147f41495050b4844108e0cab40dea32fd5679b --- /dev/null +++ b/tests/test_walberla.py @@ -0,0 +1,45 @@ +# +# Copyright © 2020 Stephan Seitz <stephan.seitz@fau.de> +# +# Distributed under terms of the GPLv3 license. + +""" + +""" +import numpy as np +import sympy as sp + +import pystencils +from pystencils.astnodes import Block, EmptyLine, SympyAssignment +from pystencils.data_types import TypedSymbol +from pystencils_autodiff._file_io import write_file +from pystencils_autodiff.walberla import ( + DefinitionsHeader, FieldAllocation, GetParameter, UniformBlockForrestFromConfig, + WalberlaMain, WalberlaModule) + + +def test_walberla(): + x, y = pystencils.fields('x, y: float32[3d]') + foo_symbol = TypedSymbol('foo', np.bool) + number_symbol = TypedSymbol('number', np.float32) + crazy_plus_one = TypedSymbol('crazy', np.float32) + + block_forrest = UniformBlockForrestFromConfig() + + block = Block([ + block_forrest, + SympyAssignment(foo_symbol, GetParameter('parameters', foo_symbol)), + SympyAssignment(number_symbol, GetParameter('parameters', number_symbol, 1.2)), + SympyAssignment(crazy_plus_one, number_symbol + 1), + EmptyLine(), + FieldAllocation(block_forrest.blocks, x) + ]) + + module = WalberlaModule(WalberlaMain(block)) + code = str(module) + print(code) + + write_file('/localhome/seitz_local/projects/walberla/apps/autogen/main.cpp', code) + + definitions = DefinitionsHeader(module) + write_file('/localhome/seitz_local/projects/walberla/apps/autogen/UserDefinitions.h', str(definitions))