//====================================================================================================================== // // This file is part of waLBerla. waLBerla is free software: you can // redistribute it and/or modify it under the terms of the GNU General Public // License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // waLBerla 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 General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // //! \file Initialization.cpp //! \ingroup vtk //! \author Florian Schornbaum <florian.schornbaum@fau.de> // //====================================================================================================================== #include "ChainedFilter.h" #include "Initialization.h" #include "core/Abort.h" #include "core/logging/Logging.h" #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/split.hpp> #include <functional> namespace walberla { namespace vtk { template< typename T > static void splitVector( T& x, T& y, T& z, const Config::BlockHandle& bb, const std::string& vertex, const std::string& errorMsg ) { std::vector< std::string > coordinates; std::string vector = bb.getParameter< std::string >( vertex ); boost::split( coordinates, vector, boost::is_any_of("<,> \t") ); coordinates.erase( std::remove_if( coordinates.begin(), coordinates.end(), std::bind( &std::string::empty, std::placeholders::_1 ) ), coordinates.end() ); if( coordinates.size() != 3 ) WALBERLA_ABORT( errorMsg ); x = boost::lexical_cast< T >( coordinates[0] ); y = boost::lexical_cast< T >( coordinates[1] ); z = boost::lexical_cast< T >( coordinates[2] ); } static std::vector< std::string > splitList( const std::string& string ) { std::vector< std::string > list; boost::split( list, string, boost::is_any_of(", \t") ); list.erase( std::remove_if( list.begin(), list.end(), std::bind( &std::string::empty, std::placeholders::_1 ) ), list.end() ); return list; } static void addStates( Set<SUID>& set, const std::string& string ) { std::vector< std::string > states; boost::split( states, string, boost::is_any_of(", \t") ); states.erase( std::remove_if( states.begin(), states.end(), std::bind( &std::string::empty, std::placeholders::_1 ) ), states.end() ); for( auto it = states.begin(); it != states.end(); ++it ) set += SUID( *it ); } void initializeVTKOutput( std::map< std::string, SelectableOutputFunction > & outputFunctions, const shared_ptr< const StructuredBlockStorage > & storage, const shared_ptr< Config > & config, const std::string & configBlockName, const std::vector< shared_ptr< BlockCellDataWriterInterface > > & writers, const std::map< std::string, VTKOutput::CellFilter > & filters, const std::map< std::string, VTKOutput::BeforeFunction > & beforeFunctions ) { if( !!config ) initializeVTKOutput( outputFunctions, storage, config->getGlobalBlock(), configBlockName, writers, filters, beforeFunctions ); } struct CaseInsensitiveCompare { bool operator()( const std::string& lhs, const std::string& rhs ) const { return boost::ilexicographical_compare( lhs, rhs ); } }; // only required in 'initializeVTKOutput' below void initializeVTKOutput( std::map< std::string, SelectableOutputFunction > & outputFunctions, const shared_ptr< const StructuredBlockStorage > & storage, const Config::BlockHandle & parentBlockHandle, const std::string & configBlockName, const std::vector< shared_ptr< BlockCellDataWriterInterface > > & _writers, const std::map< std::string, VTKOutput::CellFilter > & _filters, const std::map< std::string, VTKOutput::BeforeFunction > & _beforeFunctions ) { if( !parentBlockHandle ) WALBERLA_ABORT("Invalid Argument: parentBlockHandle not valid!"); std::map< std::string, shared_ptr< BlockCellDataWriterInterface >, CaseInsensitiveCompare > writers; std::map< std::string, VTKOutput::CellFilter, CaseInsensitiveCompare > globalFilters; std::map< std::string, VTKOutput::BeforeFunction, CaseInsensitiveCompare > beforeFunctions; for( auto writer = _writers.begin(); writer != _writers.end(); ++writer ) { if( writers.find( (*writer)->identifier() ) != writers.end() ) WALBERLA_ABORT( "There are at least two block data writers with identifier \"" << (*writer)->identifier() << "\" (test is case insensitive!).\nEvery writer must have a unique identifier!" ); writers[ (*writer)->identifier() ] = *writer; } for( auto filter = _filters.begin(); filter != _filters.end(); ++filter ) { if( globalFilters.find( filter->first ) != globalFilters.end() ) WALBERLA_ABORT( "There are at least two cell filters with identifier \"" << filter->first << "\" (test is case insensitive!).\nEvery filter must have a unique identifier!" ); globalFilters[ filter->first ] = filter->second; } for( auto function = _beforeFunctions.begin(); function != _beforeFunctions.end(); ++function ) { if( beforeFunctions.find( function->first ) != beforeFunctions.end() ) WALBERLA_ABORT( "There are at least two before functions with identifier \"" << function->first << "\" (test is case insensitive!).\nEvery function must have a unique identifier!" ); beforeFunctions[ function->first ] = function->second; } Config::BlockHandle vtkBlock = parentBlockHandle.getBlock( configBlockName ); if( !vtkBlock ) return; Config::Blocks blocks; vtkBlock.getBlocks( blocks ); for( auto block = blocks.begin(); block != blocks.end(); ++block ) { Config::Blocks subBlocks; block->getBlocks( subBlocks ); const std::string identifier( block->getKey() ); const int simultaneousIOOperations = block->getParameter< int >( "simultaneousIOOperations", 0 ); const uint_t writeFrequency = block->getParameter< uint_t >( "writeFrequency", uint_c(1) ); const uint_t initialExecutionCount = block->getParameter< uint_t >( "initialExecutionCount", uint_c(0) ); const bool forcePVTU = block->getParameter< bool >( "forcePVTU", false ); const uint_t ghostLayers = block->getParameter< uint_t >( "ghostLayers", uint_c(0) ); std::string baseFolder( block->getParameter< std::string >( "baseFolder", std::string( "vtk_out" ) ) ); std::string executionFolder( block->getParameter< std::string >( "executionFolder", std::string( "simulation_step" ) ) ); const bool outputDomainDecomposition = block->getParameter< bool >( "outputDomainDecomposition", false ); const bool continuousNumbering = block->getParameter< bool >( "continuousNumbering", false ); const bool binary = block->getParameter< bool >( "binary", true ); const bool littleEndian = block->getParameter< bool >( "littleEndian", true ); const bool useMPIIO = block->getParameter< bool >( "useMPIIO", true ); Config::BlockHandle writersBlock = block->getBlock( "writers" ); if( !writersBlock && !outputDomainDecomposition ) WALBERLA_ABORT( "You declared a VTK output instance [\"" << identifier << "\"] without a \"writers\" block. " "You have to specify at least on block data writer!" ); if( useMPIIO && simultaneousIOOperations > 0 ) { WALBERLA_LOG_WARNING( "In VTK output instance [\"" << identifier << "\"] you request the use of MPI I/O and " "specified \"simultaneousIOOperations\". Those two settings are incompatible. " "\"simultaneousIOOperations\" will be ignored!" ); } std::vector< shared_ptr< BlockCellDataWriterInterface > > selectedWriters; if( writersBlock ) { for( auto writerId = writersBlock.begin(); writerId != writersBlock.end(); ++writerId ) { if( writers.find( writerId->first ) != writers.end() ) selectedWriters.push_back( writers[ writerId->first ] ); else WALBERLA_ABORT( "You have requested a block data writer \"" << writerId->first << "\". This writer is not available!" ); } } if( selectedWriters.empty() && !outputDomainDecomposition ) WALBERLA_ABORT( "No block data writers could be selected for your VTK output instance [\"" << identifier << "\"]. " "Either you did not specify any writers or non of your specified writers are available." ); shared_ptr< VTKOutput > vtkOutput; if( outputDomainDecomposition ) vtkOutput = createVTKOutput_DomainDecomposition( *storage, identifier, writeFrequency, baseFolder, executionFolder, continuousNumbering, binary, littleEndian, useMPIIO, initialExecutionCount ); else vtkOutput = createVTKOutput_BlockData( *storage, identifier, writeFrequency, ghostLayers, forcePVTU, baseFolder, executionFolder, continuousNumbering, binary, littleEndian, useMPIIO, initialExecutionCount ); const uint_t initialWriteCallsToSkip = block->getParameter< uint_t >( "initialWriteCallsToSkip", uint_t(0) ); if( initialWriteCallsToSkip > uint_t(0) ) vtkOutput->setInitialWriteCallsToSkip( initialWriteCallsToSkip ); const real_t samplingResolution = block->getParameter< real_t >( "samplingResolution", real_c(-1) ); vtkOutput->setSamplingResolution( samplingResolution ); if( block->isDefined( "samplingDx" ) ) { const real_t samplingDx = block->getParameter< real_t >( "samplingDx", real_c(-1) ); const real_t samplingDy = block->getParameter< real_t >( "samplingDy", real_c(-1) ); const real_t samplingDz = block->getParameter< real_t >( "samplingDz", real_c(-1) ); vtkOutput->setSamplingResolution( samplingDx, samplingDy, samplingDz ); } Config::BlockHandle beforeFunctionsBlock = block->getBlock( "before_functions" ); if( beforeFunctionsBlock ) { for( auto beforeFunctionId = beforeFunctionsBlock.begin(); beforeFunctionId != beforeFunctionsBlock.end(); ++beforeFunctionId ) { if( beforeFunctions.find( beforeFunctionId->first ) != beforeFunctions.end() ) vtkOutput->addBeforeFunction( beforeFunctions[ beforeFunctionId->first ] ); else WALBERLA_ABORT( "You have requested a before function \"" << beforeFunctionId->first << "\". This function is not available!" ); } } std::map< std::string, VTKOutput::CellFilter, CaseInsensitiveCompare > filters( globalFilters ); Config::Blocks aabbBlocks; Config::Blocks cellBBBlocks; for( auto subBlock = subBlocks.begin(); subBlock != subBlocks.end(); ++subBlock ) { if( boost::algorithm::iequals( std::string( subBlock->getKey(), 0, 11 ), std::string("AABB_filter") ) ) aabbBlocks.push_back( *subBlock ); if( boost::algorithm::iequals( std::string( subBlock->getKey(), 0, 13 ), std::string("CellBB_filter") ) ) cellBBBlocks.push_back( *subBlock ); } for( auto aabb = aabbBlocks.begin(); aabb != aabbBlocks.end(); ++aabb ) { if( !aabb->isDefined("min") || !aabb->isDefined("max") ) WALBERLA_ABORT( "You must specify a \"min\" and a \"max\" coordinate for AABB cell filter \"" << aabb->getKey() << "\"." ); real_t xmin, ymin, zmin; splitVector< real_t >( xmin, ymin, zmin, *aabb, "min", std::string( "The \"min\" coordinate of AABB cell filter \"" ) + aabb->getKey() + std::string( "\" must be a three-dimensional vector." ) ); real_t xmax, ymax, zmax; splitVector< real_t >( xmax, ymax, zmax, *aabb, "max", std::string( "The \"max\" coordinate of AABB cell filter \"" ) + aabb->getKey() + std::string( "\" must be a three-dimensional vector." ) ); if( filters.find( aabb->getKey() ) != filters.end() ) WALBERLA_ABORT( "There are at least two cell filters with identifier \"" << aabb->getKey() << "\" (test is case insensitive!).\nEvery filter must have a unique identifier!" ); filters[ aabb->getKey() ] = AABBCellFilter( AABB( xmin, ymin, zmin, xmax, ymax, zmax ) ); } for( auto bb = cellBBBlocks.begin(); bb != cellBBBlocks.end(); ++bb ) { if( !bb->isDefined("min") || !bb->isDefined("max") ) WALBERLA_ABORT( "You must specify a \"min\" and a \"max\" coordinate for CellBB cell filter \"" << bb->getKey() << "\"." ); uint_t level = 0; if( bb->isDefined( "level" ) ) level = bb->getParameter< uint_t >( "level" ); cell_idx_t xmin, ymin, zmin; splitVector< cell_idx_t >( xmin, ymin, zmin, *bb, "min", std::string( "The \"min\" coordinate of CellBB cell filter \"" ) + bb->getKey() + std::string( "\" must be a three-dimensional vector." ) ); cell_idx_t xmax, ymax, zmax; splitVector< cell_idx_t >( xmax, ymax, zmax, *bb, "max", std::string( "The \"max\" coordinate of CellBB cell filter \"" ) + bb->getKey() + std::string( "\" must be a three-dimensional vector." ) ); if( filters.find( bb->getKey() ) != filters.end() ) WALBERLA_ABORT( "There are at least two cell filters with identifier \"" << bb->getKey() << "\" (test is case insensitive!).\nEvery filter must have a unique identifier!" ); filters[ bb->getKey() ] = CellBBCellFilter( CellInterval( xmin, ymin, zmin, xmax, ymax, zmax ), level ); } for( auto selectedWriter = selectedWriters.begin(); selectedWriter != selectedWriters.end(); ++selectedWriter ) vtkOutput->addCellDataWriter( *selectedWriter ); Config::BlockHandle inclusionFiltersBlock = block->getBlock( "inclusion_filters" ); if( inclusionFiltersBlock ) { for( auto inclusionFilterId = inclusionFiltersBlock.begin(); inclusionFilterId != inclusionFiltersBlock.end(); ++inclusionFilterId ) { if( inclusionFilterId->first.compare( "combine" ) == 0 ) { std::vector< std::string > filterList = splitList( inclusionFilterId->second ); ChainedFilter combine; for( auto filter = filterList.begin(); filter != filterList.end(); ++filter ) { if( filters.find( *filter ) != filters.end() ) combine.addFilter( filters[ *filter ] ); else WALBERLA_ABORT( "You have requested an inclusion cell filter \"" << *filter << "\". This filter is not available!" ); } vtkOutput->addCellInclusionFilter( combine ); } else { if( filters.find( inclusionFilterId->first ) != filters.end() ) vtkOutput->addCellInclusionFilter( filters[ inclusionFilterId->first ] ); else WALBERLA_ABORT( "You have requested an inclusion cell filter \"" << inclusionFilterId->first << "\". This filter is not available!" ); } } } Config::BlockHandle exclusionFiltersBlock = block->getBlock( "exclusion_filters" ); if( exclusionFiltersBlock ) { for( auto exclusionFilterId = exclusionFiltersBlock.begin(); exclusionFilterId != exclusionFiltersBlock.end(); ++exclusionFilterId ) { if( exclusionFilterId->first.compare( "combine" ) == 0 ) { std::vector< std::string > filterList = splitList( exclusionFilterId->second ); ChainedFilter combine; for( auto filter = filterList.begin(); filter != filterList.end(); ++filter ) { if( filters.find( *filter ) != filters.end() ) combine.addFilter( filters[ *filter ] ); else WALBERLA_ABORT( "You have requested an exclusion cell filter \"" << *filter << "\". This filter is not available!" ); } vtkOutput->addCellExclusionFilter( combine ); } else { if( filters.find( exclusionFilterId->first ) != filters.end() ) vtkOutput->addCellExclusionFilter( filters[ exclusionFilterId->first ] ); else WALBERLA_ABORT( "You have requested an exclusion cell filter \"" << exclusionFilterId->first << "\". This filter is not available!" ); } } } Set<SUID> requiredGlobalStates; if( block->isDefined( "requiredGlobalStates" ) ) { std::string states = block->getParameter< std::string >( "requiredGlobalStates" ); addStates( requiredGlobalStates, states ); } Set<SUID> incompatibleGlobalStates; if( block->isDefined( "incompatibleGlobalStates" ) ) { std::string states = block->getParameter< std::string >( "incompatibleGlobalStates" ); addStates( incompatibleGlobalStates, states ); } Set<SUID> requiredBlockStates; if( block->isDefined( "requiredBlockStates" ) ) { std::string states = block->getParameter< std::string >( "requiredBlockStates" ); addStates( requiredBlockStates, states ); } Set<SUID> incompatibleBlockStates; if( block->isDefined( "incompatibleBlockStates" ) ) { std::string states = block->getParameter< std::string >( "incompatibleBlockStates" ); addStates( incompatibleBlockStates, states ); } outputFunctions[ identifier ] = SelectableOutputFunction( writeFiles( vtkOutput, true, simultaneousIOOperations, requiredGlobalStates + requiredBlockStates, incompatibleGlobalStates + incompatibleBlockStates ), requiredGlobalStates, incompatibleGlobalStates ); } } void initializeVTKOutput( std::map< std::string, SelectableOutputFunction > & outputFunctions, const shared_ptr< const StructuredBlockStorage > & storage, const shared_ptr< Config > & config, const std::vector< shared_ptr< BlockCellDataWriterInterface > > & writers, const std::map< std::string, VTKOutput::CellFilter > & filters, const std::map< std::string, VTKOutput::BeforeFunction > & beforeFunctions ) { if( !!config ) initializeVTKOutput( outputFunctions, storage, config->getGlobalBlock(), "VTK", writers, filters, beforeFunctions ); } void initializeVTKOutput( std::map< std::string, SelectableOutputFunction > & outputFunctions, const shared_ptr< const StructuredBlockStorage > & storage, const Config::BlockHandle & parentBlockHandle, const std::vector< shared_ptr< BlockCellDataWriterInterface > > & writers, const std::map< std::string, VTKOutput::CellFilter > & filters, const std::map< std::string, VTKOutput::BeforeFunction > & beforeFunctions ) { initializeVTKOutput( outputFunctions, storage, parentBlockHandle, "VTK", writers, filters, beforeFunctions ); } //********************************************************************************************************************** /*! * \brief Function for initializing VTKOutput objects from file and creating their corresponding output functions * * This initialization function reads data stored in a configuration file, uses this data to create VTKOutput objects, * and finally constructs corresponding output functions which then are returned via the parameter "outputFunctions". * The returned output functions all have the signature "void (void)". Calling such an output function initiates one * output of the associated VTKOutput object. * * \section docVTKConfigurationFile VTK via Configuration File * * For reading VTK setup information from a configuration file, the structure of the configuration file must look * like as follows: * * \code * VTK // every sub block of VTK corresponds to one VTKOutput object that is created * { * [name] // identifier for this VTKOutput object * { * simultaneousIOOperations [integer value]; // max. number of files that are written * // in parallel (optional, default=0 [=disabled]) * * initialExecutionCount [integer value]; // optional, default=0 * initialWriteCallsToSkip [integer value]; // optional, default=0 * writeFrequency [integer value]; // output frequency = number of times "writeBlocks" must be * // called for triggering an output (optional, default=1) * // 0 disables output * forcePVTU [boolean]; // if true, (P)VTU files are created, and not (P)VTI files * // (optional, default=false) * ghostLayers [integer value]; // number of ghost layers (optional, default=0) * * baseFolder [directory]; // base directory (optional, default=vtk_out) * executionFolder [directory]; // base directory for each time step, directory path is given relative * // to baseFolder (optional, default=simulation_step) * * outputDomainDecomposition [boolean]; // if true, the domain decomposition is written to file * // specifying cell filters and block cell data writers is * // not allowed! (optional, default=false) * continuousNumbering [boolean]; // if false, the actual time step is preserved * // (optional, default=false) * binary [boolean]; // if false, ascii files are written (optional, default=true) * littleEndian [boolean]; // switch between little and big endianness (optional, default=true) * * useMPIIO [boolean]; // use MPI I/O to write only one file per time step * // (optional, default=true) * * // You can either specify "samplingResolution" or "samplingDx", "samplingDy", and "samplingDz" * samplingResolution [floating point value]; // "samplingResolution VALUE" has the same effect as * // setting "samplingDx", "samplingDy", and "samplingDz" to VALUE * samplingDx [floating point value]; // forces the output to use this dx (= cell x-spacing) * samplingDy [floating point value]; // forces the output to use this dy (= cell y-spacing) * samplingDz [floating point value]; // forces the output to use this dz (= cell z-spacing) * * before_functions // (OPTIONAL, APPLICATION-DEPENDENT!) * { * [NameOfTheFirstFunction]; // the mapping of this name to a function pointer/functor is * [NameOfTheSecondFunction]; // done by the RegisterVTKOutputFunction "registerVTKOutputFunction" * [...] // which must be implemented by the user * } * * // AABB filters are OPTIONAL. AABB filters are sub blocks that must start with "AABB_filter". * // AABB filters can be selected as either inclusion or exclusion filters. In order to select an * // AABB filter "AABB_filter_XXX" as inclusion/exclusion filter, its name/identifier (in this * // example: "AABB_filter_XXX") must be added to the list of inclusion/exclusion filters in * // the sub block inclusion_filters/inclusion_filters. * * AABB_filter_0 * { * min < [x: floating point value], [y: floating point value], [z: floating point value] >; * max < [x: floating point value], [y: floating point value], [z: floating point value] >; * } * // AABB_filter_1 * // { * // min < [x: floating point value], [y: floating point value], [z: floating point value] >; * // max < [x: floating point value], [y: floating point value], [z: floating point value] >; * // } * // AABB_filter_2 { ... } * // AABB_filter_* { ... } * * // CellBB filters are OPTIONAL. CellBB filters are sub blocks that must start with "CellBB_filter". * // CellBB filters can be selected as either inclusion or exclusion filters. In order to select an * // CellBB filter "CellBB_filter_XXX" as inclusion/exclusion filter, its name/identifier (in this * // example: "CellBB_filter_XXX") must be added to the list of inclusion/exclusion filters in * // the sub block inclusion_filters/inclusion_filters. * // CellBB filters are AABB filters that are defined using discrete (!) global cell coordinates. * * CellBB_filter_0 * { * level [integer value]; // the cell level to which the following coordinates correspond to * // (optional, default=0) * min < [x: integer value], [y: integer value], [z: integer value] >; * max < [x: integer value], [y: integer value], [z: integer value] >; * } * // CellBB_filter_1 * // { * // min < [x: integer value], [y: integer value], [z: integer value] >; * // max < [x: integer value], [y: integer value], [z: integer value] >; * // } * // CellBB_filter_2 { ... } * // CellBB_filter_* { ... } * * // In terms of set theory: all filters listed as inclusion filters are "added" together, * // resulting in a union of all filters. * * inclusion_filters // (OPTIONAL, APPLICATION-DEPENDENT!) * { * [NameOfTheFirstFilter]; // the mapping of this name to an inclusion filter is * [NameOfTheSecondFilter]; // done by the RegisterVTKOutputFunction "registerVTKOutputFunction" * [...] // which must be implemented by the user * * // In terms of set theory: combining filters results in an intersection of these filters. * combine [NameOfAFilter],[NameOfAnotherFilter],[NameOfYetAnotherFilter],[...]; * } * * // In terms of set theory: all filters listed as exclusion filters are "added" together, * // resulting in a union of all filters. * * exclusion_filters // (OPTIONAL, APPLICATION-DEPENDENT!) * { * [NameOfTheFirstFilter]; // the mapping of this name to an exclusion filter is * [NameOfTheSecondFilter]; // done by the RegisterVTKOutputFunction "registerVTKOutputFunction" * [...] // which must be implemented by the user * * // In terms of set theory: combining filters results in an intersection of these filters. * combine [NameOfAFilter],[NameOfAnotherFilter],[NameOfYetAnotherFilter],[...]; * } * * writers // (AT LEAST ONE IS MANDATORY [exception: if outputDomainDecomposition == true, * // no writers are allowed!], APPLICATION-DEPENDENT!) * { * [NameOfTheFirstWriter]; // the mapping of this name to a writer is * [NameOfTheSecondWriter]; // done by the RegisterVTKOutputFunction "registerVTKOutputFunction" * [...] // which must be implemented by the user * } * * requiredGlobalStates [SUID identifier #1], [SUID identifier #2], ...; // (optional, default=[none]) * incompatibleGlobalStates [SUID identifier #1], [SUID identifier #2], ...; // (optional, default=[none]) * requiredBlockStates [SUID identifier #1], [SUID identifier #2], ...; // (optional, default=[none]) * incompatibleBlockStates [SUID identifier #1], [SUID identifier #2], ...; // (optional, default=[none]) * } * * [name of another VTK output object] * { * [...] * } * * } // VTK * \endcode * * \param outputFunctions The output functions which correspond to the just created VTKOutput objects * \param registerVTKOutputFunction A boost function / function pointer that the user must provide and that is used for * registering cell filters and block data writers which then can be referenced in the * configuration file and which are used to assemble the VTKOutput objects * \param storage The structured block storage the VTKOutput object shall be associated with * \param config The configuration * \param configBlockName Name of the block in the configuration that is used to setup the VTK output */ //********************************************************************************************************************** void initializeVTKOutput( std::map< std::string, SelectableOutputFunction > & outputFunctions, RegisterVTKOutputFunction registerVTKOutputFunction, const shared_ptr< const StructuredBlockStorage > & storage, const shared_ptr< Config > & config, const std::string & configBlockName ) { if( !!config ) initializeVTKOutput( outputFunctions, registerVTKOutputFunction, storage, config->getGlobalBlock(), configBlockName ); } void initializeVTKOutput( std::map< std::string, SelectableOutputFunction > & outputFunctions, RegisterVTKOutputFunction registerVTKOutputFunction, const shared_ptr< const StructuredBlockStorage > & storage, const Config::BlockHandle & parentBlockHandle, const std::string & configBlockName ) { std::vector< shared_ptr< BlockCellDataWriterInterface > > _writers; std::map< std::string, VTKOutput::CellFilter > _filters; std::map< std::string, VTKOutput::BeforeFunction > _beforeFunctions; registerVTKOutputFunction( _writers, _filters, _beforeFunctions ); initializeVTKOutput( outputFunctions, storage, parentBlockHandle, configBlockName, _writers, _filters, _beforeFunctions ); } } // namespace vtk } // namespace walberla