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  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  end function get_mem_path_context
155 
156  !> @brief Remove the context from the memory path
157  !!
158  !! NB: when there is no context in the memory path, the
159  !! original memory path is returned.
160  !<
161  subroutine strip_context_mem_path(mem_path, mem_path_no_context)
162  character(len=*), intent(in) :: mem_path !< path to the memory object
163  character(len=LENMEMPATH), intent(inout) :: mem_path_no_context !< path to the memory object without the context
164  ! local
165  integer(I4B) :: idx
166  character(len=LENMEMPATH) :: context
167 
168  ! initialize the local mem_path
169  mem_path_no_context = mem_path
170 
171  context = get_mem_path_context(mem_path)
172 
173  if (len_trim(context) > 0) then
174  idx = len_trim(context)
175  mem_path_no_context = mem_path(idx + 1:)
176  end if
177 
178  end subroutine strip_context_mem_path
179 
180  !> @brief Generic routine to check the length of (parts of) the memory address
181  !!
182  !! The string will be trimmed before the measurement.
183  !!
184  !! @warning{if the length exceeds the maximum, a message is recorded
185  !! and the program will be stopped}
186  !!
187  !! The description should describe the part of the address that is checked
188  !! (variable, package, model, solution, exchange name) or the full memory path
189  !! itself
190  !<
191  subroutine mem_check_length(name, max_length, description)
192  character(len=*), intent(in) :: name !< string to be checked
193  integer(I4B), intent(in) :: max_length !< maximum length
194  character(len=*), intent(in) :: description !< a descriptive string
195 
196  if (len(trim(name)) > max_length) then
197  write (errmsg, '(*(G0))') &
198  'Fatal error in Memory Manager, length of ', description, ' must be ', &
199  max_length, ' characters or less: ', name, '(len=', len(trim(name)), ')'
200 
201  ! -- store error and stop program execution
202  call store_error(errmsg, terminate=.true.)
203  end if
204 
205  end subroutine mem_check_length
206 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