From 1ec440ee32ff85401c48274fa464952b97948fbe Mon Sep 17 00:00:00 2001 From: bangerth Date: Mon, 2 Mar 2009 02:21:27 +0000 Subject: [PATCH] Patch by Victor Prosolin: Add support for units in the FunctionParser class. git-svn-id: https://svn.dealii.org/trunk@18440 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/base/include/base/function_parser.h | 91 +++++++++++++++++++++ deal.II/base/source/function_parser.cc | 60 +++++++++++++- deal.II/doc/news/changes.h | 11 ++- 3 files changed, 158 insertions(+), 4 deletions(-) diff --git a/deal.II/base/include/base/function_parser.h b/deal.II/base/include/base/function_parser.h index a46319ed15..588202ef81 100644 --- a/deal.II/base/include/base/function_parser.h +++ b/deal.II/base/include/base/function_parser.h @@ -77,6 +77,65 @@ template class Vector; expressions, constants); @endverbatim + + * FunctionParser also provides an option to use units in expressions. + * We can illustrate the use of this functionality with the following example: + * @verbatim + // Define some constants that will be used by the function parser + std::map constants; + std::map units; + constants["PI"] = numbers::PI; + units["cm"] = 10; + units["m"] = 1000; + + // Define the variables that will be used inside the expressions + std::string variables = "x,y"; + + // Define the expressions of the individual components of a + // vector valued function with two components: + std::vector expressions(1); + expressions[0] = "x cm + y m + PI cm; + + // Generate an empty function for these two components. + FunctionParser<2> vector_function; + + // And populate it with the newly created objects. + vector_function.initialize(variables, + expressions, + constants, + units); //An exptra argument here + + // Point at which we want to evaluate the function + Point<2> point(2.0, 3.0); + + // Output the evaluated function + std::cout << "Function " << "[" << expressions[0] << "]" << + " @point " << "[" << point << "]" << " is " << + "[" << vector_function.value(point) << "]" << std::endl; + + * @endverbatim + + * Units are similar to constants in the way they are passed to the + * parser, i.e. via std::map. But units are slightly different + * in that they have a higher precedence than any other operator + * (except parentheses). Thus for example "5/2in" is parsed as "5/(2*300)". + * (If 5/2 inches is what one wants, it has to be written "(5/2)in".) + + * Overall, the main point of units is to make input expressions more readable + * since expressing, say, length as 10cm looks more natural than 10*cm. + + * Beware that the user has full control over units as well as full + * responsibility for "sanity" of the parsed expressions, because the parser + * does NOT know anything about the physical nature of units and one would not + * be warned when adding kilometers to kilograms. + + * units argument to the initialize function is optional, i.e. the + * user does NOT have to use this functionality. + + * For more information on this feature, please see + * contrib/functionparser/fparser.txt + + * * See http://warp.povusers.org/FunctionParser/ for an * explanation on how the underlying library works. @@ -369,6 +428,26 @@ class FunctionParser : public Function const ConstMap &constants, const bool time_dependent = false, const bool use_degrees = false); + + + /** + * Initialize the function. Same as + * above, but with an additional argument + * units - a map of units passed to + * FunctionParser via AddUnint. + * + * Can be used as "3cm". + * Have higher precedence in parsing, i.e. + * if cm=10 then 3/2cm is 3 /(2*10). + * See contrib/functionparser/fparser.txt + * for more details. + */ + void initialize (const std::string &vars, + const std::vector &expressions, + const ConstMap &constants, + const ConstMap &units, + const bool time_dependent = false, + const bool use_degrees = false); /** * Initialize the function. Same as @@ -386,6 +465,18 @@ class FunctionParser : public Function const std::string &expression, const ConstMap &constants, const bool time_dependent = false, + const bool use_degrees = false); + + /** + * Initialize the function. Same as + * above, but with units. + */ + + void initialize (const std::string &vars, + const std::string &expression, + const ConstMap &constants, + const ConstMap &units, + const bool time_dependent = false, const bool use_degrees = false); /** diff --git a/deal.II/base/source/function_parser.cc b/deal.II/base/source/function_parser.cc index e8a0f14cf6..8d7410cb85 100644 --- a/deal.II/base/source/function_parser.cc +++ b/deal.II/base/source/function_parser.cc @@ -52,11 +52,28 @@ FunctionParser::~FunctionParser() #ifndef DEAL_II_DISABLE_PARSER - template void FunctionParser::initialize (const std::string &variables, + const std::vector &expressions, + const std::map &constants, + const bool time_dependent, + const bool use_degrees) +{ + initialize (variables, + expressions, + constants, + std::map< std::string, double >(), + time_dependent, + use_degrees); +} + + + +template +void FunctionParser::initialize (const std::string &variables, const std::vector &expressions, const std::map &constants, + const std::map &units, const bool time_dependent, const bool use_degrees) { @@ -68,9 +85,26 @@ void FunctionParser::initialize (const std::string &varia AssertThrow(this->n_components == expressions.size(), ExcInvalidExpressionSize(this->n_components, expressions.size()) ); - + + + for (unsigned int i=0; in_components; ++i) { + + // Add the various units to + // the parser. + std::map< std::string, double >::const_iterator + unit = units.begin(), + endu = units.end(); + for (; unit != endu; ++unit) + { + const bool success = fp[i].AddUnit(unit->first, unit->second); + AssertThrow (success, + ExcMessage("Invalid Unit Name [error adding a unit]")); + } + + + // Add the various constants to // the parser. std::map< std::string, double >::const_iterator @@ -137,12 +171,32 @@ void FunctionParser::initialize (const std::string &variables, initialize (variables, Utilities::split_string_list (expression, ';'), constants, - time_dependent, + time_dependent, use_degrees); } +template +void FunctionParser::initialize (const std::string &variables, + const std::string &expression, + const std::map &constants, + const std::map &units, + const bool time_dependent, + const bool use_degrees) +{ + // initialize with the things + // we got. + initialize (variables, + Utilities::split_string_list (expression, ';'), + constants, + units, + time_dependent, + use_degrees); +} + + + template double FunctionParser::value (const Point &p, const unsigned int component) const diff --git a/deal.II/doc/news/changes.h b/deal.II/doc/news/changes.h index 861b01458e..fd6eeafa1e 100644 --- a/deal.II/doc/news/changes.h +++ b/deal.II/doc/news/changes.h @@ -371,6 +371,15 @@ inconvenience this causes.

base

    +
  1. +

    + New: The FunctionParser class now supports the fparser library's interface to use + units (like cm, or km) in expressions. An example is given in the documentation of + that class. +
    + (Victor Prosolin 2009/03/01) +

    +
  2. Changed: The classes Threads::ThreadMutex and Threads::ThreadCondition have @@ -379,7 +388,7 @@ inconvenience this causes.
    (WB 2009/01/14)

    - +
  3. New: There is now a class TimerOutput that allows to neatly measure computing -- 2.39.5