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