Commit 9f62e965 authored by Andreas Wagner's avatar Andreas Wagner
Browse files

Merge branch 'master' into wagnandr/facedoffunction

parents 975c5a81 0aa1b95e
......@@ -68,23 +68,28 @@ void syncVectorFunctionBetweenPrimitives( const P2VectorFunction< vType >& vecFu
}
template void syncP2FunctionBetweenPrimitives( const P2Function< double >& function, const uint_t& level );
template void syncP2FunctionBetweenPrimitives( const P2Function< int >& function, const uint_t& level );
template void syncP2FunctionBetweenPrimitives( const P2Function< int32_t >& function, const uint_t& level );
template void syncP2FunctionBetweenPrimitives( const P2Function< int64_t >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const vertexdof::VertexDoFFunction< double >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const vertexdof::VertexDoFFunction< int >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const vertexdof::VertexDoFFunction< long >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const vertexdof::VertexDoFFunction< int32_t >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const vertexdof::VertexDoFFunction< int64_t >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const EdgeDoFFunction< double >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const EdgeDoFFunction< int >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const EdgeDoFFunction< long >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const EdgeDoFFunction< int32_t >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const EdgeDoFFunction< int64_t >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const P2Function< double >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const P2Function< int >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const P2Function< int32_t >& function, const uint_t& level );
template void syncFunctionBetweenPrimitives( const P2Function< int64_t >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P1VectorFunction< real_t >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P2VectorFunction< real_t >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P1VectorFunction< double >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P1VectorFunction< int32_t >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P1VectorFunction< int64_t >& function, const uint_t& level );
//template void syncFunctionBetweenPrimitives( const P1Function<double>& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P2VectorFunction< double >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P2VectorFunction< int32_t >& function, const uint_t& level );
template void syncVectorFunctionBetweenPrimitives( const P2VectorFunction< int64_t >& function, const uint_t& level );
} // namespace communication
} // namespace hyteg
......@@ -57,40 +57,63 @@ void VTKDGDoFWriter::write( const VTKOutput& mgr, std::ostream& output, const ui
output << "<CellData>";
for ( const auto& function : mgr.dgFunctions_ )
for ( const auto& function : mgr.dgFunctions_.getFunctions< double >() )
{
vtk::openDataElement( output, typeToString< real_t >(), function.getFunctionName(), 1, mgr.vtkDataFormat_ );
writeScalarFunction( output, function, storage, level, mgr.write2D_, mgr.vtkDataFormat_ );
}
for ( const auto& function : mgr.dgFunctions_.getFunctions< int32_t >() )
{
writeScalarFunction( output, function, storage, level, mgr.write2D_, mgr.vtkDataFormat_ );
}
for ( const auto& function : mgr.dgFunctions_.getFunctions< int64_t >() )
{
writeScalarFunction( output, function, storage, level, mgr.write2D_, mgr.vtkDataFormat_ );
}
for ( const auto& it : storage->getFaces() )
{
const Face& face = *it.second;
output << "\n</CellData>\n";
vtk::writePieceFooter( output );
}
template < typename value_t >
void VTKDGDoFWriter::writeScalarFunction( std::ostream& output,
const DGFunction< value_t >& function,
const std::shared_ptr< PrimitiveStorage >& storage,
const uint_t& level,
bool write2D,
vtk::DataFormat vtkDataFormat )
{
uint_t rowsize = levelinfo::num_microvertices_per_edge( level );
uint_t inner_rowsize = rowsize;
output << std::scientific;
// hopefully at some point we will have DGFunctions also in 3D :)
WALBERLA_UNUSED( write2D );
uint_t idx;
vtk::openDataElement( output, typeToString< real_t >(), function.getFunctionName(), 1, vtkDataFormat );
for ( size_t j = 0; j < rowsize - 1; ++j )
for ( const auto& it : storage->getFaces() )
{
const Face& face = *it.second;
uint_t rowsize = levelinfo::num_microvertices_per_edge( level );
uint_t inner_rowsize = rowsize;
output << std::scientific;
uint_t idx;
for ( size_t j = 0; j < rowsize - 1; ++j )
{
for ( size_t i = 0; i < inner_rowsize - 2; ++i )
{
for ( size_t i = 0; i < inner_rowsize - 2; ++i )
{
idx = facedof::macroface::indexFaceFromGrayFace( level, i, j, stencilDirection::CELL_GRAY_C );
output << face.getData( function.getFaceDataID() )->getPointer( level )[idx] << " ";
idx = facedof::macroface::indexFaceFromBlueFace( level, i, j, stencilDirection::CELL_BLUE_C );
output << face.getData( function.getFaceDataID() )->getPointer( level )[idx] << " ";
}
idx = facedof::macroface::indexFaceFromGrayFace( level, inner_rowsize - 2, j, stencilDirection::CELL_GRAY_C );
idx = facedof::macroface::indexFaceFromGrayFace( level, i, j, stencilDirection::CELL_GRAY_C );
output << face.getData( function.getFaceDataID() )->getPointer( level )[idx] << " ";
idx = facedof::macroface::indexFaceFromBlueFace( level, i, j, stencilDirection::CELL_BLUE_C );
output << face.getData( function.getFaceDataID() )->getPointer( level )[idx] << " ";
--inner_rowsize;
}
idx = facedof::macroface::indexFaceFromGrayFace( level, inner_rowsize - 2, j, stencilDirection::CELL_GRAY_C );
output << face.getData( function.getFaceDataID() )->getPointer( level )[idx] << " ";
--inner_rowsize;
}
output << "\n</DataArray>\n";
}
output << "\n</CellData>\n";
vtk::writePieceFooter( output );
output << "\n</DataArray>\n";
}
} // namespace hyteg
......@@ -29,6 +29,15 @@ class VTKDGDoFWriter
{
public:
static void write( const VTKOutput& mgr, std::ostream& output, const uint_t& level );
private:
template < typename value_t >
static void writeScalarFunction( std::ostream& output,
const DGFunction< value_t >& function,
const std::shared_ptr< PrimitiveStorage >& storage,
const uint_t& level,
bool write2D,
vtk::DataFormat vtkDataFormat );
};
} // namespace hyteg
......@@ -81,13 +81,17 @@ void VTKEdgeDoFWriter::write( const VTKOutput& mgr, std::ostream& output, uint_t
output << "<PointData>\n";
for ( const auto& function : mgr.edgeDoFFunctions_ )
for ( const auto& function : mgr.edgeDoFFunctions_.getFunctions< double >() )
{
writeScalarFunction( mgr, output, function, storage, level, dofType );
}
for ( const auto& function : mgr.edgeDoFFunctions_.getFunctions< int32_t >() )
{
writeScalarFunction( mgr, output, function, storage, level, dofType );
}
for ( const auto& function : mgr.edgeDoFFunctions_.getFunctions< int64_t >() )
{
vtk::openDataElement( output, typeToString< real_t >(), function.getFunctionName(), 1, mgr.vtkDataFormat_ );
writeScalarFunction( mgr, output, function, storage, level, dofType );
output << "\n</DataArray>\n";
}
output << "</PointData>\n";
......@@ -107,20 +111,23 @@ void VTKEdgeDoFWriter::write( const VTKOutput& mgr, std::ostream& output, uint_t
vtk::writePieceFooter( output );
}
template < typename value_t >
void VTKEdgeDoFWriter::writeScalarFunction( const VTKOutput& mgr,
std::ostream& output,
const EdgeDoFFunction< real_t >& function,
const EdgeDoFFunction< value_t >& function,
const std::shared_ptr< PrimitiveStorage >& storage,
uint_t level,
const vtk::DoFType& dofType )
{
using ScalarType = real_t;
WALBERLA_ASSERT_EQUAL( storage, function.getStorage() );
vtk::openDataElement( output, typeToString< value_t >(), function.getFunctionName(), 1, mgr.vtkDataFormat_ );
WALBERLA_ASSERT( dofType == vtk::DoFType::EDGE_X || dofType == vtk::DoFType::EDGE_Y || dofType == vtk::DoFType::EDGE_Z ||
dofType == vtk::DoFType::EDGE_XY || dofType == vtk::DoFType::EDGE_XZ || dofType == vtk::DoFType::EDGE_YZ ||
dofType == vtk::DoFType::EDGE_XYZ );
VTKOutput::VTKStreamWriter< ScalarType > streamWriter( mgr.vtkDataFormat_ );
VTKOutput::VTKStreamWriter< value_t > streamWriter( mgr.vtkDataFormat_ );
if ( mgr.write2D_ )
{
......@@ -130,8 +137,7 @@ void VTKEdgeDoFWriter::writeScalarFunction( const VTKOutput&
switch ( dofType )
{
case vtk::DoFType::EDGE_X:
{
case vtk::DoFType::EDGE_X: {
for ( const auto& itIdx : edgedof::macroface::Iterator( level ) )
{
streamWriter << face.getData( function.getFaceDataID() )
......@@ -139,8 +145,7 @@ void VTKEdgeDoFWriter::writeScalarFunction( const VTKOutput&
}
break;
}
case vtk::DoFType::EDGE_Y:
{
case vtk::DoFType::EDGE_Y: {
for ( const auto& itIdx : edgedof::macroface::Iterator( level ) )
{
streamWriter << face.getData( function.getFaceDataID() )
......@@ -148,8 +153,7 @@ void VTKEdgeDoFWriter::writeScalarFunction( const VTKOutput&
}
break;
}
case vtk::DoFType::EDGE_XY:
{
case vtk::DoFType::EDGE_XY: {
for ( const auto& itIdx : edgedof::macroface::Iterator( level ) )
{
streamWriter << face.getData( function.getFaceDataID() )
......@@ -213,6 +217,8 @@ void VTKEdgeDoFWriter::writeScalarFunction( const VTKOutput&
}
streamWriter.toStream( output );
output << "\n</DataArray>\n";
}
} // namespace hyteg
......@@ -38,9 +38,10 @@ class VTKEdgeDoFWriter
static void write( const VTKOutput& mgr, std::ostream& output, uint_t level, const vtk::DoFType& dofType );
private:
template < typename value_t >
static void writeScalarFunction( const VTKOutput& mgr,
std::ostream& output,
const EdgeDoFFunction< real_t >& function,
const EdgeDoFFunction< value_t >& function,
const std::shared_ptr< PrimitiveStorage >& storage,
uint_t level,
const vtk::DoFType& dofType );
......
......@@ -49,7 +49,7 @@ inline void writeXMLHeader( std::ostream& output )
{
output << "<?xml version=\"1.0\"?>\n";
output << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\">\n";
output << " <UnstructuredGrid>\n";
output << "<UnstructuredGrid>\n";
}
}
......@@ -57,7 +57,7 @@ inline void writeXMLFooter( std::ostream& output )
{
WALBERLA_ROOT_SECTION()
{
output << " </UnstructuredGrid>\n";
output << "</UnstructuredGrid>\n";
output << "</VTKFile>\n";
}
}
......
......@@ -61,36 +61,6 @@ VTKOutput::VTKOutput( std::string dir,
}
}
void VTKOutput::add( const P2Function< real_t >& function )
{
p2Functions_.push_back( function );
}
void VTKOutput::add( const P1VectorFunction< real_t >& function )
{
p1VecFunctions_.push_back( function );
}
void VTKOutput::add( const P2VectorFunction< real_t >& function )
{
p2VecFunctions_.push_back( function );
}
void VTKOutput::add( const P1Function< real_t >& function )
{
p1Functions_.push_back( function );
}
void VTKOutput::add( const EdgeDoFFunction< real_t >& function )
{
edgeDoFFunctions_.push_back( function );
}
void VTKOutput::add( const DGFunction< real_t >& function )
{
dgFunctions_.push_back( function );
}
void VTKOutput::add( const P1StokesFunction< real_t >& function )
{
add( function.uvw );
......@@ -103,41 +73,34 @@ void VTKOutput::add( const P2P1TaylorHoodFunction< real_t >& function )
add( function.p );
}
void VTKOutput::add( const BlockFunction< real_t >& function )
{
for ( uint_t k = 0; k < function.getNumberOfBlocks(); k++ )
{
add( function[k] );
}
}
void VTKOutput::add( const GenericFunction< real_t >& function )
template < typename value_t >
void VTKOutput::add( const GenericFunction< value_t >& function )
{
bool matchFound = false;
switch ( function.getFunctionKind() )
{
case functionTraits::P1_FUNCTION:
matchFound = tryUnwrapAndAdd< FunctionWrapper< P1Function< real_t > > >( function );
matchFound = tryUnwrapAndAdd< FunctionWrapper< P1Function< value_t > > >( function );
break;
case functionTraits::P2_FUNCTION:
matchFound = tryUnwrapAndAdd< FunctionWrapper< P2Function< real_t > > >( function );
matchFound = tryUnwrapAndAdd< FunctionWrapper< P2Function< value_t > > >( function );
break;
case functionTraits::P1_VECTOR_FUNCTION:
matchFound = tryUnwrapAndAdd< FunctionWrapper< P1VectorFunction< real_t > > >( function );
matchFound = tryUnwrapAndAdd< FunctionWrapper< P1VectorFunction< value_t > > >( function );
break;
case functionTraits::P2_VECTOR_FUNCTION:
matchFound = tryUnwrapAndAdd< FunctionWrapper< P2VectorFunction< real_t > > >( function );
matchFound = tryUnwrapAndAdd< FunctionWrapper< P2VectorFunction< value_t > > >( function );
break;
case functionTraits::EDGE_DOF_FUNCTION:
matchFound = tryUnwrapAndAdd< FunctionWrapper< EdgeDoFFunction< real_t > > >( function );
matchFound = tryUnwrapAndAdd< FunctionWrapper< EdgeDoFFunction< value_t > > >( function );
break;
case functionTraits::DG_FUNCTION:
matchFound = tryUnwrapAndAdd< FunctionWrapper< DGFunction< real_t > > >( function );
matchFound = tryUnwrapAndAdd< FunctionWrapper< DGFunction< value_t > > >( function );
break;
default:
......@@ -151,16 +114,16 @@ void VTKOutput::add( const GenericFunction< real_t >& function )
}
const std::map< vtk::DoFType, std::string > VTKOutput::DoFTypeToString_ = {
{vtk::DoFType::VERTEX, "VertexDoF"},
{vtk::DoFType::EDGE_X, "XEdgeDoF"},
{vtk::DoFType::EDGE_Y, "YEdgeDoF"},
{vtk::DoFType::EDGE_Z, "ZEdgeDoF"},
{vtk::DoFType::EDGE_XY, "XYEdgeDoF"},
{vtk::DoFType::EDGE_XZ, "XZEdgeDoF"},
{vtk::DoFType::EDGE_YZ, "YZEdgeDoF"},
{vtk::DoFType::EDGE_XYZ, "XYZEdgeDoF"},
{vtk::DoFType::DG, "DGDoF"},
{vtk::DoFType::P2, "P2"},
{ vtk::DoFType::VERTEX, "VertexDoF" },
{ vtk::DoFType::EDGE_X, "XEdgeDoF" },
{ vtk::DoFType::EDGE_Y, "YEdgeDoF" },
{ vtk::DoFType::EDGE_Z, "ZEdgeDoF" },
{ vtk::DoFType::EDGE_XY, "XYEdgeDoF" },
{ vtk::DoFType::EDGE_XZ, "XZEdgeDoF" },
{ vtk::DoFType::EDGE_YZ, "YZEdgeDoF" },
{ vtk::DoFType::EDGE_XYZ, "XYZEdgeDoF" },
{ vtk::DoFType::DG, "DGDoF" },
{ vtk::DoFType::P2, "P2" },
};
std::string VTKOutput::fileNameExtension( const vtk::DoFType& dofType, const uint_t& level, const uint_t& timestep ) const
......@@ -235,23 +198,23 @@ void VTKOutput::write( const uint_t& level, const uint_t& timestep ) const
{
syncAllFunctions( level );
const std::vector< vtk::DoFType > dofTypes2D = {vtk::DoFType::VERTEX,
vtk::DoFType::EDGE_X,
vtk::DoFType::EDGE_Y,
vtk::DoFType::EDGE_XY,
vtk::DoFType::DG,
vtk::DoFType::P2};
const std::vector< vtk::DoFType > dofTypes3D = {vtk::DoFType::VERTEX,
vtk::DoFType::EDGE_X,
vtk::DoFType::EDGE_Y,
vtk::DoFType::EDGE_Z,
vtk::DoFType::EDGE_XY,
vtk::DoFType::EDGE_XZ,
vtk::DoFType::EDGE_YZ,
vtk::DoFType::EDGE_XYZ,
vtk::DoFType::DG,
vtk::DoFType::P2};
const std::vector< vtk::DoFType > dofTypes2D = { vtk::DoFType::VERTEX,
vtk::DoFType::EDGE_X,
vtk::DoFType::EDGE_Y,
vtk::DoFType::EDGE_XY,
vtk::DoFType::DG,
vtk::DoFType::P2 };
const std::vector< vtk::DoFType > dofTypes3D = { vtk::DoFType::VERTEX,
vtk::DoFType::EDGE_X,
vtk::DoFType::EDGE_Y,
vtk::DoFType::EDGE_Z,
vtk::DoFType::EDGE_XY,
vtk::DoFType::EDGE_XZ,
vtk::DoFType::EDGE_YZ,
vtk::DoFType::EDGE_XYZ,
vtk::DoFType::DG,
vtk::DoFType::P2 };
auto dofTypes = write2D_ ? dofTypes2D : dofTypes3D;
......@@ -288,36 +251,111 @@ void VTKOutput::write( const uint_t& level, const uint_t& timestep ) const
void VTKOutput::syncAllFunctions( const uint_t& level ) const
{
for ( const auto& function : p1Functions_ )
// ----------------------------------------
// P1Functions [double, int32_t, int64_t]
// ----------------------------------------
for ( const auto& function : p1Functions_.getFunctions< double >() )
{
hyteg::communication::syncFunctionBetweenPrimitives< hyteg::P1Function< double > >( function, level );
}
for ( const auto& function : p1Functions_.getFunctions< int32_t >() )
{
hyteg::communication::syncFunctionBetweenPrimitives< hyteg::P1Function< real_t > >( function, level );
hyteg::communication::syncFunctionBetweenPrimitives< hyteg::P1Function< int32_t > >( function, level );
}
for ( const auto& function : p1Functions_.getFunctions< int64_t >() )
{
hyteg::communication::syncFunctionBetweenPrimitives< hyteg::P1Function< int64_t > >( function, level );
}
for ( const auto& function : p1VecFunctions_ )
// ----------------------------------------------
// P1VectorFunctions [double, int32_t, int64_t]
// ----------------------------------------------
for ( const auto& function : p1VecFunctions_.getFunctions< double >() )
{
hyteg::communication::syncVectorFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p1VecFunctions_.getFunctions< int32_t >() )
{
hyteg::communication::syncVectorFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p1VecFunctions_.getFunctions< int64_t >() )
{
hyteg::communication::syncVectorFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p2Functions_ )
// ----------------------------------------
// P2Functions [double, int32_t, int64_t]
// ----------------------------------------
for ( const auto& function : p2Functions_.getFunctions< double >() )
{
hyteg::communication::syncP2FunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p2Functions_.getFunctions< int32_t >() )
{
hyteg::communication::syncP2FunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p2Functions_.getFunctions< int64_t >() )
{
hyteg::communication::syncP2FunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p2VecFunctions_ )
// ----------------------------------------------
// P2VectorFunctions [double, int32_t, int64_t]
// ----------------------------------------------
for ( const auto& function : p2VecFunctions_.getFunctions< double >() )
{
hyteg::communication::syncVectorFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p2VecFunctions_.getFunctions< int32_t >() )
{
hyteg::communication::syncVectorFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : p2VecFunctions_.getFunctions< int64_t >() )
{
hyteg::communication::syncVectorFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : edgeDoFFunctions_ )
// ---------------------------------------------
// EdgeDoFFunctions [double, int32_t, int64_t]
// ---------------------------------------------
for ( const auto& function : edgeDoFFunctions_.getFunctions< double >() )
{
hyteg::communication::syncFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : edgeDoFFunctions_.getFunctions< int32_t >() )
{
hyteg::communication::syncFunctionBetweenPrimitives< hyteg::EdgeDoFFunction< real_t > >( function, level );
hyteg::communication::syncFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : edgeDoFFunctions_.getFunctions< int64_t >() )
{
hyteg::communication::syncFunctionBetweenPrimitives( function, level );
}
for ( const auto& function : dgFunctions_ )
// ----------------------------------------
// DGFunctions [double, int32_t, int64_t]
// ----------------------------------------
for ( const auto& function : dgFunctions_.getFunctions< double >() )
{
function.communicate< Vertex, Edge >( level );
function.communicate< Edge, Face >( level );
}
for ( const auto& function : dgFunctions_.getFunctions< int32_t >() )
{
function.communicate< Vertex, Edge >( level );
function.communicate< Edge, Face >( level );
}
for ( const auto& function : dgFunctions_.getFunctions< int64_t >() )
{
function.communicate< Vertex, Edge >( level );
function.communicate< Edge, Face >( level );
}
}
// -------------------------
// Explicit Instantiations
// -------------------------
template void VTKOutput::add( const GenericFunction< double >& function );
template void VTKOutput::add( const GenericFunction< int32_t >& function );
template void VTKOutput::add( const GenericFunction< int64_t >& function );
} // namespace hyteg
......@@ -31,13 +31,19 @@
#include "hyteg/dgfunctionspace/DGFunction.hpp"
#include "hyteg/edgedofspace/EdgeDoFFunction.hpp"
#include "hyteg/functions/BlockFunction.hpp"
#include "hyteg/functions/FunctionMultiStore.hpp"
#include "hyteg/p1functionspace/P1Function.hpp"
#include "hyteg/p2functionspace/P2Function.hpp"
// our friends and helpers
// clang off
// ordering matter here, otherwise we need to add forward declarations
#include "hyteg/dataexport/VTKHelpers.hpp"
// clang on
#include "hyteg/dataexport/VTKDGDoFWriter.hpp"
#include "hyteg/dataexport/VTKEdgeDoFWriter.hpp"
#include "hyteg/dataexport/VTKHelpers.hpp"
#include "hyteg/dataexport/VTKMeshWriter.hpp"
#include "hyteg/dataexport/VTKP1Writer.hpp"
#include "hyteg/dataexport/VTKP2Writer.hpp"
......@@ -70,21 +76,57 @@ class VTKOutput
void setVTKDataFormat( vtk::DataFormat vtkDataFormat ) { vtkDataFormat_ = vtkDataFormat; }
void add( const P1Function< real_t >& function );
void add( const P2Function< real_t >& function );
template < typename value_t >
inline void add( const P1Function< value_t >& function )
{
p1Functions_.push_back( function );
}
template < typename value_t >
inline void add( const P2Function< value_t >& function )
{
p2Functions_.push_back( function );
}
template < typename value_t >
inline void add( const P1VectorFunction< value_t >& function )
{
p1VecFunctions_.push_back( function );
}
template < typename value_t >
inline void add( const P2VectorFunction< value_t >& function )