Mathematical expressions in Reflex ================================== When certain field such as a boundary condition or a material property accepts a mathematical expression such as ``sqrt(x^2+y^2)+z`` instead of just a constant value, the Reflex mathematical parser and evaluator is employed. A mathematical expression is a string that contains operators, constants, variables and functions that work as described below. Operators --------- The available operators, in decreasing order of precedence, are ========================================= ====================== ============= ====== Operator Example Expression Result ========================================= ====================== ============= ====== Exponentiation ``^`` :math:`2^3` ``2^3`` 8 Multiplication ``*`` and division ``/`` :math:`4 \cdot 3/2` ``4*3/2`` 6 Addition ``+`` and subtraction ``-`` :math:`4 + 3 - 2` ``4+3-2`` 5 Smaller than ``<`` and greater than ``>`` :math:`2>1` ``2>1`` 1 Equal to ``==`` and different from ``!=`` :math:`2 \neq 1` ``2!=1`` 1 Logical AND ``&`` and logical OR ``|`` :math:`2>1 \wedge 3>2` ``2>1 & 3>2`` 1 ========================================= ====================== ============= ====== - Spaces are ignored by the parser. They can be used (or not) to make the string clearer. - All logical operators evaluate to zero (false) or one (true). - All operations (even the logical ones) are made in double-precision floating-point algebra. - There is no need to add an explicit decimal dot such as writing ``2.0`` instead of ``2``. All numbers are converted to floating point values. - Scientific notation such as ``1e3`` can be used for numerical constants. Parenthesis can be used to change the order of precedence in the usual way. They can be used to handle addition or subtraction of negative numbers as well. In general, Reflex’ mathematical parser behaves as any other parser one may encounter in any programming langauge: ============================================================== ======================== ======== Example Expression Result ============================================================== ======================== ======== :math:`1+2 \cdot 3` ``1+2*3`` 7 :math:`(1+2)\cdot 3` ``(1+2)*3`` 9 :math:`-2^3` ``-2^3`` -8 :math:`-1-(-1)` ``-1-(-1)`` 0 :math:`-1+(-1)` ``-1+(-1)`` -2 :math:`-1+(+1)` ``-1+(+1)`` 0 :math:`-1-(+1)` ``-1-(+1)`` -2 :math:`\frac{1}{3}` ``1/3`` 0.333333 :math:`\left(1+\frac{1}{10^6}\right)^{10^6}` ``(1+1/1e6)^1e6`` 2.71828 :math:`\frac{1}{(1+\frac{1}{10^6})^{10^6}}` ``1/((1+1/1e6)^1e6)`` 0.36788 :math:`\left[\left(1+\frac{1}{10^6}\right)^{10^6}\right]^{-1}` ``((1+1/1e6)^1e6)^(-1)`` 0.36788 :math:`2^{0.5}` ``2^0.5`` 1.41421 :math:`2^{\frac{1}{2}}` ``2^(1/2)`` 1.41421 ============================================================== ======================== ======== Variables --------- Besides numerical constants, expression strings can contain references to variables which hold scalar values. ============= =========================================================== Variable name Description ============= =========================================================== ``t`` Current time of a transient or quasistatic simulation ``x`` Global spatial coordinate :math:`x` ``y`` Global spatial coordinate :math:`y` ``z`` Global spatial coordinate :math:`z` ``T`` Temperature at the current spatial location :math:`(x,y,z)` ``pi`` The :math:`\pi` constant ============= =========================================================== Also, for each coordinate system defined in the simulation, three extra variables are defined that hold the local coordinates as converted from the global spatial location :math:`(x,y,z)`. For instance, if the coordinate system is named ``coord1`` then the following extra variables are available, depending on the type of ``coord1``: =========== ================== ================== ================== Type Local coordinate 1 Local coordinate 2 Local coordinate 3 =========== ================== ================== ================== Cartesian ``x_coord1`` ``y_coord1`` ``z_coord1`` Cylindrical ``r_coord1`` ``theta_coord1`` ``z_coord1`` Spherical ``r_coord1`` ``theta_coord1`` ``phi_coord1`` =========== ================== ================== ================== Built-in functions ------------------ The built-in mathematical functions described below are available. Functions take one or more arguments between brackets separated by commas. Arguments can be sub-expressions as well: ========================================================================================= ================================ =============================== Example Expression Result ========================================================================================= ================================ =============================== :math:`\sqrt{2}` ``sqrt(2)`` 1.41421 :math:`\sqrt{3}` ``sqrt(3)`` 1.73205 :math:`\sqrt{\pi}` ``sqrt(pi)`` 1.77245 :math:`\sqrt{\pi^2}` ``sqrt(pi^2)`` 3.14159 :math:`\sqrt{\pi}^2` ``sqrt(pi)^2`` 3.14159 :math:`\sin \pi` ``sin(pi)`` 1.22465 :math:`\cdot 10^{-16}` :math:`\cos \pi` ``cos(pi)`` -1 :math:`\sin \frac{\pi}{2}` ``sin(pi/2)`` 1 :math:`\cos \frac{\pi}{2}` ``cos(pi/2)`` 6.12323\ :math:`\cdot 10^{-17}` :math:`\sin 1` ``sin(1)`` 0.841471 :math:`\sqrt{1-\cos(1)^2}` ``sqrt(1-cos(1)^2)`` 0.841471 :math:`\sin(1)^2 + \cos(1)^2` ``sin(1)^2+cos(1)^2`` 1 :math:`\arctan \left[ \exp\left(-\frac{1}{2}\right), \log\left( \sqrt{2} \right) \right]` ``atan(exp(-1/2),log(sqrt(2)))`` 1.05167 :math:`\sinh(1+x^2) \mod \pi` ``mod(sinh(1+x^2), pi)`` 0.485268 :math:`\max \left[ 1, \sqrt{2}, \lfloor 1.9 \rfloor \right]` ``max(1,sqrt(2),floor(1.9))`` 1.41421 :math:`\begin{cases}10 & \text{if $\sqrt{10}>\pi$}\\ \pi^2 & \text{otherwise}\end{cases}` ``if(sqrt(10)>pi, 10, pi^2)`` 10 ========================================================================================= ================================ =============================== abs ~~~ Returns the absolute value of the argument :math:`x`. ``abs(x)`` :math:`= \displaystyle |x|` |abs|  acos ~~~~ Computes the arc in radians whose cosine is equal to the argument :math:`x`. ``acos(x)`` :math:`= \displaystyle \arccos(x)` |acos|  asin ~~~~ Computes the arc in radians whose sine is equal to the argument :math:`x`. ``asin(x)`` :math:`= \displaystyle \arcsin(x)` |asin|  atan ~~~~ Computes, in radians, the arc tangent of the argument :math:`x`. ``atan(x)`` :math:`= \displaystyle \arctan(x)` |atan|  atan2 ~~~~~ Computes, in radians, the arc tangent of quotient :math:`y/x`, using the signs of the two arguments to determine the quadrant of the result, which is in the range :math:`[-\pi,\pi]`. ``atan2(y,x)`` :math:`= \displaystyle \arctan(y/x)` ceil ~~~~ Returns the smallest integral value not less than the argument :math:`x`. ``ceil(x)`` :math:`= \displaystyle \lceil x \rceil` |ceil|  cos ~~~ Computes the cosine of the argument :math:`x`, where :math:`x` is in radians. A cosine wave can be generated by passing as the argument :math:`x` a linear function of time such as :math:`\omega t+\phi`, where :math:`\omega` controls the frequency of the wave and :math:`\phi` controls its phase. ``cos(x)`` :math:`= \displaystyle \cos(x)` |cos|  cosh ~~~~ Computes the hyperbolic cosine of the argument :math:`x`, where :math:`x` is in radians. ``cosh(x)`` :math:`= \displaystyle \cosh(x)` |cosh|  equal ~~~~~ Checks if the two first expressions :math:`a` and :math:`b` are equal, up to the tolerance given by the third optional argument :math:`\epsilon`. Default value for :math:`\epsilon = 10^{-9}`. ``equal(a, b, [eps])`` :math:`= \displaystyle \begin{cases} 1 & \text{if $|a-b|<\epsilon$} \\ 0 & \text{otherwise} \end{cases}` exp ~~~ Computes the exponential function the argument :math:`x`, i.e. the base of the natural logarithm :math:`e` raised to the :math:`x`-th power. ``exp(x)`` :math:`= \displaystyle e^x` |exp|  floor ~~~~~ Returns the largest integral value not greater than the argument :math:`x`. ``floor(x)`` :math:`= \displaystyle \lfloor x \rfloor` |floor|  heaviside ~~~~~~~~~ Computes the zero-centered Heaviside step function of the argument :math:`x`. If the optional second argument :math:`\delta` is provided, the discontinuous step at :math:`x=0` is replaced by a ramp starting at :math:`x=0` and finishing at :math:`x=\delta`. ``heaviside(x, [delta])`` :math:`= \displaystyle \begin{cases} 0 & \text{if $x < 0$} \\ x / \delta & \text{if $0 < x < \delta$} \\ 1 & \text{if $x > \delta$} \end{cases}` |heaviside|  if ~~ Performs a conditional testing of the first argument :math:`a`, and returns either the second optional argument :math:`b` if :math:`a` is different from zero or the third optional argument :math:`c` if :math:`a` evaluates to zero. The comparison of the condition :math:`a` with zero is performed within the precision given by the optional fourth argument :math:`\epsilon`. If the second argument :math:`c` is not given and :math:`a` is not zero, the function returns one. If the third argument :math:`c` is not given and :math:`a` is zero, the function returns zero. The default precision is :math:`\epsilon = 10^{-9}`. Even though ``if`` is a logical operation, all the arguments and the returned value are double-precision floating point numbers. ``if(a, [b], [c], [eps])`` :math:`= \displaystyle \begin{cases} b & \text{if $|a|<\epsilon$} \\ c & \text{otherwise} \end{cases}` limit ~~~~~ Limits the first argument :math:`x` to the interval :math:`[a,b]`. The second argument :math:`a` should be less than the third argument :math:`b`. ``limit(x, a, b)`` :math:`= \displaystyle \begin{cases} a & \text{if $x < a$} \\ x & \text{if $a \leq x \leq b$} \\ b & \text{if $x > b$} \end{cases}` log ~~~ Computes the natural logarithm of the argument :math:`x`. ``log(x)`` :math:`= \displaystyle \ln(x)` |log|  max ~~~ Returns the maximum of the arguments :math:`x_i` provided. Currently only maximum of ten arguments can be given. ``max(x1, x2, [...], [x10])`` :math:`= \displaystyle \max \Big (x_1, x_2, \dots, x_{10} \Big)` min ~~~ Returns the minimum of the arguments :math:`x_i` provided. Currently only maximum of ten arguments can be given. ``min(x1, x2, [...], [x10])`` :math:`= \displaystyle \min \Big (x_1, x_2, \dots, x_{10} \Big)` mod ~~~ Returns the remainder of the division between the first argument :math:`a` and the second one :math:`b`. Both arguments may be non-integral. ``mod(a, b)`` :math:`= \displaystyle a - \left\lfloor \frac{a}{b} \right\rfloor \cdot b` not ~~~ Returns one if the first argument :math:`x` is zero and zero otherwise. The second optional argument :math:`\epsilon` gives the precision of the “zero” evaluation. If not given, default is :math:`\epsilon = 10^{-9}`. ``not(x, [eps])`` :math:`= \displaystyle \begin{cases}1 &\text{if $|x| < \epsilon$} \\ 0 &\text{otherwise} \end{cases}` random ~~~~~~ Returns a random real number uniformly distributed between the first real argument :math:`x_1` and the second one :math:`x_2`. If the third integer argument :math:`s` is given, it is used as the seed and thus repetitive sequences can be obtained. If no seed is provided, the current time is used. ``random(x1, x2, [s])`` :math:`= \displaystyle x_1 + r \cdot (x_2-x_1) \quad \quad 0 \leq r < 1` round ~~~~~ Rounds the argument :math:`x` to the nearest integer. Halfway cases are rounded away from zero. ``round(x)`` :math:`= \displaystyle \begin{cases} \lceil x \rceil & \text{if $\lceil x \rceil - x < 0.5$} \\ \lceil x \rceil & \text{if $\lceil x \rceil - x = 0.5 \wedge x > 0$} \\ \lfloor x \rfloor & \text{if $x-\lfloor x \rfloor < 0.5$} \\ \lfloor x \rfloor & \text{if $x-\lfloor x \rfloor = 0.5 \wedge x < 0$} \end{cases}` |round|  sawtooth_wave ~~~~~~~~~~~~~ Computes a sawtooth wave between zero and one with a period equal to one. As with the sine wave, a sawtooh wave can be generated by passing as the argument :math:`x` a linear function of time such as :math:`\omega t+\phi`, where :math:`\omega` controls the frequency of the wave and :math:`\phi` controls its phase. ``sawtooth_wave(x)`` :math:`= \displaystyle x - \lfloor x \rfloor` |sawtooth_wave|  sgn ~~~ Returns minus one, zero or plus one depending on the sign of the first argument :math:`x`. The second optional argument :math:`\epsilon` gives the precision of the “zero” evaluation. If not given, default is :math:`\epsilon = 10^{-9}`. ``sgn(x, [eps])`` :math:`= \displaystyle \begin{cases}-1 &\text{if $x \le -\epsilon$} \\ 0 &\text{if $|x| < \epsilon$} \\ +1 &\text{if $x \ge +\epsilon$} \end{cases}` |sgn|  sin ~~~ Computes the sine of the argument :math:`x`, where :math:`x` is in radians. A sine wave can be generated by passing as the argument :math:`x` a linear function of time such as :math:`\omega t+\phi`, where :math:`\omega` controls the frequency of the wave and :math:`\phi` controls its phase. ``sin(x)`` :math:`= \displaystyle \sin(x)` |sin|  sinh ~~~~ Computes the hyperbolic sine of the argument :math:`x`, where :math:`x` is in radians. ``sinh(x)`` :math:`= \displaystyle \sinh(x)` |sinh|  sqrt ~~~~ Computes the positive square root of the argument :math:`x`. ``sqrt(x)`` :math:`= \displaystyle +\sqrt{x}` |sqrt|  square_wave ~~~~~~~~~~~ Computes a square function between zero and one with a period equal to one. The output is one for :math:`0 < x < 1/2` and zero for :math:`1/2 \leq x < 1`. As with the sine wave, a square wave can be generated by passing as the argument :math:`x` a linear function of time such as :math:`\omega t+\phi`, where :math:`\omega` controls the frequency of the wave and :math:`\phi` controls its phase. ``square_wave(x)`` :math:`= \displaystyle \begin{cases} 1 & \text{if $x - \lfloor x \rfloor < 0.5$} \\ 0 & \text{otherwise} \end{cases}` |square_wave|  tan ~~~ Computes the tangent of the argument :math:`x`, where :math:`x` is in radians. ``tan(x)`` :math:`= \displaystyle \tan(x)` |tan|  tanh ~~~~ Computes the hyperbolic tangent of the argument :math:`x`, where :math:`x` is in radians. ``tanh(x)`` :math:`= \displaystyle \tanh(x)` |tanh|  triangular_wave ~~~~~~~~~~~~~~~ Computes a triangular wave between zero and one with a period equal to one. As with the sine wave, a triangular wave can be generated by passing as the argument :math:`x` a linear function of time such as :math:`\omega t+\phi`, where :math:`\omega` controls the frequency of the wave and :math:`\phi` controls its phase. ``triangular_wave(x)`` :math:`= \displaystyle \begin{cases} 2 \cdot (x - \lfloor x \rfloor) & \text{if $x - \lfloor x \rfloor < 0.5$} \\ 2 \cdot [1-(x - \lfloor x \rfloor)] & \text{otherwise} \end{cases}` |triangular_wave|  User-provided functions ----------------------- If the Reflex input also contains user-defined functions, such as - :math:`f(\xi)` defined by an expression .. code:: json { "function_name": "f", "function_type": "Expression", "function": { "arguments": [ "xi" ], "expression": "heaviside(xi-0.25)*(xi-0.25)^2" } } - :math:`g(\xi)` as a linear interpolation of one-dimensional point-wise data .. code:: json { "function_name": "g", "function_type": "Interpolation", "function": { "domain_values": [ { "values": [0, 0.1, 0.2, 0.3, 0.4, 0.6, 0.8, 10 ] } ], "range_values": [0, 0.0, 0.25, 0.5, 0.75, 1, 0.5, 0 ], "interpolation_type": "LinearInterpolation", "interpolation": {} } } - :math:`h(x,y,z)` with multi-dimensional data from a CSV interpolated using a Shepard-based scheme .. code:: json { "function_name": "h", "function_type": "Interpolation", "domain_dimension": 3, "function": { "file_name": "TempFunction.csv", "interpolation_type": "ShepardInterpolation", "interpolation": { "power": 4 } } } In these cases, the functions above might be referred to as ``f(t/100)``, ``g((T-20)/100)`` or ``h(x_coord1,y_coord1,z_coord1)``. The number of arguments ought to match the function definition (there can be no optional arguments) or otherwise the parser will issue a syntax error and Reflex will not run. But apart from that, the arguments can be any other valid mathematical expression, which will we evaluated before calling the actual user-defined function. These user-provided functions can be then used as a part of a more general expression like ``1+f(t/100)`` or ``sqrt(1-g((T-20)/100)^2)`` or ``(h(x_coord1,y_coord1,z_coord1)-32)*5/9``. .. |abs| image:: figures/abs.svg :width: 90.0% .. |acos| image:: figures/acos.svg :width: 90.0% .. |asin| image:: figures/asin.svg :width: 90.0% .. |atan| image:: figures/atan.svg :width: 90.0% .. |ceil| image:: figures/ceil.svg :width: 90.0% .. |cos| image:: figures/cos.svg :width: 90.0% .. |cosh| image:: figures/cosh.svg :width: 90.0% .. |exp| image:: figures/exp.svg :width: 90.0% .. |floor| image:: figures/floor.svg :width: 90.0% .. |heaviside| image:: figures/heaviside.svg :width: 90.0% .. |log| image:: figures/log.svg :width: 90.0% .. |round| image:: figures/round.svg :width: 90.0% .. |sawtooth_wave| image:: figures/sawtooth_wave.svg :width: 90.0% .. |sgn| image:: figures/sgn.svg :width: 90.0% .. |sin| image:: figures/sin.svg :width: 90.0% .. |sinh| image:: figures/sinh.svg :width: 90.0% .. |sqrt| image:: figures/sqrt.svg :width: 90.0% .. |square_wave| image:: figures/square_wave.svg :width: 90.0% .. |tan| image:: figures/tan.svg :width: 90.0% .. |tanh| image:: figures/tanh.svg :width: 90.0% .. |triangular_wave| image:: figures/triangular_wave.svg :width: 90.0%