Commit 801badd8 authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Allow argument to Function and FieldInfo be passed in arbitrary order

Use RangeTypes to determine name of first Scalars, Vectors, or Tensors DataArray
parent acbaf624
......@@ -4,9 +4,11 @@
#include <type_traits>
#include <dune/common/typetraits.hh>
#include <dune/common/version.hh>
#include "localfunction.hh"
#include "types.hh"
#include "utility/arguments.hh"
namespace Dune
{
......@@ -27,7 +29,7 @@ namespace Dune
using LocalFunction = decltype(localFunction(std::declval<F>()));
template <class LF, class E>
using HasBind = decltype(std::declval<LF>().bind(std::declval<E>()));
using HasBind = decltype(std::declval<std::decay_t<LF>&>().bind(std::declval<E>()));
using Element = typename GridView::template Codim<0>::Entity;
using LocalDomain = typename Element::Geometry::LocalCoordinate;
......@@ -61,23 +63,23 @@ namespace Dune
* \param localFct A local-function, providing a `bind(Element)` and an `operator()(LocalDomain)`
* \param name The name to use as identification in the VTK file
* \param components A vector of component indices to extract from the range type
* \param category The type category for the range, i.e., vector, tensor or unspecified [AUTO]
* \param dataType The \ref Vtk::DataTypes used in the output. [FLOAT32]
* \param category The \ref Vtk::RangeTypes category for the range. [Vtk::RangeTypes::AUTO]
* \param dataType The \ref Vtk::DataTypes used in the output. [Vtk::DataTypes::FLOAT32]
*
* The arguments `category` and `dataType` can be passed in any order.
*
* NOTE: Stores the localFunction by value.
**/
template <class LF,
template <class LF, class... Args,
class = void_t<HasBind<LF,Element>>,
class R = Range<LF,LocalDomain> >
Function (LF&& localFct, std::string name, std::vector<int> components,
Vtk::RangeTypes rangeType = Vtk::RangeTypes::AUTO,
Vtk::DataTypes dataType = Vtk::DataTypes::FLOAT32)
Function (LF&& localFct, std::string name, std::vector<int> components, Args const&... args)
: localFct_(std::forward<LF>(localFct))
, name_(std::move(name))
{
setComponents(std::move(components));
setRangeType(rangeType == Vtk::RangeTypes::AUTO ? rangeTypeOf(components.size()) : rangeType);
setDataType(dataType);
setRangeType(getArg<Vtk::RangeTypes>(args..., Vtk::RangeTypes::AUTO), components_.size());
setDataType(getArg<Vtk::DataTypes>(args..., Vtk::DataTypes::FLOAT32));
}
/// (2) Construct from a LocalFunction directly
......@@ -94,11 +96,23 @@ namespace Dune
template <class LF, class... Args,
class = void_t<HasBind<LF,Element>>,
class R = Range<LF,LocalDomain> >
Function (LF&& localFct, std::string name, int ncomps = sizeOf<R>(), Args&&... args)
: Function(std::forward<LF>(localFct), std::move(name), allComponents(ncomps), std::forward<Args>(args)...)
Function (LF&& localFct, std::string name, Args const&... args)
: Function(std::forward<LF>(localFct), std::move(name),
allComponents(getArg<int,unsigned int,long,unsigned long>(args..., sizeOf<R>())),
getArg<Vtk::RangeTypes>(args..., Vtk::RangeTypes::AUTO),
getArg<Vtk::DataTypes>(args..., Vtk::DataTypes::FLOAT32))
{}
/// (3) Construct from a Vtk::Function
template <class... Args>
Function (Function<GridView> const& fct, std::string name, Args const&... args)
: Function(fct.localFct_, std::move(name),
getArg<int,unsigned int,long,unsigned long,std::vector<int>>(args..., fct.components_),
getArg<Vtk::RangeTypes>(args..., fct.rangeType_),
getArg<Vtk::DataTypes>(args..., fct.dataType_))
{}
/// (3) Construct from a GridFunction
/// (4) Construct from a GridFunction
/**
* \param fct A Grid(View)-function, providing a `localFunction(fct)`
* \param name The name to use as identification in the VTK file
......@@ -108,18 +122,19 @@ namespace Dune
* NOTE: Stores the localFunction(fct) by value.
*/
template <class F, class... Args,
disableCopyMove<Function, F> = 0,
class = void_t<LocalFunction<F>> >
Function (F&& fct, std::string name, Args&&... args)
: Function(localFunction(std::forward<F>(fct)), std::move(name), std::forward<Args>(args)...)
{}
/// (4) Constructor that forwards the number of components and data type to the other constructor
/// (5) Constructor that forwards the number of components and data type to the other constructor
template <class F>
Function (F&& fct, Vtk::FieldInfo info)
: Function(std::forward<F>(fct), info.name(), info.size(), info.rangeType(), info.dataType())
{}
/// (5) Construct from legacy VTKFunction
/// (6) Construct from legacy VTKFunction
/**
* \param fct The Dune::VTKFunction to wrap
**/
......@@ -128,7 +143,11 @@ namespace Dune
, name_(fct->name())
{
setComponents(fct->ncomps());
#if DUNE_VERSION_LT(DUNE_GRID,2,7)
setDataType(Vtk::DataTypes::FLOAT32);
#else
setDataType(dataTypeOf(fct->precision()));
#endif
setRangeType(rangeTypeOf(fct->ncomps()));
}
......@@ -193,9 +212,11 @@ namespace Dune
}
/// Set the category of the range, SCALAR, VECTOR, TENSOR, or UNSPECIFIED
void setRangeType (Vtk::RangeTypes type)
void setRangeType (Vtk::RangeTypes type, std::size_t ncomp = 1)
{
rangeType_ = type;
if (type == Vtk::RangeTypes::AUTO)
rangeType_ = rangeTypeOf(ncomp);
}
/// Set all the parameters from a FieldInfo object
......
......@@ -79,38 +79,101 @@ int main (int argc, char** argv)
writer.addPointData(Vtk::Function<GridView>{f3, "vector5", {0,1}});
writer.addPointData(Vtk::Function<GridView>{f3, "vector5"}, "vector6", std::vector{0}, Vtk::RangeTypes::VECTOR);
// 6. pass argument to FieldInfo and Function in any order
writer.addPointData(f3, Dune::Vtk::FieldInfo{"vector6", Vtk::DataTypes::FLOAT32, Vtk::RangeTypes::VECTOR, 3});
writer.addPointData(f3, "vector7", Vtk::DataTypes::FLOAT32, Vtk::RangeTypes::UNSPECIFIED, 3u);
// test default constructible
Vtk::Function<GridView> func0;
// test constructible by (legacy) VTKFunction
Vtk::Function<GridView> func1{f1};
VTK_ASSERT(func1.numComponents() == 1);
VTK_ASSERT(func1.rangeType() == Vtk::RangeTypes::SCALAR);
VTK_ASSERT(func1.dataType() == Vtk::DataTypes::FLOAT32);
writer.addPointData(func1);
// test constructible by local-function
Vtk::Function<GridView> func2{f2, "f2"};
VTK_ASSERT(func2.numComponents() == 1);
VTK_ASSERT(func2.rangeType() == Vtk::RangeTypes::SCALAR);
VTK_ASSERT(func2.dataType() == Vtk::DataTypes::FLOAT32);
writer.addPointData(func2);
Vtk::Function<GridView> func3{f3, "f3", 3};
VTK_ASSERT(func3.numComponents() == 3);
VTK_ASSERT(func3.rangeType() == Vtk::RangeTypes::VECTOR);
VTK_ASSERT(func3.dataType() == Vtk::DataTypes::FLOAT32);
writer.addPointData(func3);
// test constructible with component vector
Vtk::Function<GridView> func4a{f3, "f4a", 1};
Vtk::Function<GridView> func4b{f3, "f4b", {1}}; // == func4a
Vtk::Function<GridView> func4c{f3, "f4c", std::vector{1}};
VTK_ASSERT(func4a.numComponents() == 1);
VTK_ASSERT(func4a.rangeType() == Vtk::RangeTypes::SCALAR);
VTK_ASSERT(func4a.dataType() == Vtk::DataTypes::FLOAT32);
writer.addPointData(func4a);
Vtk::Function<GridView> func4b{f3, "f4b", {1}}; // == func4a
VTK_ASSERT(func4b.numComponents() == 1);
VTK_ASSERT(func4b.rangeType() == Vtk::RangeTypes::SCALAR);
VTK_ASSERT(func4b.dataType() == Vtk::DataTypes::FLOAT32);
writer.addPointData(func4b);
Vtk::Function<GridView> func4c{f3, "f4c", std::vector{1}};
VTK_ASSERT(func4c.numComponents() == 1);
VTK_ASSERT(func4c.rangeType() == Vtk::RangeTypes::SCALAR);
VTK_ASSERT(func4c.dataType() == Vtk::DataTypes::FLOAT32);
writer.addPointData(func4c);
// Test copy-constructible
auto func5{func3};
VTK_ASSERT(func5.numComponents() == func3.numComponents());
VTK_ASSERT(func5.rangeType() == func3.rangeType());
VTK_ASSERT(func5.dataType() == func3.dataType());
auto func6 = func3;
VTK_ASSERT(func6.numComponents() == func3.numComponents());
VTK_ASSERT(func6.rangeType() == func3.rangeType());
VTK_ASSERT(func6.dataType() == func3.dataType());
// Test move-constructible
auto func7{std::move(func5)};
VTK_ASSERT(func7.numComponents() == func3.numComponents());
VTK_ASSERT(func7.rangeType() == func3.rangeType());
VTK_ASSERT(func7.dataType() == func3.dataType());
writer.addPointData(func7, "f7");
auto func8 = std::move(func6);
VTK_ASSERT(func8.numComponents() == func3.numComponents());
VTK_ASSERT(func8.rangeType() == func3.rangeType());
VTK_ASSERT(func8.dataType() == func3.dataType());
writer.addPointData(func8, "f8");
// test template-argument deduction
Vtk::Function func9a{func8};
VTK_ASSERT(func9a.numComponents() == func8.numComponents());
VTK_ASSERT(func9a.rangeType() == func8.rangeType());
VTK_ASSERT(func9a.dataType() == func8.dataType());
Vtk::Function func9b{func8, "f9"};
VTK_ASSERT(func9b.numComponents() == func8.numComponents());
VTK_ASSERT(func9b.rangeType() == func8.rangeType());
VTK_ASSERT(func9b.dataType() == func8.dataType());
Vtk::Function func9c{func8, "f9", 2};
VTK_ASSERT(func9c.numComponents() == 3);
VTK_ASSERT(func9c.rangeType() == func8.rangeType());
VTK_ASSERT(func9c.dataType() == func8.dataType());
Vtk::Function func9d{func8, "f9", std::vector{0}};
VTK_ASSERT(func9d.numComponents() == 3);
VTK_ASSERT(func9d.rangeType() == func8.rangeType());
VTK_ASSERT(func9d.dataType() == func8.dataType());
Vtk::Function func9e{func8, "f9", Vtk::RangeTypes::SCALAR};
VTK_ASSERT(func9e.numComponents() == 1);
VTK_ASSERT(func9e.rangeType() == Vtk::RangeTypes::SCALAR);
VTK_ASSERT(func9e.dataType() == func8.dataType());
writer.write("test-function.vtu");
}
\ No newline at end of file
......@@ -12,21 +12,21 @@ int main()
Vtk::mapDataTypes(Vtk::DataTypes::UINT32, [](auto t)
{
using T = typename decltype(t)::type;
VTK_ASSERT(Vtk::Map::type<T>() == Vtk::DataTypes::UINT32);
VTK_ASSERT(Vtk::dataTypeOf<T>() == Vtk::DataTypes::UINT32);
});
// constrained mapping of DataTypes to real type t
Vtk::mapDataTypes<std::is_integral>(Vtk::DataTypes::UINT32, [](auto t)
{
using T = typename decltype(t)::type;
VTK_ASSERT(Vtk::Map::type<T>() == Vtk::DataTypes::UINT32);
VTK_ASSERT(Vtk::dataTypeOf<T>() == Vtk::DataTypes::UINT32);
static_assert(std::is_integral_v<T>);
});
Vtk::mapDataTypes<std::is_floating_point>(Vtk::DataTypes::FLOAT32, [](auto t)
{
using T = typename decltype(t)::type;
VTK_ASSERT(Vtk::Map::type<T>() == Vtk::DataTypes::FLOAT32);
VTK_ASSERT(Vtk::dataTypeOf<T>() == Vtk::DataTypes::FLOAT32);
static_assert(std::is_floating_point_v<T>);
});
......@@ -45,8 +45,8 @@ int main()
{
using F = typename decltype(f)::type;
using H = typename decltype(h)::type;
VTK_ASSERT(Vtk::Map::type<F>() == Vtk::DataTypes::FLOAT32);
VTK_ASSERT(Vtk::Map::type<H>() == Vtk::DataTypes::UINT32);
VTK_ASSERT(Vtk::dataTypeOf<F>() == Vtk::DataTypes::FLOAT32);
VTK_ASSERT(Vtk::dataTypeOf<H>() == Vtk::DataTypes::UINT32);
});
// constrained mapping with multiple types
......@@ -55,8 +55,8 @@ int main()
{
using F = typename decltype(f)::type;
using H = typename decltype(h)::type;
VTK_ASSERT(Vtk::Map::type<F>() == Vtk::DataTypes::FLOAT32);
VTK_ASSERT(Vtk::Map::type<H>() == Vtk::DataTypes::UINT32);
VTK_ASSERT(Vtk::dataTypeOf<F>() == Vtk::DataTypes::FLOAT32);
VTK_ASSERT(Vtk::dataTypeOf<H>() == Vtk::DataTypes::UINT32);
static_assert(std::is_floating_point_v<F>);
static_assert(std::is_integral_v<H>);
});
......
......@@ -36,6 +36,21 @@ Vtk::FormatTypes formatTypeOf (Dune::VTK::OutputType o)
}
}
std::string to_string (Vtk::RangeTypes type)
{
switch (type) {
case Vtk::RangeTypes::UNSPECIFIED: return "unspecified";
case Vtk::RangeTypes::AUTO: return "auto";
case Vtk::RangeTypes::SCALAR: return "scalar";
case Vtk::RangeTypes::VECTOR: return "vector";
case Vtk::RangeTypes::TENSOR: return "tensor";
default:
DUNE_THROW(RangeError, "RangeType not found.");
std::abort();
}
}
// Map a dune-grid FieldInfo::Type to ValueTypes
Vtk::RangeTypes rangeTypeOf (Dune::VTK::FieldInfo::Type t)
{
......
......@@ -9,6 +9,7 @@
#include <dune/common/typelist.hh>
#include <dune/geometry/type.hh>
#include <dune/grid/io/file/vtk/common.hh>
#include <dune/vtk/utility/arguments.hh>
#include <dune/vtk/utility/errors.hh>
namespace Dune
......@@ -36,6 +37,7 @@ namespace Dune
VECTOR, //< Use exactly 3 components
TENSOR //< Use exactly 9 components
};
std::string to_string (Vtk::RangeTypes);
// Map a dune-grid FieldInfo::Type to ValueTypes
Vtk::RangeTypes rangeTypeOf (Dune::VTK::FieldInfo::Type);
......@@ -216,14 +218,16 @@ namespace Dune
class FieldInfo
{
public:
explicit FieldInfo (std::string name, int ncomps = 1,
Vtk::RangeTypes rangeType = Vtk::RangeTypes::AUTO,
Vtk::DataTypes dataType = Vtk::DataTypes::FLOAT32)
template <class... Args>
explicit FieldInfo (std::string name, Args... args)
: name_(std::move(name))
, ncomps_(ncomps)
, rangeType_(rangeType == Vtk::RangeTypes::AUTO ? rangeTypeOf(ncomps) : rangeType)
, dataType_(dataType)
{}
, ncomps_(getArg<int,unsigned int,long,unsigned long>(args..., 1))
, rangeType_(getArg<Vtk::RangeTypes>(args..., Vtk::RangeTypes::AUTO))
, dataType_(getArg<Vtk::DataTypes>(args..., Vtk::DataTypes::FLOAT32))
{
if (rangeType_ == Vtk::RangeTypes::AUTO)
rangeType_ = rangeTypeOf(ncomps_);
}
// Construct from dune-grid FieldInfo
FieldInfo (Dune::VTK::FieldInfo info)
......
......@@ -3,6 +3,7 @@ dune_add_library("filesystem" OBJECT
#install headers
install(FILES
arguments.hh
enum.hh
errors.hh
filesystem.hh
......
#pragma once
#include <type_traits>
#include <utility>
namespace Dune
{
namespace Vtk
{
/// Extract the first argument of the variadic list that is the same as one of
/// the types {T,...} and return its value.
/**
* This utility can be used to implement function parameters with flexible order.
*
* Example:
* ```
* template <class... Args>
* void foo(Args const&... args)
* {
* int i = getArg<int>(args...);
* double d = getArg<double>(args..., 42.0); // with default value
* }
* ```
*
* The arguments are tested from first to last. Thus, a default parmaeter could be given at
* end of the variadic list that is chosen if no argument matches the requested type.
**/
template <class... T, class Arg0, class... Args>
decltype(auto) getArg(Arg0&& arg0, Args&&... args)
{
using A = std::decay_t<Arg0>;
if constexpr ((std::is_same_v<A,T> ||...))
return std::forward<Arg0>(arg0);
else
return getArg<T...>(std::forward<Args>(args)...);
}
} // end namespace Vtk
} // end namespace Dune
dune_add_test(SOURCES test-arguments.cc)
dune_add_test(NAME test-lagrange1
SOURCES test-lagrange.cc
COMPILE_DEFINITIONS "CHECKDIM=1")
......
#include <config.h>
#include <dune/vtk/utility/arguments.hh>
#include <dune/vtk/utility/errors.hh>
using namespace Dune::Vtk;
template <class... Args>
void test_found(Args const&... args)
{
VTK_ASSERT(getArg<double>(args...,1.0) == 2.0);
VTK_ASSERT(getArg<float>(args...,2.0f) == 3.0f);
VTK_ASSERT(getArg<int>(args...,3) == 4);
VTK_ASSERT(getArg<unsigned int>(args...,4u) == 5u);
}
template <class... Args>
void test_notfound(Args const&... args)
{
VTK_ASSERT(getArg<double>(args...,1.0) == 1.0);
VTK_ASSERT(getArg<float>(args...,2.0f) == 2.0f);
VTK_ASSERT(getArg<int>(args...,3) == 3);
VTK_ASSERT(getArg<unsigned int>(args...,4u) == 4u);
}
struct A{};
int main()
{
test_found(2.0, 3.0f, 4, 5u);
test_found(5u, 4, 3.0f, 2.0);
test_notfound();
test_notfound(4l);
test_notfound(A{},4ul);
}
......@@ -352,9 +352,9 @@ template <class GV, class DC>
std::string VtkWriterInterface<GV,DC>
::getNames (std::vector<VtkFunction> const& data) const
{
auto scalar = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.numComponents() == 1; });
auto vector = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.numComponents() == 3; });
auto tensor = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.numComponents() == 9; });
auto scalar = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.rangeType() == Vtk::RangeTypes::SCALAR; });
auto vector = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.rangeType() == Vtk::RangeTypes::VECTOR; });
auto tensor = std::find_if(data.begin(), data.end(), [](auto const& v) { return v.rangeType() == Vtk::RangeTypes::TENSOR; });
return (scalar != data.end() ? " Scalars=\"" + scalar->name() + "\"" : "")
+ (vector != data.end() ? " Vectors=\"" + vector->name() + "\"" : "")
+ (tensor != data.end() ? " Tensors=\"" + tensor->name() + "\"" : "");
......
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