diff --git a/apps/pythonmodule/PythonModule.cpp b/apps/pythonmodule/PythonModule.cpp index 419b1b37727a73245e01c7aaf6c466f7c48a6a85..b32f103ddda25f9590a6f2d87ee1cae30bc2e47b 100644 --- a/apps/pythonmodule/PythonModule.cpp +++ b/apps/pythonmodule/PythonModule.cpp @@ -40,34 +40,24 @@ using namespace walberla; Field<walberla::real_t,1>,\ Field<walberla::real_t,2>,\ Field<walberla::real_t,3>,\ - Field<walberla::real_t,4>,\ - Field<walberla::real_t,5>,\ - Field<walberla::real_t,6>,\ Field<walberla::real_t,9>,\ Field<walberla::real_t,15>,\ Field<walberla::real_t,19>,\ Field<walberla::real_t,27>,\ Field<walberla::int8_t,1>,\ - Field<walberla::int16_t,1>,\ - Field<walberla::int32_t,1>,\ Field<walberla::int64_t,1>,\ Field<walberla::int64_t,2>,\ Field<walberla::int64_t,3>,\ - Field<walberla::int64_t,4>,\ Field<walberla::uint8_t,1>,\ Field<walberla::uint16_t,1>,\ Field<walberla::uint32_t,1> #define GPU_FIELD_TYPES \ - GPUField<double>,\ - GPUField<float>,\ + GPUField<real_t>,\ GPUField<int8_t>,\ - GPUField<int16_t>,\ GPUField<int32_t>,\ GPUField<int64_t>,\ GPUField<uint8_t>,\ - GPUField<uint16_t>,\ - GPUField<uint32_t>,\ GPUField<uint64_t> struct InitObject diff --git a/python/waLBerla/callbacks.py b/python/waLBerla/callbacks.py index f9153ec5b7f19bc6789915f470222ce48cd4f307..07f2ebc0f35ae7cda48f3958531b1f0fb11f48ac 100644 --- a/python/waLBerla/callbacks.py +++ b/python/waLBerla/callbacks.py @@ -149,7 +149,7 @@ class ScenarioManager: cfg = None while cfg is None: cfg = get_config_from_scenario(scenario) - # walberla_cpp.log_info_on_root("Simulating Scenario %d of %d :" % (idx + 1, len(self._scenarios))) + walberla_cpp.log_info_on_root("Simulating Scenario %d of %d :" % (idx + 1, len(self._scenarios))) yield cfg except ImportError: diff --git a/python/waLBerla_docs/modules/core.rst b/python/waLBerla_docs/modules/core.rst index c1253ba29577a9dcb2e6477cbf9f095f0006b4a8..ee8d985a3b8fe7f3a9582697c87c6afb519c7ac1 100644 --- a/python/waLBerla_docs/modules/core.rst +++ b/python/waLBerla_docs/modules/core.rst @@ -198,6 +198,10 @@ Block Structure .. py:method:: containsGlobalBlockInformation( ) .. py:method:: blocksOverlappedByAABB( point, aabb ) .. py:method:: blocksContainedWithinAABB( point, aabb ) + + .. py:method:: addBlockData( name, blockdata) + + Adds custom data to the blockforest. This can be a Python Class for example which is then callable on all blocks .. py:method:: blockExists( point ) .. py:method:: blockExistsLocally( point ) diff --git a/python/waLBerla_tests/test_field.py b/python/waLBerla_tests/test_field.py index 3ab25c4189bcc014200ccf9c1ffc763c421ff41b..04ab5afb43512619654425d04e40ca99c56f0238 100644 --- a/python/waLBerla_tests/test_field.py +++ b/python/waLBerla_tests/test_field.py @@ -18,14 +18,14 @@ class FieldModuleTest(unittest.TestCase): def testNumpyConversionWithoutGhostLayers(self): blocks = createUniformBlockGrid(blocks=(1, 1, 1), cellsPerBlock=(1, 2, 3), periodic=(True, False, False)) - field.addToStorage(blocks, 'f1', np.float64, fSize=4, ghostLayers=0, initValue=2.0) - field.addToStorage(blocks, 'f2', np.float64, fSize=5, ghostLayers=0, initValue=2.0) + field.addToStorage(blocks, 'f1', np.float64, fSize=2, ghostLayers=0, initValue=2.0) + field.addToStorage(blocks, 'f2', np.float64, fSize=3, ghostLayers=0, initValue=2.0) f1np = field.toArray(blocks[0]['f1']) f2np = field.toArray(blocks[0]['f2']) self.assertEqual(f1np[0, 0, 0, 0], 2.0) - self.assertEqual(f1np.shape, (1, 2, 3, 4)) - self.assertEqual(f2np.shape, (1, 2, 3, 5)) + self.assertEqual(f1np.shape, (1, 2, 3, 2)) + self.assertEqual(f2np.shape, (1, 2, 3, 3)) def testGhostLayerExtraction(self): size = (10, 5, 4) diff --git a/src/python_coupling/CreateConfig.cpp b/src/python_coupling/CreateConfig.cpp index c7e3d1b2499e510e98700bdc5ab09500ad2abcfd..5f8f9615c2f346096b567826974d20904ad2b9af 100644 --- a/src/python_coupling/CreateConfig.cpp +++ b/src/python_coupling/CreateConfig.cpp @@ -70,30 +70,27 @@ shared_ptr< Config > createConfigFromPythonScript(const std::string& scriptFile, class PythonMultipleConfigGenerator : public config::ConfigGenerator { public: - PythonMultipleConfigGenerator(py::list ConfigList) // NOLINT - : ConfigList_(ConfigList), counter(0) // NOLINT + PythonMultipleConfigGenerator(py::object ScenarioConfigGenerator) // NOLINT + : ScenarioConfigGenerator_(ScenarioConfigGenerator) // NOLINT {} shared_ptr< Config > next() override { shared_ptr< Config > config = make_shared< Config >(); - - if ( counter == ConfigList_.size() ) + try + { + py::dict configDict = ScenarioConfigGenerator_.attr("__next__")(); + configFromPythonDict(config->getWritableGlobalBlock(), configDict); + return config; + } + catch (py::error_already_set&) + { return shared_ptr<Config>(); - - py::dict configDict = ConfigList_[counter]; - configFromPythonDict(config->getWritableGlobalBlock(), configDict); - - WALBERLA_LOG_INFO_ON_ROOT("Simulating Scenario " << counter + 1 << " of " << ConfigList_.size() << ":") - - counter++; - - return config; + } } private: - py::list ConfigList_; - uint_t counter; + py::object ScenarioConfigGenerator_; }; class PythonSingleConfigGenerator : public config::ConfigGenerator diff --git a/src/python_coupling/export/BasicExport.cpp b/src/python_coupling/export/BasicExport.cpp index 279e304e5adbcc032e0825fa46e3829af158c552..c4fad8eb6cf39d9442ddbbe46e4e278d5e738a4d 100644 --- a/src/python_coupling/export/BasicExport.cpp +++ b/src/python_coupling/export/BasicExport.cpp @@ -55,14 +55,6 @@ # include <pybind11/stl.h> -// specialize operator== since == is deprecated in pybind11 -template<> -bool walberla::domain_decomposition::internal::BlockData::Data< pybind11::object >::operator==( - const BlockData::DataBase& rhs) const -{ - const Data< pybind11::object >* rhsData = dynamic_cast< const Data< pybind11::object >* >(&rhs); - return (rhsData == &rhs) && (data_->is(*(rhsData->data_))); -} namespace py = pybind11; namespace walberla { diff --git a/src/python_coupling/export/BlockForestExport.cpp b/src/python_coupling/export/BlockForestExport.cpp index 7d2c9d764a76f3c012d85d86e21efb24a4444e06..e4aae6226c92ee24cad6f4d1db07fcfce6c80a66 100644 --- a/src/python_coupling/export/BlockForestExport.cpp +++ b/src/python_coupling/export/BlockForestExport.cpp @@ -42,6 +42,15 @@ # include "BlockForestExport.h" # include "python_coupling/helper/OwningIterator.h" +// specialize operator== since == is deprecated in pybind11 +template<> +bool walberla::domain_decomposition::internal::BlockData::Data< pybind11::object >::operator==( + const BlockData::DataBase& rhs) const +{ + const Data< pybind11::object >* rhsData = dynamic_cast< const Data< pybind11::object >* >(&rhs); + return (rhsData == &rhs) && (data_->is(*(rhsData->data_))); +} + namespace walberla { namespace blockforest @@ -257,6 +266,19 @@ bool p_blockExistsRemotely1(StructuredBlockForest& s, const std::array<real_t, 3 } +py::object * blockDataCreationHelper( IBlock * block, py::object callable ) //NOLINT +{ + py::object * res = new py::object( callable( block )); + return res; +} + +uint_t StructuredBlockForest_addBlockData( StructuredBlockForest & s, const std::string & name, py::object functionPtr ) //NOLINT +{ + BlockDataID res = s.addBlockData(name) + << BlockDataCreator<py::object>( std::bind( &blockDataCreationHelper, std::placeholders::_1, functionPtr ) ); + return res; +} + bool SbF_atDomainXMinBorder(StructuredBlockForest& s, const IBlock* b) { return s.atDomainXMinBorder(*b); } bool SbF_atDomainXMaxBorder(StructuredBlockForest& s, const IBlock* b) { return s.atDomainXMaxBorder(*b); } bool SbF_atDomainYMinBorder(StructuredBlockForest& s, const IBlock* b) { return s.atDomainYMinBorder(*b); } @@ -278,6 +300,7 @@ void exportBlockForest(py::module_& m) py::class_< StructuredBlockForest, std::shared_ptr< StructuredBlockForest > >(m, "StructuredBlockForest") .def("getNumberOfLevels", &StructuredBlockForest::getNumberOfLevels) .def_property_readonly("getDomain", &StructuredBlockForest::getDomain) + .def( "addBlockData", &StructuredBlockForest_addBlockData) .def("mapToPeriodicDomain", &SbF_mapToPeriodicDomain1) .def("mapToPeriodicDomain", &SbF_mapToPeriodicDomain2) .def("mapToPeriodicDomain", &SbF_mapToPeriodicDomain3) diff --git a/src/python_coupling/export/FieldCommunicationExport.impl.h b/src/python_coupling/export/FieldCommunicationExport.impl.h index 0793b26a567b7da73f8f905f604be3048c1afd59..57289631d981822f5ba10c5111279c5da1d79337 100644 --- a/src/python_coupling/export/FieldCommunicationExport.impl.h +++ b/src/python_coupling/export/FieldCommunicationExport.impl.h @@ -51,6 +51,119 @@ namespace internal { namespace py = pybind11; +//=================================================================================================================== +// +// createStencilRestrictedPackInfo Export +// +//=================================================================================================================== + +template< typename FieldType > +typename std::enable_if<FieldType::F_SIZE == 27, py::object>::type +createStencilRestrictedPackInfoObject( BlockDataID bdId ) +{ + typedef GhostLayerField<typename FieldType::value_type, 27> GlField_T; + using field::communication::StencilRestrictedPackInfo; + return py::cast( make_shared< StencilRestrictedPackInfo<GlField_T, stencil::D3Q27> >( bdId) ); +} + +template< typename FieldType > +typename std::enable_if<FieldType::F_SIZE == 19, py::object>::type +createStencilRestrictedPackInfoObject( BlockDataID bdId ) +{ + typedef GhostLayerField<typename FieldType::value_type, 19> GlField_T; + using field::communication::StencilRestrictedPackInfo; + return py::cast( make_shared< StencilRestrictedPackInfo<GlField_T, stencil::D3Q19> >( bdId) ); +} + +template< typename FieldType > +typename std::enable_if<FieldType::F_SIZE == 15, py::object>::type +createStencilRestrictedPackInfoObject( BlockDataID bdId ) +{ + typedef GhostLayerField<typename FieldType::value_type, 15> GlField_T; + using field::communication::StencilRestrictedPackInfo; + return py::cast( make_shared< StencilRestrictedPackInfo<GlField_T, stencil::D3Q15> >( bdId) ); +} + +template< typename FieldType > +typename std::enable_if<FieldType::F_SIZE == 7, py::object>::type +createStencilRestrictedPackInfoObject( BlockDataID bdId ) +{ + typedef GhostLayerField<typename FieldType::value_type, 7> GlField_T; + using field::communication::StencilRestrictedPackInfo; + return py::cast( make_shared< StencilRestrictedPackInfo<GlField_T, stencil::D3Q7> >( bdId) ); +} + +template< typename FieldType > +typename std::enable_if<FieldType::F_SIZE == 9, py::object>::type +createStencilRestrictedPackInfoObject( BlockDataID bdId ) +{ + typedef GhostLayerField<typename FieldType::value_type, 9> GlField_T; + using field::communication::StencilRestrictedPackInfo; + return py::cast( make_shared< StencilRestrictedPackInfo<GlField_T, stencil::D2Q9> >( bdId) ); +} + +template< typename FieldType > +typename std::enable_if<!(FieldType::F_SIZE == 9 || + FieldType::F_SIZE == 7 || + FieldType::F_SIZE == 15 || + FieldType::F_SIZE == 19 || + FieldType::F_SIZE == 27), py::object>::type +createStencilRestrictedPackInfoObject( BlockDataID ) +{ + throw py::value_error("This works only for fields with fSize in 7, 9, 15, 19 or 27"); +} + +class StencilRestrictedPackInfoExporter +{ + public: + StencilRestrictedPackInfoExporter(const shared_ptr<StructuredBlockForest> & blocks, BlockDataID fieldId) + : blocks_(blocks), fieldId_(fieldId) + {} + + template< typename FieldType> + void operator() ( python_coupling::NonCopyableWrap<FieldType> ) + { + typedef typename FieldType::value_type T; + const uint_t F_SIZE = FieldType::F_SIZE; + typedef GhostLayerField<T, F_SIZE> GlField_T; + IBlock * firstBlock = & ( * blocks_->begin() ); + if( firstBlock->isDataClassOrSubclassOf<FieldType>(fieldId_) ) + { + resultStencilRestrictedPackInfo_ = createStencilRestrictedPackInfoObject<GlField_T>(fieldId_); + } + } + py::object getResultStencilRestrictedPackInfo() + { + return resultStencilRestrictedPackInfo_; + } + + private: + py::object resultStencilRestrictedPackInfo_; + shared_ptr< StructuredBlockStorage > blocks_; + BlockDataID fieldId_; +}; + +template<typename... FieldTypes> +static py::object StencilRestrictedPackInfoWrapper(const shared_ptr<StructuredBlockForest> & blocks, + const std::string & blockDataName ) +{ + BlockDataID fieldID = python_coupling::blockDataIDFromString( *blocks, blockDataName ); + + if ( blocks->begin() == blocks->end() ) { + // if no blocks are on this field an arbitrary PackInfo can be returned + return py::cast( make_shared< field::communication::StencilRestrictedPackInfo<GhostLayerField<real_t, 9>, stencil::D2Q9> >( fieldID ) ); + } + + StencilRestrictedPackInfoExporter exporter(blocks, fieldID); + python_coupling::for_each_noncopyable_type< FieldTypes... > ( std::ref(exporter) ); + if ( ! exporter.getResultStencilRestrictedPackInfo() ) { + throw py::value_error("Failed to create Stencil Restricted PackInfo"); + } + else { + return exporter.getResultStencilRestrictedPackInfo(); + } +} + //=================================================================================================================== // // createPackInfo Export @@ -241,6 +354,14 @@ void exportCommunicationClasses(py::module_& m) return internal::UniformMPIDatatypeInfoWrapper< FieldTypes... >(blocks, blockDataName, numberOfGhostLayers); }, "blocks"_a, "blockDataName"_a, "numberOfGhostLayers"_a = uint_t(0)); + + m2.def( + "createStencilRestrictedPackInfo", + [](const shared_ptr<StructuredBlockForest> & blocks, + const std::string & blockDataName) { + return internal::StencilRestrictedPackInfoWrapper< FieldTypes... >(blocks, blockDataName); + }, + "blocks"_a, "blockDataName"_a); } } // namespace field