Skip to content
Snippets Groups Projects
Commit 7c9fadf5 authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Merge branch 'feature/parseExpressions' into 'master'

add muParser library and implement replaceExpression() in InitfileParser.cpp.

See merge request amdis/amdis!147
parents 0e3fed6d 90febba2
Branches
Tags
No related merge requests found
...@@ -21,8 +21,9 @@ dune_project() ...@@ -21,8 +21,9 @@ dune_project()
add_subdirectory("libs") add_subdirectory("libs")
dune_add_library(amdis dune_add_library(amdis
LINK_LIBRARIES ${DUNE_LIBS} fmt::fmt LINK_LIBRARIES ${DUNE_LIBS} fmt::fmt muparser::muparser
EXPORT_NAME AMDiS NAMESPACE AMDiS::) EXPORT_NAME AMDiS NAMESPACE AMDiS::)
add_dune_all_flags(amdis)
add_subdirectory("amdis") add_subdirectory("amdis")
add_subdirectory("bin") add_subdirectory("bin")
...@@ -47,7 +48,6 @@ if (PETSc_FOUND) ...@@ -47,7 +48,6 @@ if (PETSc_FOUND)
target_link_libraries(amdis PUBLIC PETSc::PETSc) target_link_libraries(amdis PUBLIC PETSc::PETSc)
endif (PETSc_FOUND) endif (PETSc_FOUND)
add_dune_all_flags(amdis)
if (ENABLE_ALL_WARNINGS) if (ENABLE_ALL_WARNINGS)
target_compile_options(amdis PUBLIC "-Wall" "-Wpedantic" target_compile_options(amdis PUBLIC "-Wall" "-Wpedantic"
......
#pragma once #pragma once
#include <cassert>
#include <cmath>
#include <optional> #include <optional>
#include <string> #include <string>
#include <type_traits>
#include <vector>
#include <dune/common/parametertree.hh> #include <dune/common/parametertree.hh>
#include <dune/functions/functionspacebases/concepts.hh>
#include <muParser.h>
namespace AMDiS namespace AMDiS
{ {
...@@ -21,15 +26,32 @@ namespace AMDiS ...@@ -21,15 +26,32 @@ namespace AMDiS
* *
* May throw an exception if the value can not be parsed into type T * May throw an exception if the value can not be parsed into type T
**/ **/
template <class T> template <class T,
std::enable_if_t<!std::is_arithmetic_v<T>, int> = 0>
static std::optional<T> get(std::string const& key) static std::optional<T> get(std::string const& key)
{ {
if (pt().hasKey(key)) if (pt().hasKey(key)) {
return pt().get<T>(key); if constexpr (is_arithmetic_container<T>::value)
return getVector<T>(key);
else
return pt().get<T>(key);
}
else else
return {}; return {};
} }
template <class T,
std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
static std::optional<T> get(std::string const& key) {
if (pt().hasKey(key)) {
std::string aux;
std::string valStr = pt().get(key, aux);
return parseExpression<T>(valStr,key);
} else {
return {};
}
}
/// \brief Get parameter-values from parameter-tree with default value /// \brief Get parameter-values from parameter-tree with default value
/** /**
* initialized in init()-method. * initialized in init()-method.
...@@ -39,9 +61,8 @@ namespace AMDiS ...@@ -39,9 +61,8 @@ namespace AMDiS
* \param value: The default value and result. * \param value: The default value and result.
**/ **/
template <class T> template <class T>
static void get(std::string const& key, T& value) static void get(std::string const& key, T& value) {
{ value = get<T>(key).value_or(value);
value = pt().get(key, value);
} }
template <class T> template <class T>
...@@ -64,13 +85,6 @@ namespace AMDiS ...@@ -64,13 +85,6 @@ namespace AMDiS
protected: protected:
Initfile() = default; Initfile() = default;
/// Return the singleton that contains the data
static Initfile& singlett()
{
static Initfile initfile;
return initfile;
}
/// Return the parameter-tree /// Return the parameter-tree
static Dune::ParameterTree& pt() static Dune::ParameterTree& pt()
{ {
...@@ -84,6 +98,84 @@ namespace AMDiS ...@@ -84,6 +98,84 @@ namespace AMDiS
/// read standard values for output and information of parameter-values /// read standard values for output and information of parameter-values
void getInternalParameters(); void getInternalParameters();
/// get Parameter values for vector types
template <class T>
static std::optional<T> getVector(const std::string& key) {
if constexpr (std::is_arithmetic_v<typename T::value_type>) {
T result;
std::vector<std::string> aux;
auto valStr = pt().get(key, aux);
if constexpr(Dune::models<Dune::Functions::Concept::HasResize, T>())
result.resize(valStr.size());
assert(result.size() == valStr.size());
for (std::size_t i = 0; i < valStr.size(); ++i) {
result[i] = parseExpression<typename T::value_type,T>(valStr[i],key,i);
}
return result;
} else {
return pt().get<T>(key);
}
}
/// replace expression with the respective result
template<typename T>
static bool parse(const std::string& input, T& result) {
std::string inputSwap = input;
std::string allowedChars = "+-*/()0123456789";
// do not parse strings
std::string notAllowed = ",abcdfghijklmnopqrstuvwxyzABCDFGHIJKLMNOPQRSTUVWXYZ";
std::size_t found = inputSwap.find_first_of(allowedChars);
std::size_t found2 = inputSwap.find_first_of(notAllowed);
mu::Parser parser;
if (found != std::string::npos && found2 == std::string::npos) {
parser.SetExpr(input);
result = parser.Eval();
return true;
}
return false;
}
template<typename T>
static T parseExpression(const std::string& input,
const std::string& key) {
T result;
if (parse(input, result)) return result;
return pt().get<T>(key);
}
template<typename T, typename Container>
static T parseExpression(const std::string& input,
const std::string& key,
size_t i) {
T result;
if (parse(input, result)) return result;
auto container = pt().get<Container>(key);
return container[i];
}
/// Template for container types with [] operator and existing value_type
template <typename Container, typename = void>
struct is_arithmetic_container : std::false_type {};
template <typename Container>
struct is_arithmetic_container<Container,
std::enable_if_t<std::is_arithmetic<typename Container::value_type>::value &&
!std::is_same<Container, std::string>::value>>
: std::true_type {};
/// Return the singleton that contains the data
static Initfile& singlett()
{
static Initfile initfile;
return initfile;
}
int msgInfo_ = 0; int msgInfo_ = 0;
int paramInfo_ = 1; int paramInfo_ = 1;
bool breakOnMissingTag_ = false; bool breakOnMissingTag_ = false;
......
...@@ -74,7 +74,7 @@ void InitfileParser::readInitfile(std::istream& in, Dune::ParameterTree& pt, boo ...@@ -74,7 +74,7 @@ void InitfileParser::readInitfile(std::istream& in, Dune::ParameterTree& pt, boo
epos = sw.find_first_of(delimiter, pos); epos = sw.find_first_of(delimiter, pos);
fn = sw.substr(pos, epos - pos); fn = sw.substr(pos, epos - pos);
test_exit(sw[epos]==c, "Filename in #include not terminated by {}.", std::to_string(c)); test_exit(sw[epos]==closing[c], "Filename in #include not terminated by {}.", closing[c]);
break; break;
default: default:
error_exit("No filename given for #include"); error_exit("No filename given for #include");
......
...@@ -6,18 +6,50 @@ FetchContent_Declare(fmt # name of the content ...@@ -6,18 +6,50 @@ FetchContent_Declare(fmt # name of the content
GIT_TAG 9.1.0 # the tag GIT_TAG 9.1.0 # the tag
) )
FetchContent_Declare(muparser
GIT_REPOSITORY https://github.com/beltoforion/muparser.git
GIT_TAG v2.3.4
)
FetchContent_GetProperties(fmt) FetchContent_GetProperties(fmt)
if(NOT fmt_POPULATED) if(NOT fmt_POPULATED)
FetchContent_Populate(fmt) FetchContent_Populate(fmt)
endif() endif()
FetchContent_GetProperties(muparser)
if(NOT muparser_POPULATED)
FetchContent_Populate(muparser)
endif()
dune_add_library(fmt dune_add_library(fmt
SOURCES ${fmt_SOURCE_DIR}/src/format.cc SOURCES ${fmt_SOURCE_DIR}/src/format.cc
EXPORT_NAME fmt NAMESPACE fmt::) EXPORT_NAME fmt NAMESPACE fmt::)
dune_add_library(muparser
SOURCES ${muparser_SOURCE_DIR}/src/muParser.cpp
${muparser_SOURCE_DIR}/src/muParserBase.cpp
${muparser_SOURCE_DIR}/src/muParserBytecode.cpp
${muparser_SOURCE_DIR}/src/muParserCallback.cpp
${muparser_SOURCE_DIR}/src/muParserDLL.cpp
${muparser_SOURCE_DIR}/src/muParserError.cpp
${muparser_SOURCE_DIR}/src/muParserInt.cpp
${muparser_SOURCE_DIR}/src/muParserTest.cpp
${muparser_SOURCE_DIR}/src/muParserTokenReader.cpp
EXPORT_NAME muparser NAMESPACE muparser::)
target_compile_features(fmt PRIVATE cxx_std_17) target_compile_features(fmt PRIVATE cxx_std_17)
target_include_directories(fmt PUBLIC target_include_directories(fmt PUBLIC
$<BUILD_INTERFACE:${fmt_SOURCE_DIR}/include>) $<BUILD_INTERFACE:${fmt_SOURCE_DIR}/include>)
target_compile_features(muparser PRIVATE cxx_std_17)
target_include_directories(muparser PUBLIC
$<BUILD_INTERFACE:${muparser_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
file(GLOB FMT_HEADERS ${fmt_SOURCE_DIR}/include/fmt/*.h) file(GLOB FMT_HEADERS ${fmt_SOURCE_DIR}/include/fmt/*.h)
install(FILES ${FMT_HEADERS} install(FILES ${FMT_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fmt) DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fmt)
file(GLOB MUPARSER_HEADERS ${muparser_SOURCE_DIR}/include/*.h)
install(FILES ${MUPARSER_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/muparser)
\ No newline at end of file
...@@ -87,6 +87,9 @@ if(BACKEND STREQUAL "ISTL") ...@@ -87,6 +87,9 @@ if(BACKEND STREQUAL "ISTL")
CMAKE_GUARD MPI_FOUND) CMAKE_GUARD MPI_FOUND)
endif() endif()
dune_add_test(SOURCES InitfileTest.cpp
LINK_LIBRARIES amdis)
dune_add_test(SOURCES IntegrateTest.cpp dune_add_test(SOURCES IntegrateTest.cpp
LINK_LIBRARIES amdis) LINK_LIBRARIES amdis)
......
#include <amdis/AMDiS.hpp>
#include <amdis/Initfile.hpp>
#include "Tests.hpp"
int main(int argc, char** argv)
{
using namespace AMDiS;
using namespace Dune::Functions::BasisFactory;
AMDiS::Environment env(argc, argv);
std::string fn = "/tmp/initfile.dat";
std::string fn2 = "/tmp/initfile2.dat";
{
std::ofstream f_out(fn, std::ios_base::out);
f_out << "int: 4\n"; // 4.0
f_out << "scalar: 2.0\n"; // 2.0
f_out << "scalar->expr: 2.0*3.0\n"; // 6.0
f_out << "scalar->expr->var: 2.0*${scalar}\n"; // 4.0
f_out << "vector: 2.0 3.0\n"; // 2.0 3.0
f_out << "vector->expr: 2.0*3.0 3.0*4.0\n"; // 6.0 12.0
f_out << "vector->expr->var: 2.0*${scalar} 3.0*${scalar}\n"; // 4.0 6.0
f_out << "#include <" << fn2 << ">\n";
std::ofstream f2_out(fn2, std::ios_base::out);
f2_out << "scalar2: 7.0\n";
}
Initfile::init(fn);
// test reading scalar values
AMDIS_TEST_EQ(Initfile::get<int>("int").value(), 4);
AMDIS_TEST_EQ(Initfile::get<double>("scalar").value(), 2.0);
AMDIS_TEST_EQ(Initfile::get<double>("scalar->expr").value(), 6.0);
AMDIS_TEST_EQ(Initfile::get<double>("scalar->expr->var").value(), 4.0);
// test parsing vectors
AMDIS_TEST((Initfile::get<std::array<double,2>>("vector").value() == std::array{2.0,3.0}));
AMDIS_TEST((Initfile::get<std::array<double,2>>("vector->expr").value() == std::array{6.0,12.0}));
AMDIS_TEST((Initfile::get<std::array<double,2>>("vector->expr->var").value() == std::array{4.0,6.0}));
AMDIS_TEST((Initfile::get<Dune::FieldVector<double,2>>("vector").value() == Dune::FieldVector<double,2>{2.0,3.0}));
AMDIS_TEST((Initfile::get<Dune::FieldVector<double,2>>("vector->expr").value() == Dune::FieldVector<double,2>{6.0,12.0}));
AMDIS_TEST((Initfile::get<Dune::FieldVector<double,2>>("vector->expr->var").value() == Dune::FieldVector<double,2>{4.0,6.0}));
AMDIS_TEST((Initfile::get<std::vector<double>>("vector").value() == std::vector{2.0,3.0}));
AMDIS_TEST((Initfile::get<std::vector<double>>("vector->expr").value() == std::vector{6.0,12.0}));
AMDIS_TEST((Initfile::get<std::vector<double>>("vector->expr->var").value() == std::vector{4.0,6.0}));
// test of include statements
AMDIS_TEST_EQ(Initfile::get<double>("scalar2").value(), 7.0);
return report_errors();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment