parser_module.f90
Go to the documentation of this file.
1 !> @file parser_module.f90
2 !!
3 !! The error file code for this file is ***W36***.
4 !!
5 !! @brief Module \ref parser_module, which enables parsing strings for analytic trajectory mode
6 !!
7 
8 !> @brief Subroutines for equation parsing in case of an analytic trajectory
9 !! or luminosity mode.
10 !!
11 !! The subroutine can calculate equations from a string, e.g., "5.1+3d-2*(2-1)*sin(pi)/x".
12 !! A variable name (in the upper example "x") can be given, which will be filled with a value.
13 !! Everything in this function is private with the exception of the function
14 !! "parse_string" which serves as a interface to parse the given string.
15 !! The return value of this function is a real (i.e., not a string).
16 !!
17 !!
18 !! @author Moritz Reichert
19 !! @date 20.12.20
20 !!
21 #include "macros.h"
25  implicit none
26 
27  ! Parsing strings and lengths
28  character(max_fname_len) :: parsing_string !< Current substring to parse
29  character(max_fname_len) :: complete_string !< Complete input string
30 
31  ! Operator and number arrays that got parsed
33  character(1),dimension(:),allocatable :: operators !< Array containing the operations of the equation as a character (e.g., ["*","+"])
34  real(r_kind),dimension(:),allocatable :: numbers !< Array containing the numbers of the equation (e.g., [1, 2, 3])
35 
36  ! Variable to replace, the value is set by "parse_string"
37  real(r_kind) :: variable_value !< Input variable, set by \ref parse_string
38  character(1),parameter :: variable_name='x' !< Name of the variable that is replaced by parse_string
39 
40 
41  !
42  ! Public and private fields and methods of the module
43  ! Only the function parse_string and find_start_value
44  ! should be public
45  !
46  public:: &
48  private:: &
51  private:: &
56 
57  contains
58 
59 
60  !>
61  !! @brief Function to decide whether a character is a number or not (i.e., 0-9).
62  !!
63  !! ### Example
64  !!~~~~~~~~~~~~~~.f90
65  !! b = is_digit("5")
66  !! c = is_digit("a")
67  !!~~~~~~~~~~~~~~
68  !! b will be .True. and c will be .False.
69  !!
70  !!
71  !! @author Moritz Reichert
72  !! @date 20.12.20
73  function is_digit(str_in)
74  implicit none
75  character(1),intent(in) :: str_in !< Input character
76  integer :: ascii_rep !< ascii representation of string
77  logical :: is_digit !< True in case of a digit and False in case of another character
78 
79  ! Check numbers between 0 and 9 by their ascii representation
80  ascii_rep = iachar(str_in(1:1))
81  if (ascii_rep>= iachar("0") .and. ascii_rep<=iachar("9") ) then
82  is_digit=.true.
83  else
84  is_digit = .false.
85  endif
86  end function is_digit
87 
88 
89  !>
90  !! @brief Function to decide whether a character is a mathematical operator
91  !! or not. Functions (as e.g., sin) are not defined here!
92  !!
93  !! ### Example
94  !!~~~~~~~~~~~~~~.f90
95  !! b = is_operator("+")
96  !! c = is_operator("5")
97  !!~~~~~~~~~~~~~~
98  !! b will be .True. and c will be .False.
99  !!
100  !! @see is_line_operator, is_power_operator, is_separator, is_dot_operator
101  !!
102  !! @author Moritz Reichert
103  !! @date 20.12.20
104  function is_operator(str_in)
105  implicit none
106  character(1),intent(in) :: str_in !< Input character
107  logical :: is_operator !< True in case of an operator (+,-,*,/,^) and False otherwise
108 
109  select case(str_in)
110  case('+')
111  is_operator = .true.
112  case('-')
113  is_operator = .true.
114  case('*')
115  is_operator = .true.
116  case('/')
117  is_operator = .true.
118  case('^')
119  is_operator = .true.
120  case default
121  is_operator = .false.
122  end select
123 
124  end function is_operator
125 
126 
127  !>
128  !! @brief Function to decide whether a character is "*" or "/"
129  !!
130  !! ### Example
131  !!~~~~~~~~~~~~~~.f90
132  !! b = is_dot_operator("+")
133  !! c = is_dot_operator("*")
134  !!~~~~~~~~~~~~~~
135  !! b will be .False. and c will be .True.
136  !!
137  !! @see is_line_operator, is_power_operator, is_separator, is_operator
138  !!
139  !! @author Moritz Reichert
140  !! @date 20.12.20
141  function is_dot_operator(str_in)
142  implicit none
143  character(1),intent(in) :: str_in !< Input character
144  logical :: is_dot_operator !< True in case of a * or / input string and False otherwise
145 
146  select case(str_in)
147  case('*')
148  is_dot_operator = .true.
149  case('/')
150  is_dot_operator = .true.
151  case default
152  is_dot_operator = .false.
153  end select
154 
155  end function is_dot_operator
156 
157 
158  !>
159  !! @brief Function to decide whether a character is a "+" or "-"
160  !!
161  !! ### Example
162  !!~~~~~~~~~~~~~~.f90
163  !! b = is_line_operator("+")
164  !! c = is_line_operator("*")
165  !!~~~~~~~~~~~~~~
166  !! b will be .True. and c will be .False.
167  !!
168  !! @see is_dot_operator, is_power_operator, is_separator, is_operator
169  !!
170  !! @author Moritz Reichert
171  !! @date 20.12.20
172  function is_line_operator(str_in)
173  implicit none
174  character(1),intent(in) :: str_in !< Input character
175  logical :: is_line_operator !< True in case of a + or - input string and False otherwise
176 
177  select case(str_in)
178  case('+')
179  is_line_operator = .true.
180  case('-')
181  is_line_operator = .true.
182  case default
183  is_line_operator = .false.
184  end select
185 
186  end function is_line_operator
187 
188 
189  !>
190  !! @brief Function to decide whether a character is a "^"
191  !!
192  !! ### Example
193  !!~~~~~~~~~~~~~~.f90
194  !! b = is_power_operator("^")
195  !! c = is_power_operator("-")
196  !!~~~~~~~~~~~~~~
197  !! b will be .True. and c will be .False.
198  !!
199  !! @see is_dot_operator, is_line_operator, is_separator, is_operator
200  !!
201  !! @author Moritz Reichert
202  !! @date 20.12.20
203  function is_power_operator(str_in)
204  implicit none
205  character(1),intent(in) :: str_in !< Input character
206  logical :: is_power_operator !< True in case of a ^ input string and False otherwise
207 
208  select case(str_in)
209  case('^')
210  is_power_operator = .true.
211  case default
212  is_power_operator = .false.
213  end select
214 
215  end function is_power_operator
216 
217 
218  !>
219  !! @brief Function to decide whether a character can be associated with a number.
220  !!
221  !! Allowed characters are ".", "d", and "e"
222  !! (for scientific format of a number).
223  !!
224  !! ### Example
225  !!~~~~~~~~~~~~~~.f90
226  !! b = is_separator(",")
227  !! c = is_separator("-")
228  !!~~~~~~~~~~~~~~
229  !! b will be .True. and c will be .False.
230  !!
231  !! @see is_dot_operator, is_line_operator, is_separator, is_operator, is_power_operator
232  !!
233  !! @author Moritz Reichert
234  !! @date 20.12.20
235  function is_separator(str_in)
236  implicit none
237  character(1),intent(in) :: str_in !< Input character
238  logical :: is_separator !< True in case of a ",", "d", and "e" input string and False otherwise
239 
240  select case(str_in)
241  case('.')
242  is_separator = .true.
243  case('d')
244  is_separator = .true.
245  case('e')
246  is_separator = .true.
247  case default
248  is_separator = .false.
249  end select
250 
251  end function is_separator
252 
253 
254  !>
255  !! @brief Function to perform a simple mathematical operation.
256  !!
257  !! Depending on the input character, the function performs
258  !! "+". "-", "*", "/", or "^". In case of a different character, an
259  !! error is raised.
260  !!
261  !! ### Example
262  !!~~~~~~~~~~~~~~.f90
263  !! b = operation(10.3, 2.7, "+")
264  !!~~~~~~~~~~~~~~
265  !! b will be 13.
266  !!
267  !! @author Moritz Reichert
268  !! @date 20.12.20
269  function operation(number_1,number_2,str_in)
270  implicit none
271  character(1),intent(in) :: str_in !< Input character (containing "+","-","*","/","^".)
272  real(r_kind) :: operation !< Result of a certain operation of number_1 and number_2, determined by the input string.
273  real(r_kind) :: number_1,number_2 !< Input numbers on which the operation is performed
274 
275  select case(str_in)
276  case('+')
277  operation = number_1+number_2
278  case('-')
279  operation = number_1-number_2
280  case('*')
281  operation = number_1*number_2
282  case('/')
283  operation = number_1/number_2
284  case('^')
285  operation = number_1**number_2
286  case default
287  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
288  "."//new_line("A")//'Unknown operator "'//&
289  trim(adjustl(str_in))//'".',"operation",&
290  360003)
291  end select
292 
293  end function operation
294 
295 
296  !>
297  !! @brief Function to perform a function operations.
298  !!
299  !! Depending on the input it will calculate,
300  !! e.g., the square root (sqrt) or the sinus (sin).
301  !! To add a function to the functionality of the parser,
302  !! add the translation in this function here.
303  !!
304  !! ### Example
305  !!~~~~~~~~~~~~~~.f90
306  !! b = eval_function(4, "sqrt")
307  !!~~~~~~~~~~~~~~
308  !! b will be 2.
309  !!
310  !! @note New parsing functions can be defined here.
311  !!
312  !! @author Moritz Reichert
313  !! @date 20.12.20
314  function eval_function(number,str_in)
315  implicit none
316  character(max_fname_len),intent(in) :: str_in !< Name of the function
317  real(r_kind),intent(in) :: number !< input to the function
318  real(r_kind) :: eval_function!< function(number), where function is defined by the input string.
319 
320  select case(trim(adjustl(str_in)))
321  case('abs')
322  eval_function =abs(number)
323  case('sqrt')
324  eval_function =sqrt(number)
325  case('log')
326  eval_function =log10(number)
327  case('ln')
328  eval_function =log(number)
329  case('exp')
330  eval_function =exp(number)
331  case('sin')
332  eval_function =sin(number)
333  case('asin')
334  eval_function =asin(number)
335  case('cos')
336  eval_function =cos(number)
337  case('acos')
338  eval_function =acos(number)
339  case('tan')
340  eval_function =tan(number)
341  case('atan')
342  eval_function =atan(number)
343  case default
344  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
345  "."//new_line("A")//'Function "'//trim(adjustl(str_in))//&
346  '" not known.',"eval_function",360004)
347  end select
348  end function eval_function
349 
350 
351  !>
352  !! @brief Subroutine to check the parsing string for consistency and correct it.
353  !!
354  !! This subroutine will convert all characters to lower case characters
355  !! (e.g., 4E-1 -> 4e-1) and will add a leading "0" in case the string starts
356  !! with a mathematical operator (i.e., + or -, e.g., "-3+5" -> "0-3+5").
357  !! Furthermore, it checks for "+-" (and "++", "--" and all combinations)
358  !! and will correct it to "-". Additionally "**" is corrected to "^",
359  !! in this way the power can be written by both (**, and ^).
360  !!
361  !! ### Example
362  !!~~~~~~~~~~~~~~.f90
363  !! parsing_string = "-2+-3**2"
364  !! call make_pars_str_consistent()
365  !!~~~~~~~~~~~~~~
366  !! After this, parsing_string will be "0-2-3^2"
367  !!
368  !! @returns A corrected string that can be parsed by other functions
369  !!
370  !! @author Moritz Reichert
371  !! @date 20.12.20
373  implicit none
374  integer :: i,j !< Loop variables
375  integer :: max_length_tmp !< Length of the string without spaces
376  logical :: still_busy !< Flag to check if the string still have to change
377 
378  max_length_tmp = len(trim(adjustl(parsing_string)))
379  ! Convert the string to lower case letters to avoid problems
380  do i = 1, max_length_tmp
381  j = iachar(parsing_string(i:i))
382  if (j>= iachar("A") .and. j<=iachar("Z") ) then
383  parsing_string(i:i) = achar(iachar(parsing_string(i:i))+32)
384  else
385  cycle
386  end if
387  end do
388 
389  ! its a problem if the string starts with a minus or a plus
390  if ((parsing_string(1:1) .eq. '-') .or. (parsing_string(1:1) .eq. '+')) then
391  parsing_string = '0'//trim(adjustl(parsing_string))
392  end if
393 
394  ! Loop through string to check for "++", "--", or "+-"
395  still_busy = .true.
396  do while (still_busy)
397  still_busy = .false.
398  do i=2,max_length_tmp
399  ! +- is equal to -
400  if (((parsing_string(i:i) .eq. '+') .and. (parsing_string(i-1:i-1) .eq. '-')) &
401  & .or.((parsing_string(i-1:i-1) .eq. '+') .and. (parsing_string(i:i) .eq. '-'))) then
402  parsing_string = parsing_string(1:i-2)//' -'//parsing_string(i+1:)
403  still_busy = .true.
404  ! -- is equal to +
405  else if ((parsing_string(i:i) .eq. '-') .and. (parsing_string(i-1:i-1) .eq. '-')) then
406  parsing_string = parsing_string(1:i-2)//' +'//parsing_string(i+1:)
407  still_busy = .true.
408  ! ++ is equal to +
409  else if ((parsing_string(i:i) .eq. '+') .and. (parsing_string(i-1:i-1) .eq. '+')) then
410  parsing_string = parsing_string(1:i-2)//' +'//parsing_string(i+1:)
411  still_busy = .true.
412  ! ** is equal to ^
413  else if ((parsing_string(i:i) .eq. '*') .and. (parsing_string(i-1:i-1) .eq. '*')) then
414  parsing_string = parsing_string(1:i-2)//' ^'//parsing_string(i+1:)
415  still_busy = .true.
416  end if
417  end do
418  end do
419 
420  end subroutine make_pars_str_consistent
421 
422 
423  !>
424  !! @brief Function to define constants.
425  !!
426  !! This function translates names of constants
427  !! to numbers (real). For example, "pi" is
428  !! translated to 3.1415. Define new constants
429  !! (names and values) in this function.
430  !!
431  !! ### Example
432  !!~~~~~~~~~~~~~~.f90
433  !! b = common_variables("pi")
434  !!~~~~~~~~~~~~~~
435  !! After this, will be 3.141592653589793
436  !!
437  !! @note New variables can be defined here.
438  !!
439  !! @author Moritz Reichert
440  !! @date 20.12.20
441  function common_variables(inp_str)
442  implicit none
443  character(len=*),intent(in) :: inp_str !< Input character, defining the constant
444  real(r_kind) :: common_variables !< A value of a given constant
445 
446  ! Return common variables to replace them in the equation
447  select case(trim(adjustl(inp_str)))
448  case('pi')
449  common_variables = 3.141592653589793
450  case('kb')
451  common_variables = 1.380649d-23
452  case('e')
453  common_variables = 2.718281828459045
454  case(variable_name)
456  case default ! If it is not known variable
457  common_variables = -1
458  end select
459 
460  end function common_variables
461 
462 
463  !>
464  !! @brief Store mathematical operators (+-*/) and numbers in arrays.
465  !!
466  !! The result of this subroutine are two arrays, one containing all
467  !! operators (e.g., for "3+2*2+1-1": ['+','*','+','-']) and one
468  !! array containing all numbers (as real type, [3,2,2,1,1]).
469  !!
470  !! ### Example
471  !!~~~~~~~~~~~~~~.f90
472  !! parsing_string = "0-2-3^2"
473  !! call store_digits_operator()
474  !!~~~~~~~~~~~~~~
475  !! After this, the array \ref operators will contain ("-","-","^"), and
476  !! the array \ref numbers will contain (0, 2, 3, 2).
477  !!
478  !! @author Moritz Reichert
479  !! @date 20.12.20
481  implicit none
482  integer :: i !< Loop variable
483  integer :: istat !< status variable
484  integer :: o_c_tmp !< temporary operator count
485  character(max_fname_len) :: digit_tmp !< temporary storage for numbers
486  character(max_fname_len) :: internal_pars!< internal parsing string
487  real(r_kind) :: tmp_storage !< helper variable to replace constants
488 
489  ! Remove things from the parsing string and bring it
490  ! to a shape that this subroutine can deal with
492  internal_pars = parsing_string
493 
494  ! Count the amount of operators
495  operator_count = 0
496  do i = 2,max_fname_len
497  if ((is_operator(internal_pars(i:i))) &
498  & .and. (.not. is_separator(internal_pars(i-1:i-1))) &
499  & .and. (.not. is_operator(internal_pars(i-1:i-1)))) then
501  endif
502  end do
503  number_count = operator_count +1 ! amount of numbers
504 
505  ! deallocate if they are allocated
506  if (allocated(operators)) then
507  deallocate(operators)
508  deallocate(numbers)
509  end if
510 
511  allocate(operators(operator_count),numbers(number_count),stat=istat)
512  if (istat /= 0) then
513  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
514  "."//new_line("A")//&
515  'Allocation of "operators" failed.',&
516  "store_digits_operator",360001)
517  end if
518  o_c_tmp = 0
519  digit_tmp = trim(adjustl(internal_pars(1:1))) ! It starts with a digit by defintion
520  ! Count the amount of operators
521  do i = 2,max_fname_len
522 
523  ! Store operators and numbers
524  if ((is_operator(internal_pars(i:i)))&
525  & .and. (.not. is_separator(internal_pars(i-1:i-1))) &
526  & .and. (.not. is_operator(internal_pars(i-1:i-1)))) then
527  o_c_tmp = o_c_tmp+1
528  operators(o_c_tmp) = internal_pars(i:i)
529 
530  tmp_storage = common_variables(digit_tmp)
531  if (tmp_storage .ne. -1) then ! It was a known variable name
532  numbers(o_c_tmp) = tmp_storage
533  else
534  read( digit_tmp, *,iostat=istat) numbers(o_c_tmp)
535  if (istat /= 0) then ! Complain if something went wrong in conversion
536  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
537  "."//new_line("A")//&
538  'Could not convert "'//trim(adjustl(digit_tmp))//'" to float.',&
539  "store_digits_operator",360005)
540  end if
541  end if
542  digit_tmp = ''
543  elseif (i .eq. max_fname_len-1) then ! Also store the last number
544  o_c_tmp = o_c_tmp+1
545  tmp_storage = common_variables(digit_tmp)
546  if (tmp_storage .ne. -1) then ! It was a known variable name
547  numbers(o_c_tmp) = tmp_storage
548  else ! otherwise read in the hopefully valid number
549  read( digit_tmp, *,iostat=istat) numbers(o_c_tmp)
550  if (istat /= 0) then ! Complain if something went wrong in conversion
551  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
552  "."//new_line("A")//&
553  'Could not convert "'//trim(adjustl(digit_tmp))//'" to float.',&
554  "store_digits_operator",360005)
555  end if
556  end if
557  digit_tmp = ''
558  elseif ((.not. is_operator(internal_pars(i:i)))&
559  & .or. (is_separator(internal_pars(i-1:i-1))) &
560  & .or. (is_operator(internal_pars(i-1:i-1)))) then
561  ! Append all characters to a digit (operators reset this string)
562  digit_tmp = trim(adjustl(digit_tmp))//trim(adjustl(internal_pars(i:i)))
563  elseif (internal_pars(i:i) .eq. ' ') then ! skip blanks in string
564  cycle
565  else
566  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
567  "."//new_line("A")//&
568  'Unknown character. ',&
569  "store_digits_operator",360006)
570  end if
571 
572  end do
573  end subroutine store_digits_operator
574 
575 
576  !>
577  !! @brief Evaluate a simple string expression, without brackets and functions.
578  !!
579  !! This subroutine is able to evaluate simply expressions without
580  !! brackets or functions. Only +- * / and ^ is allowed here. In addition
581  !! a variable name or constant names may be given.
582  !! For example "2+3-1" will store the result (4) in the first entry
583  !! of the "numbers" array.
584  !!
585  !! ### Example
586  !!~~~~~~~~~~~~~~.f90
587  !! parsing_string = "0-2-3^2"
588  !! call get_simple_result()
589  !!~~~~~~~~~~~~~~
590  !! After this, the array \ref numbers will have -11 on its first entry.
591  !!
592  !! @author Moritz Reichert
593  !! @date 20.12.20
594  subroutine get_simple_result
595  implicit none
596  integer :: i,j !< Loop variables
597  integer :: operator_count_tmp !< Count variable
598  logical :: dot_operation !< still operations to do?
599  logical :: line_operation,power_operation !< still operations to do?
600  real(r_kind):: helper_result !< Helper variable for evaluation
601 
602  if (.not. allocated(operators)) then
603  call raise_exception('Could not parse: '//trim(adjustl(complete_string))//&
604  "."//new_line("A")//&
605  'Array "operators" was not allocated.',&
606  "get_simple_result",360007)
607  end if
608  ! Calculate first exponents, then dot operations ( * / ) and then line operations (+ -)
609  ! In German: "Punkt vor Strich ;)"
610 
611  operator_count_tmp = operator_count
612 
613  ! Power (^)
614  power_operation = .true.
615  do while(power_operation)
616  power_operation = .false.
617  innerloop_power: do i=1, operator_count_tmp
618  ! Skip if all operators have been processed
619  ! (the loop goes over the initial value of the variable)
620  if (i .gt. operator_count_tmp) exit innerloop_power
621 
622  ! Found "^"
623  if (is_power_operator(operators(i))) then
624  ! Evaluate the operation
625  helper_result = operation(numbers(i),numbers(i+1),operators(i))
626  numbers(i) = helper_result
627 
628  ! shift all operators and numbers forward
629  do j=i,operator_count_tmp-1
630  operators(j) = operators(j+1)
631  numbers(j+1) = numbers(j+2)
632  end do
633  ! Still things to do
634  power_operation=.true.
635  ! Still things to do
636  operator_count_tmp = operator_count_tmp -1
637  end if
638 
639  end do innerloop_power
640  end do
641 
642  ! Dot operations (* /)
643  dot_operation = .true.
644  do while(dot_operation)
645  dot_operation = .false.
646  innerloop_dot: do i=1, operator_count_tmp
647  ! Skip if all operators have been processed
648  ! (the loop goes over the initial value of the variable)
649  if (i .gt. operator_count_tmp) exit innerloop_dot
650  ! Found * or /
651  if (is_dot_operator(operators(i))) then
652  ! Evaluate the operation
653  helper_result = operation(numbers(i),numbers(i+1),operators(i))
654  numbers(i) = helper_result
655 
656  ! shift all operators and numbers forward
657  do j=i,operator_count_tmp-1
658  operators(j) = operators(j+1)
659  numbers(j+1) = numbers(j+2)
660  end do
661  ! Still things to do
662  dot_operation=.true.
663  ! One operation has been performed
664  operator_count_tmp = operator_count_tmp -1
665  end if
666 
667  end do innerloop_dot
668  end do
669 
670  ! Line operations (+ -)
671  line_operation = .true.
672  do while(line_operation)
673  line_operation = .false.
674  innerloop_line: do i=1, operator_count_tmp
675  ! Found + or -
676  if (is_line_operator(operators(i))) then
677  ! Evaluate the operation
678  helper_result = operation(numbers(i),numbers(i+1),operators(i))
679  numbers(i) = helper_result
680 
681  ! shift all operators and numbers forward
682  do j=i,operator_count_tmp-1
683  operators(j) = operators(j+1)
684  numbers(j+1) = numbers(j+2)
685  end do
686  ! Still things to do
687  line_operation=.true.
688  ! One operation has been performed
689  operator_count_tmp = operator_count_tmp -1
690  exit innerloop_line
691  end if
692  end do innerloop_line
693  end do
694 
695  end subroutine get_simple_result
696 
697 
698  !>
699  !! @brief Evaluate a complex string expression.
700  !!
701  !! Evaluate expressions with brackets ( i.e., "(" and ")" ) and
702  !! function names (i.e., "sin(5)" ).
703  !!
704  !! ### Example
705  !!~~~~~~~~~~~~~~.f90
706  !! parsing_string = "2+sin(pi)-5*(1+1)"
707  !! call evaluate()
708  !!~~~~~~~~~~~~~~
709  !! After this, the array \ref numbers will have -8 on its first entry.
710  !!
711  !! @author Moritz Reichert
712  !! @date 20.12.20
713  subroutine evaluate
714  implicit none
715  integer :: i !< Loop variable
716  character(max_fname_len) :: mod_expression
717  character(1) :: cc ! Current character in the loop
718  integer :: start_block
719  integer :: end_block,len_function_name
720  character(max_fname_len) :: string_res
721  logical :: is_busy
722  character(max_fname_len) :: function_name,function_store
723 
724  mod_expression = complete_string
725  is_busy=.true.
726 
727  ! Loop until nothing to do anymore
728  do while (is_busy)
729  is_busy = .false.
730  function_name = ''
731  inner_loop:do i=1,max_fname_len
732  ! Store the current character to make it shorter
733  cc = mod_expression(i:i)
734 
735  ! Ignore whitespaces
736  if (cc .eq. ' ') then
737  cycle
738  end if
739 
740  ! Keep track if a function is written in the expression
741  if ((is_operator(cc) .or. is_digit(cc))) then
742  function_name = ''
743  else
744  if (cc .ne. "(") then
745  function_name =trim(adjustl(function_name))//cc
746  end if
747  end if
748 
749  ! Store functions and position of opening brackets
750  if (mod_expression(i:i) .eq. '(') then
751  start_block = i+1
752  function_store=function_name
753  end if
754 
755  ! The first closing bracket marks the innermost brackets
756  if (mod_expression(i:i) .eq. ')') then
757  end_block = i-1
758  parsing_string = mod_expression(start_block:end_block)
759 
760  ! Evaluate this sub-block that only has simple operators
762  call get_simple_result
763 
764  ! Should also a function get executed?
765  if (trim(adjustl(function_store)) .ne. '') then
766  numbers(1)=eval_function(numbers(1),function_store)
767  len_function_name = len(trim(adjustl(function_store))) ! get the length of the function name
768  start_block = start_block-len_function_name ! Also remove the function in the string
769  end if
770 
771  write(string_res,*) numbers(1) ! The result is always stored in numbers(1) afterwards
772  mod_expression = mod_expression(1:start_block-2)//trim(adjustl(string_res))//mod_expression(end_block+2:max_fname_len)
773 
774  ! write(*,*) trim(adjustl(mod_expression))
775  is_busy = .true.
776  exit inner_loop
777  end if
778  end do inner_loop
779  end do
780 
781  ! Evaluate it a last time
782  parsing_string = mod_expression
784  call get_simple_result
785 
786  ! Now the final result is stored in numbers(1)
787  end subroutine evaluate
788 
789 
790  !>
791  !! @brief Takes a string and evaluates the expression
792  !!
793  !! This function is accessible to the outside of the module.
794  !! It serves as interface between other modules and this one.
795  !! Also replaces \ref variable_name with \ref variable_value.
796  !!
797  !! ### Example
798  !!~~~~~~~~~~~~~~.f90
799  !! b = parse_string("-8+3*(2-1)-x",10)
800  !!~~~~~~~~~~~~~~
801  !! After this, b will be -15.
802  !!
803  !!
804  !! @author Moritz Reichert
805  !! @date 20.12.20
806  function parse_string(input_string,var_value)
807  implicit none
808  character(300),intent(in) :: input_string !< String to parse
809  real(r_kind),intent(in) :: var_value !< Value of the variable that will be stored in \ref variable_value
810  real(r_kind) :: parse_string !< Value of the evaluated expression
811 
812  info_entry("PARSE_STRING")
813 
814  ! Store input in module variables
815  variable_value = var_value
816  complete_string = input_string
817 
818  ! Evaluate the expression
819  call evaluate
820 
821  ! Store the result
822  parse_string = numbers(1)
823 
824  ! deallocate the arrays if they are allocated
825  if (allocated(operators)) then
826  deallocate(operators)
827  deallocate(numbers)
828  end if
829 
830  info_exit("PARSE_STRING")
831  end function parse_string
832 
833 
834  !>
835  !! @brief Finds a value of the variable for a given y-value
836  !!
837  !! This function solves an equation, i.e., finds the value of
838  !! variable "x" for expressions as, for example, "3*x+2+x^2 = 10"
839  !! returns 1.701562. This works with a newton raphson to find
840  !! the root of f(x) - 10.
841  !!
842  !! ### Example
843  !!~~~~~~~~~~~~~~.f90
844  !! input_string = "3*x+2+x^2"
845  !! eq_value = 10
846  !! initial_guess = 0.0
847  !! converged = .False.
848  !! result = 0.0
849  !! call find_start_value(input_string,eq_value,initial_guess,converged,result)
850  !!~~~~~~~~~~~~~~
851  !! After this, result will be 1.701562 and converged will be .True.
852  !!
853  !! @author Moritz Reichert
854  !! @date 20.12.20
855  subroutine find_start_value(input_string,eq_value,initial_guess,converged,result)
856  implicit none
857  character(300),intent(in) :: input_string !< String to parse
858  real(r_kind),intent(in) :: eq_value !< Value of the equation
859  real(r_kind),intent(in) :: initial_guess !< Initial guess for the variable
860  logical,intent(out) :: converged !< Flag that indicates a success
861  real(r_kind),intent(out) :: result !< Time at which the expression is equal to eq_value.
862  real(r_kind) :: newguess !< guess if the initial one failed
863  integer :: i !< Loop variable
864  integer,parameter :: maxiter = 100 !< Maximum number of iterations
865  real(r_kind) :: y1,y2 !< values of f(x)-eq_value
866  real(r_kind) :: x1,x2,xnew !< x values of the variable
867  real(r_kind) :: m,b !< slope and intercept
868  real(r_kind),parameter :: diff = 1d-5 !< difference for the derivative
869  real(r_kind),parameter :: tol = 1d-5 !< tolerance for the convergence
870  integer :: try_count !< count how often the initial guess was changed
871  integer,parameter :: max_try_count = 10 !< maximum changes of the initial guess
872 
873  info_entry("FIND_START_VALUE")
874 
875  ! Set the first x-values
876  newguess=initial_guess
877  x1=newguess
878  x2=x1+diff
879 
880  ! The outer loop is to ensure several initial guesses if NR fails
881  converged = .false.
882  outer_loop: do try_count=1, max_try_count
883 
884  ! Newton-Raphson
885  do i=1, maxiter
886 
887  ! Calculate slope
888  y1 = parse_string(input_string,x1)-eq_value
889  y2 = parse_string(input_string,x2)-eq_value
890  if (x1 .ne. x2) then
891  m = (y1-y2)/(x1-x2)
892  else
893  converged = .false.
894  exit outer_loop
895  endif
896  ! calculate new x value
897  b = y1-m*x1
898 
899  ! Exit if the slope is zero
900  if (m .eq. 0) then
901  converged = .false.
902  ! Give a very large negative number
903  exit
904  end if
905 
906  xnew = -b/m
907 
908  ! Exit if converged
909  if (abs(x1-xnew) .lt. tol) then
910  converged = .true.
911  exit outer_loop
912  end if
913 
914  ! Reshuffle variables if it is not converged
915  x1 = xnew
916  x2 = x1+diff
917  end do
918 
919  ! Vary the initial guess
920  newguess = newguess+1d2
921  x1 = newguess
922  x2 = x1+diff
923  end do outer_loop
924 
925  ! Store the result
926  if (converged) result = xnew
927 
928  info_exit("FIND_START_VALUE")
929  end subroutine find_start_value
930 
931 end module parser_module
parser_module::is_line_operator
logical function, private is_line_operator(str_in)
Function to decide whether a character is a "+" or "-".
Definition: parser_module.f90:173
parser_module::evaluate
subroutine, private evaluate
Evaluate a complex string expression.
Definition: parser_module.f90:714
parser_module::complete_string
character(max_fname_len), private complete_string
Complete input string.
Definition: parser_module.f90:29
parser_module::operation
real(r_kind) function, private operation(number_1, number_2, str_in)
Function to perform a simple mathematical operation.
Definition: parser_module.f90:270
error_msg_class
Error handling routines.
Definition: error_msg_class.f90:16
parser_module::is_dot_operator
logical function, private is_dot_operator(str_in)
Function to decide whether a character is "*" or "/".
Definition: parser_module.f90:142
error_msg_class::int_to_str
character(:) function, allocatable, public int_to_str(num)
Converts a given integer to a string.
Definition: error_msg_class.f90:224
error_msg_class::raise_exception
subroutine, public raise_exception(msg, sub, error_code)
Raise a exception with a given error message.
Definition: error_msg_class.f90:245
parser_module::is_power_operator
logical function, private is_power_operator(str_in)
Function to decide whether a character is a "^".
Definition: parser_module.f90:204
parser_module::eval_function
real(r_kind) function, private eval_function(number, str_in)
Function to perform a function operations.
Definition: parser_module.f90:315
parameter_class::max_fname_len
integer, parameter, public max_fname_len
maximum length of filenames
Definition: parameter_class.f90:58
parser_module::variable_value
real(r_kind), private variable_value
Input variable, set by parse_string.
Definition: parser_module.f90:37
parser_module::operator_count
integer, private operator_count
Definition: parser_module.f90:32
parser_module::get_simple_result
subroutine, private get_simple_result
Evaluate a simple string expression, without brackets and functions.
Definition: parser_module.f90:595
parser_module::number_count
integer, private number_count
Definition: parser_module.f90:32
parser_module::numbers
real(r_kind), dimension(:), allocatable, private numbers
Array containing the numbers of the equation (e.g., [1, 2, 3])
Definition: parser_module.f90:34
parser_module
Subroutines for equation parsing in case of an analytic trajectory or luminosity mode.
Definition: parser_module.f90:22
parser_module::make_pars_str_consistent
subroutine, private make_pars_str_consistent
Subroutine to check the parsing string for consistency and correct it.
Definition: parser_module.f90:373
parser_module::find_start_value
subroutine, public find_start_value(input_string, eq_value, initial_guess, converged, result)
Finds a value of the variable for a given y-value.
Definition: parser_module.f90:856
parser_module::variable_name
character(1), parameter, private variable_name
Name of the variable that is replaced by parse_string.
Definition: parser_module.f90:38
parser_module::parse_string
real(r_kind) function, public parse_string(input_string, var_value)
Takes a string and evaluates the expression.
Definition: parser_module.f90:807
error_msg_class::num_to_str
character(:) function, allocatable, public num_to_str(num)
Converts a given real to a string with format "(1pE10.2)".
Definition: error_msg_class.f90:205
parser_module::common_variables
real(r_kind) function, private common_variables(inp_str)
Function to define constants.
Definition: parser_module.f90:442
r_kind
#define r_kind
Definition: macros.h:46
parser_module::operators
character(1), dimension(:), allocatable, private operators
Array containing the operations of the equation as a character (e.g., ["*","+"])
Definition: parser_module.f90:33
parser_module::is_digit
logical function, private is_digit(str_in)
Function to decide whether a character is a number or not (i.e., 0-9).
Definition: parser_module.f90:74
parser_module::is_operator
logical function, private is_operator(str_in)
Function to decide whether a character is a mathematical operator or not. Functions (as e....
Definition: parser_module.f90:105
parser_module::parsing_string
character(max_fname_len), private parsing_string
Current substring to parse.
Definition: parser_module.f90:28
parser_module::store_digits_operator
subroutine, private store_digits_operator
Store mathematical operators (+-*/) and numbers in arrays.
Definition: parser_module.f90:481
parameter_class
Contains all runtime parameters as well as phys and math constants.
Definition: parameter_class.f90:24
parser_module::is_separator
logical function, private is_separator(str_in)
Function to decide whether a character can be associated with a number.
Definition: parser_module.f90:236