48 use,
intrinsic :: ieee_arithmetic, only : ieee_is_finite
94 real(kind=
rp) :: num = 0.0_rp
95 character(len=EXPR_MAX_IDENT) :: name =
''
106 character(len=:),
allocatable :: src
107 integer,
allocatable :: op(:)
108 real(kind=
rp),
allocatable :: lit(:)
112 integer :: max_depth = 0
113 logical :: time_dependent = .false.
119 integer,
allocatable :: op(:)
122 real(kind=
rp),
allocatable :: lit(:)
128 logical :: time_dependent = .false.
130 character(len=:),
allocatable :: src
132 real(kind=
rp),
allocatable,
private :: stk(:,:)
148 character(len=*),
intent(in) :: str
154 if (len(p%src) .eq. 0)
call neko_error(
"Empty expression")
158 allocate(p%op(p%n_tok + 1))
159 allocate(p%lit(p%n_tok + 1))
162 if (p%tok(p%cur)%kind .ne.
tk_end)
then
163 call expr_error(p,
"unexpected trailing input", p%tok(p%cur)%pos)
167 this%depth = p%max_depth
168 this%time_dependent = p%time_dependent
171 allocate(this%op(this%n_op), this%lit(this%n_op))
172 this%op = p%op(1:this%n_op)
173 this%lit = p%lit(1:this%n_op)
186 if (
allocated(p%tok))
deallocate(p%tok)
187 if (
allocated(p%src))
deallocate(p%src)
188 if (
allocated(p%op))
deallocate(p%op)
189 if (
allocated(p%lit))
deallocate(p%lit)
196 p%time_dependent = .false.
204 if (
allocated(this%op))
deallocate(this%op)
205 if (
allocated(this%lit))
deallocate(this%lit)
206 if (
allocated(this%src))
deallocate(this%src)
207 if (
allocated(this%stk))
deallocate(this%stk)
210 this%time_dependent = .false.
228 integer,
intent(in) :: n
229 real(kind=
rp),
intent(inout) :: res(n)
230 real(kind=
rp),
intent(in) :: x(n)
231 real(kind=
rp),
intent(in) :: y(n)
232 real(kind=
rp),
intent(in) :: z(n)
233 real(kind=
rp),
intent(in),
optional :: t
234 real(kind=
rp),
intent(in),
optional :: dt
235 real(kind=
rp) :: t_, dt_
236 integer :: i0, nb, ip, sp, i, k
238 if (this%n_op .eq. 0)
call neko_error(
"Evaluating an uncompiled expression")
240 if (this%time_dependent .and. .not.
present(t))
then
241 call neko_error(
"The expression '" // this%src //
"' depends on " // &
242 "time, but no time is available where it is used")
247 if (
present(t)) t_ = t
248 if (
present(dt)) dt_ = dt
255 select case (this%op(ip))
263 this%stk(i, sp) = this%lit(ip)
268 this%stk(i, sp) = x(i0 + i - 1)
273 this%stk(i, sp) = y(i0 + i - 1)
278 this%stk(i, sp) = z(i0 + i - 1)
288 this%stk(i, sp) = dt_
296 this%stk(i, sp) = -this%stk(i, sp)
300 this%stk(i, sp) = sin(this%stk(i, sp))
304 this%stk(i, sp) = cos(this%stk(i, sp))
308 this%stk(i, sp) = tan(this%stk(i, sp))
312 this%stk(i, sp) = asin(this%stk(i, sp))
316 this%stk(i, sp) = acos(this%stk(i, sp))
320 this%stk(i, sp) = atan(this%stk(i, sp))
324 this%stk(i, sp) = sinh(this%stk(i, sp))
328 this%stk(i, sp) = cosh(this%stk(i, sp))
332 this%stk(i, sp) = tanh(this%stk(i, sp))
336 this%stk(i, sp) = exp(this%stk(i, sp))
340 this%stk(i, sp) = log(this%stk(i, sp))
344 this%stk(i, sp) = log10(this%stk(i, sp))
348 this%stk(i, sp) = sqrt(this%stk(i, sp))
352 this%stk(i, sp) = abs(this%stk(i, sp))
356 this%stk(i, sp) = erf(this%stk(i, sp))
360 this%stk(i, sp) = erfc(this%stk(i, sp))
364 if (this%stk(i, sp) .lt. 0.0_rp)
then
365 this%stk(i, sp) = 0.0_rp
367 this%stk(i, sp) = 1.0_rp
373 k = nint(this%lit(ip))
375 this%stk(i, sp) = this%stk(i, sp) ** k
383 this%stk(i, sp-1) = this%stk(i, sp-1) + this%stk(i, sp)
388 this%stk(i, sp-1) = this%stk(i, sp-1) - this%stk(i, sp)
393 this%stk(i, sp-1) = this%stk(i, sp-1) * this%stk(i, sp)
398 this%stk(i, sp-1) = this%stk(i, sp-1) / this%stk(i, sp)
403 this%stk(i, sp-1) = this%stk(i, sp-1) ** this%stk(i, sp)
408 this%stk(i, sp-1) = atan2(this%stk(i, sp-1), this%stk(i, sp))
413 this%stk(i, sp-1) = min(this%stk(i, sp-1), this%stk(i, sp))
418 this%stk(i, sp-1) =
max(this%stk(i, sp-1), this%stk(i, sp))
423 this%stk(i, sp-1) = mod(this%stk(i, sp-1), this%stk(i, sp))
428 call neko_error(
"Corrupt expression opcode stream")
432 if (sp .ne. 1)
call neko_error(
"Corrupt expression opcode stream")
435 res(i0 + i - 1) = this%stk(i, 1)
456 character(len=*),
intent(in) :: str
457 integer,
intent(in) :: n
458 real(kind=
rp),
intent(inout) :: res(n)
459 real(kind=
rp),
intent(in) :: x(n)
460 real(kind=
rp),
intent(in) :: y(n)
461 real(kind=
rp),
intent(in) :: z(n)
462 character(len=*),
intent(in) ::
usage
465 if (len_trim(str) .eq. 0)
then
471 if (e%time_dependent)
then
473 "' depends on time, which is not available where it is used")
476 call e%eval(res, n, x, y, z)
493 character(len=*),
intent(in) :: str
494 integer,
intent(in) :: n
495 real(kind=
rp),
intent(in) :: res(n)
496 character(len=*),
intent(in) ::
usage
500 if (.not. ieee_is_finite(res(i)))
then
502 "' does not evaluate to a finite value everywhere")
516 integer :: i, j, k, n, ios
518 character(len=1) :: c
519 character(len=EXPR_MAX_IDENT) :: buf
522 allocate(p%tok(n + 1))
529 if (c .eq.
' ' .or. c .eq. achar(9))
then
534 if (
is_digit(c) .or. (c .eq.
'.' .and. i .lt. n .and. &
535 is_digit(p%src(min(i+1, n):min(i+1, n)))))
then
542 else if (p%src(j:j) .eq.
'.' .and. .not. seen_dot)
then
552 if (scan(p%src(j:j),
'eEdD') .gt. 0)
then
555 if (scan(p%src(k:k),
'+-') .gt. 0) k = k + 1
560 if (.not.
is_digit(p%src(k:k)))
exit
570 call expr_error(p,
"numeric literal is too long", i)
575 do k = 1, len_trim(buf)
576 if (buf(k:k) .eq.
'd' .or. buf(k:k) .eq.
'D') buf(k:k) =
'e'
579 read (buf, *, iostat = ios) p%tok(p%n_tok)%num
580 if (ios .ne. 0)
call expr_error(p,
"malformed number", i)
589 p%src(j:j) .eq.
'_')
then
596 call expr_error(p,
"identifier is too long", i)
599 p%tok(p%n_tok)%name = p%src(i:j-1)
611 if (p%src(i+1:i+1) .eq.
'*')
then
629 call expr_error(p,
"unexpected character '" // c //
"'", i)
644 integer,
intent(in) :: kind
645 integer,
intent(in) :: pos
647 p%n_tok = p%n_tok + 1
648 p%tok(p%n_tok)%kind = kind
649 p%tok(p%n_tok)%pos = pos
670 if (p%tok(p%cur)%kind .eq.
tk_plus)
then
674 else if (p%tok(p%cur)%kind .eq.
tk_minus)
then
692 if (p%tok(p%cur)%kind .eq.
tk_star)
then
696 else if (p%tok(p%cur)%kind .eq.
tk_slash)
then
714 if (p%tok(p%cur)%kind .eq.
tk_minus)
then
718 if (p%n_op .eq. before + 1 .and. p%op(p%n_op) .eq.
op_lit)
then
721 p%lit(p%n_op) = -p%lit(p%n_op)
725 else if (p%tok(p%cur)%kind .eq.
tk_plus)
then
742 if (p%tok(p%cur)%kind .eq.
tk_pow)
then
747 if (p%n_op .eq. before + 1 .and. p%op(p%n_op) .eq.
op_lit)
then
751 if (p%lit(p%n_op) .eq. anint(p%lit(p%n_op)) .and. &
752 abs(p%lit(p%n_op)) .lt. 1.0e4_rp)
then
757 p%depth = p%depth - 1
771 integer :: k, op, nargs
773 select case (p%tok(p%cur)%kind)
781 if (p%tok(p%cur)%kind .ne.
tk_rpar)
then
782 call expr_error(p,
"expected ')'", p%tok(p%cur)%pos)
789 if (p%tok(p%cur)%kind .eq.
tk_lpar)
then
793 do while (p%tok(p%cur)%kind .eq.
tk_comma)
798 if (p%tok(p%cur)%kind .ne.
tk_rpar)
then
799 call expr_error(p,
"expected ')' closing the argument list of '" &
800 // trim(p%tok(k)%name) //
"'", p%tok(p%cur)%pos)
804 op =
func_op(trim(p%tok(k)%name), nargs)
807 trim(p%tok(k)%name) //
"'", p%tok(k)%pos)
808 else if (op .eq. -2)
then
809 call expr_error(p,
"wrong number of arguments to '" // &
810 trim(p%tok(k)%name) //
"'", p%tok(k)%pos)
818 call expr_error(p,
"expected a value", p%tok(p%cur)%pos)
832 integer,
intent(in) :: k
833 character(len=:),
allocatable :: name
834 real(kind=
rp),
pointer :: rval
835 integer,
pointer :: ival
837 name = trim(p%tok(k)%name)
848 p%time_dependent = .true.
851 p%time_dependent = .true.
862 call expr_error(p,
"unknown symbol '" // name //
"', it is " // &
863 "neither a coordinate nor a constant declared under " // &
864 "case.constants", p%tok(k)%pos)
868 if (
allocated(name))
deallocate(name)
878 character(len=*),
intent(in) :: name
879 integer,
intent(in) :: nargs
935 if (nargs .ne. arity) op = -2
945 integer,
intent(in) :: op
946 real(kind=
rp),
intent(in),
optional :: val
948 if (p%n_op .ge.
size(p%op))
then
949 call neko_error(
"Expression '" // p%src //
"' is too complex")
954 if (
present(val))
then
957 p%lit(p%n_op) = 0.0_rp
961 p%depth = p%depth + 1
963 p%depth = p%depth - 1
965 p%max_depth =
max(p%max_depth, p%depth)
975 character(len=*),
intent(in) :: msg
976 integer,
intent(in) :: pos
977 character(len=16) :: buf
979 write (buf,
'(I0)') pos
980 call neko_error(
"Invalid expression '" // p%src //
"', at character " // &
981 trim(buf) //
": " // msg)
988 character(len=1),
intent(in) :: c
991 res = (c .ge.
'0' .and. c .le.
'9')
998 character(len=1),
intent(in) :: c
1001 res = (c .ge.
'a' .and. c .le.
'z') .or. (c .ge.
'A' .and. c .le.
'Z')
Evaluation of mathematical expressions given as strings in the case file.
integer, parameter op_tan
subroutine push_token(p, kind, pos)
Append a token to the token stream.
integer, parameter tk_rpar
integer, parameter op_sqrt
integer, parameter tk_pow
integer, parameter op_asin
recursive subroutine parse_term(p)
Parse a multiplicative expression.
integer, parameter op_erf
subroutine expression_eval(this, res, n, x, y, z, t, dt)
Evaluate the expression in n points.
integer, parameter op_erfc
integer, parameter tk_end
pure logical function is_alpha(c)
True if c is a letter.
recursive subroutine parse_factor(p)
Parse a possibly signed factor. Unary minus binds looser than ^, so -x^2 is -(x^2),...
integer, parameter op_div
integer, parameter tk_lpar
integer, parameter op_abs
subroutine, public expression_check_finite(str, res, n, usage)
Abort if an expression did not evaluate to a finite value everywhere.
integer, parameter op_add
integer, parameter op_neg
subroutine expr_error(p, msg, pos)
Abort with a message pointing at the offending part of the expression.
integer, parameter op_log
integer, parameter op_cos
integer, parameter tk_ident
subroutine parser_free(p)
Release the memory held by the parser state.
integer, parameter op_binary
integer, parameter, public neko_expr_len
Maximum length of an expression string read from the case file.
integer, parameter op_log10
integer, parameter op_sub
integer, parameter op_mod
integer, parameter op_lit
subroutine expression_init(this, str)
Compile an expression.
pure logical function is_digit(c)
True if c is a decimal digit.
subroutine expression_free(this)
Destructor.
integer, parameter tk_plus
integer, parameter expr_chunk
Number of points evaluated per pass over the opcode stream. Chosen so that the evaluation stack stays...
integer, parameter expr_max_ident
Maximum length of an identifier appearing in an expression.
integer, parameter tk_slash
integer, parameter op_atan2
integer function func_op(name, nargs)
Look up the opcode of a function.
integer, parameter op_min
integer, parameter op_cosh
integer, parameter op_step
integer, parameter op_atan
integer, parameter op_acos
subroutine emit(p, op, val)
Append an opcode, keeping track of how deep the evaluation stack gets.
recursive subroutine parse_primary(p)
Parse a literal, a symbol, a function call or a parenthesised expression.
integer, parameter op_unary
integer, parameter tk_num
integer, parameter tk_star
integer, parameter tk_minus
integer, parameter op_max
integer, parameter op_tanh
subroutine expr_tokenize(p)
Split the source string into a stream of tokens.
integer, parameter op_pow
subroutine, public expression_eval_static(str, res, n, x, y, z, usage)
Compile an expression and evaluate it in a set of points, in a context where there is no time state.
integer, parameter op_exp
integer, parameter op_ipow
recursive subroutine parse_expr(p)
Parse an additive expression.
integer, parameter op_mul
integer, parameter op_sin
recursive subroutine parse_power(p)
Parse an exponentiation. Right associative, so 2^3^2 is 2^(3^2).
subroutine parse_symbol(p, k)
Resolve a bare identifier into either a variable opcode or a literal.
integer, parameter tk_comma
integer, parameter op_sinh
integer, parameter, public rp
Global precision used in computations.
Defines a registry for storing solution fields.
type(registry_t), target, public neko_const_registry
This registry is used to store user-defined scalars and vectors, provided under the constants section...
A compiled mathematical expression.
State of the recursive descent parser.
A single token of an expression.