MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
MemoryHelper.f90
Go to the documentation of this file.
2  use kindmodule, only: i4b, lgp
5  use simmodule, only: store_error
6  use simvariablesmodule, only: errmsg
7 
8  implicit none
9 
10  character(len=LENMEMSEPARATOR), parameter :: mempathseparator = '/' !< used to build up the memory address for the stored variables
11 
12 contains
13 
14  !> @brief returns the path to the memory object
15  !!
16  !! Returns the path to the location in the memory manager where
17  !! the variables for this (sub)component are stored, the 'memoryPath'
18  !!
19  !! NB: no need to trim the input parameters
20  !<
21  function create_mem_path(component, subcomponent, context) result(memory_path)
22  character(len=*), intent(in) :: component !< name of the solution, model, or exchange
23  character(len=*), intent(in), optional :: subcomponent !< name of the package (optional)
24  character(len=*), intent(in), optional :: context !< name of the context (optional)
25  character(len=LENMEMPATH) :: memory_path !< the memory path
26 
27  call mem_check_length(component, lencomponentname, "solution/model/exchange")
28  call mem_check_length(subcomponent, lencomponentname, "package")
29  call mem_check_length(context, lencontextname, "context")
30 
31  memory_path = trim(component)
32 
33  if (present(subcomponent)) then
34  memory_path = trim(memory_path)//mempathseparator//trim(subcomponent)
35  end if
36 
37  if (present(context)) then
38  memory_path = trim(context)//mempathseparator//trim(memory_path)
39  end if
40 
41  end function create_mem_path
42 
43  !> @brief returns the address string of the memory object
44  !!
45  !! Returns the memory address, i.e. the full path plus name of the stored variable
46  !!
47  !! NB: no need to trim the input parameters
48  !<
49  function create_mem_address(mem_path, var_name) result(mem_address)
50  character(len=*), intent(in) :: mem_path !< path to the memory object
51  character(len=*), intent(in) :: var_name !< name of the stored variable
52  character(len=LENMEMADDRESS) :: mem_address !< full address string to the memory object
53 
54  call mem_check_length(mem_path, lenmempath, "memory path")
55  call mem_check_length(var_name, lenvarname, "variable")
56 
57  mem_address = trim(mem_path)//mempathseparator//trim(var_name)
58 
59  end function create_mem_address
60 
61  !> @brief Split a memory address string into memory path and variable name
62  !<
63  subroutine split_mem_address(mem_address, mem_path, var_name, success)
64  character(len=*), intent(in) :: mem_address !< the full memory address string
65  character(len=LENMEMPATH), intent(out) :: mem_path !< the memory path
66  character(len=LENVARNAME), intent(out) :: var_name !< the variable name
67  logical(LGP), intent(out) :: success !< true when successful
68  ! local
69  integer(I4B) :: idx
70 
71  idx = index(mem_address, mempathseparator, back=.true.)
72 
73  ! if no separator, or it's at the end of the string,
74  ! the memory address is not valid:
75  if (idx < 1 .or. idx == len(mem_address)) then
76  success = .false.
77  mem_path = ''
78  var_name = ''
79  else
80  success = .true.
81  mem_path = mem_address(:idx - 1)
82  var_name = mem_address(idx + 1:)
83  end if
84 
85  ! remove context specifier if prepended to mempath
86  !if (success) then
87  ! idx = index(mem_path, memPathSeparator, back=.true.)
88  ! if (idx > 0 .and. mem_path(1:2) == '__') then
89  ! mem_path = mem_path(idx + 1:)
90  ! end if
91  !end if
92 
93  end subroutine split_mem_address
94 
95  !> @brief Split the memory path into component(s)
96  !!
97  !! NB: when there is no subcomponent in the path, the
98  !! value for @par subcomponent is set to an empty string.
99  !<
100  subroutine split_mem_path(mem_path, component, subcomponent)
101  character(len=*), intent(in) :: mem_path !< path to the memory object
102  character(len=LENCOMPONENTNAME), intent(out) :: component !< name of the component (solution, model, exchange)
103  character(len=LENCOMPONENTNAME), intent(out) :: subcomponent !< name of the subcomponent (package)
104  ! local
105  character(len=LENMEMPATH) :: local_mem_path
106  integer(I4B) :: idx
107 
108  call strip_context_mem_path(mem_path, local_mem_path)
109 
110  idx = index(local_mem_path, mempathseparator, back=.true.)
111  ! if the separator is found at the end of the string,
112  ! the path is invalid:
113  if (idx == len_trim(local_mem_path)) then
114  write (errmsg, '(*(G0))') &
115  'Fatal error in Memory Manager, cannot split invalid memory path: ', &
116  mem_path
117 
118  ! -- store error and stop program execution
119  call store_error(errmsg, terminate=.true.)
120  end if
121 
122  if (idx > 0) then
123  ! when found:
124  component = local_mem_path(:idx - 1)
125  subcomponent = local_mem_path(idx + 1:)
126  else
127  ! when not found, there apparently is no subcomponent:
128  component = local_mem_path(:lencomponentname)
129  subcomponent = ''
130  end if
131 
132  end subroutine split_mem_path
133 
134  !> @brief Return the context from the memory path
135  !!
136  !! NB: when there is no context in the memory path, a
137  !! empty character string is returned.
138  !<
139  function get_mem_path_context(mem_path) result(res)
140  character(len=*), intent(in) :: mem_path !< path to the memory object
141  character(len=LENMEMPATH) :: res !< memory path context
142  ! local
143  integer(I4B) :: idx
144 
145  ! initialize the memory path context
146  res = ' '
147 
148  if (mem_path(1:2) == '__') then
149  idx = index(mem_path, mempathseparator)
150  if (idx > 0) then
151  res = mem_path(:idx)
152  end if
153  end if
154 
155  return
156 
157  end function get_mem_path_context
158 
159  !> @brief Remove the context from the memory path
160  !!
161  !! NB: when there is no context in the memory path, the
162  !! original memory path is returned.
163  !<
164  subroutine strip_context_mem_path(mem_path, mem_path_no_context)
165  character(len=*), intent(in) :: mem_path !< path to the memory object
166  character(len=LENMEMPATH), intent(inout) :: mem_path_no_context !< path to the memory object without the context
167  ! local
168  integer(I4B) :: idx
169  character(len=LENMEMPATH) :: context
170 
171  ! initialize the local mem_path
172  mem_path_no_context = mem_path
173 
174  context = get_mem_path_context(mem_path)
175 
176  if (len_trim(context) > 0) then
177  idx = len_trim(context)
178  mem_path_no_context = mem_path(idx + 1:)
179  end if
180 
181  end subroutine strip_context_mem_path
182 
183  !> @brief Generic routine to check the length of (parts of) the memory address
184  !!
185  !! The string will be trimmed before the measurement.
186  !!
187  !! @warning{if the length exceeds the maximum, a message is recorded
188  !! and the program will be stopped}
189  !!
190  !! The description should describe the part of the address that is checked
191  !! (variable, package, model, solution, exchange name) or the full memory path
192  !! itself
193  !<
194  subroutine mem_check_length(name, max_length, description)
195  character(len=*), intent(in) :: name !< string to be checked
196  integer(I4B), intent(in) :: max_length !< maximum length
197  character(len=*), intent(in) :: description !< a descriptive string
198 
199  if (len(trim(name)) > max_length) then
200  write (errmsg, '(*(G0))') &
201  'Fatal error in Memory Manager, length of ', description, ' must be ', &
202  max_length, ' characters or less: ', name, '(len=', len(trim(name)), ')'
203 
204  ! -- store error and stop program execution
205  call store_error(errmsg, terminate=.true.)
206  end if
207 
208  end subroutine mem_check_length
209 end module memoryhelpermodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter lencomponentname
maximum length of a component name
Definition: Constants.f90:18
integer(i4b), parameter lenmemaddress
maximum length of the full memory address, including variable name
Definition: Constants.f90:30
integer(i4b), parameter lenmemseparator
maximum length of the memory path separator used, currently a '/'
Definition: Constants.f90:25
integer(i4b), parameter lenvarname
maximum length of a variable name
Definition: Constants.f90:17
integer(i4b), parameter lencontextname
maximum length of a memory manager context
Definition: Constants.f90:19
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:26
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmemseparator), parameter mempathseparator
used to build up the memory address for the stored variables
character(len=lenmempath) function get_mem_path_context(mem_path)
Return the context from the memory path.
subroutine split_mem_address(mem_address, mem_path, var_name, success)
Split a memory address string into memory path and variable name.
subroutine mem_check_length(name, max_length, description)
Generic routine to check the length of (parts of) the memory address.
subroutine strip_context_mem_path(mem_path, mem_path_no_context)
Remove the context from the memory path.
character(len=lenmemaddress) function create_mem_address(mem_path, var_name)
returns the address string of the memory object
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
subroutine split_mem_path(mem_path, component, subcomponent)
Split the memory path into component(s)
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string