Line data Source code
1 : !> \file mo_common_read_config.f90
2 : !> \brief \copybrief mo_common_read_config
3 : !> \details \copydetails mo_common_read_config
4 :
5 : !> \brief Reading of main model configurations.
6 : !> \details This routine reads the configurations of namelists commonly used by mHM, mRM and MPR
7 : !> \authors Matthias Zink
8 : !> \date Dec 2012
9 : !> \copyright Copyright 2005-\today, the mHM Developers, Luis Samaniego, Sabine Attinger: All rights reserved.
10 : !! mHM is released under the LGPLv3+ license \license_note
11 : !> \ingroup f_common
12 : MODULE mo_common_read_config
13 :
14 : USE mo_kind, ONLY : i4, dp
15 : use mo_message, only: error_message
16 :
17 : IMPLICIT NONE
18 :
19 : PRIVATE
20 :
21 : PUBLIC :: common_read_config, set_land_cover_scenes_id
22 :
23 : ! ------------------------------------------------------------------
24 :
25 : CONTAINS
26 :
27 :
28 : !> \brief Read main configurations commonly used by mHM, mRM and MPR
29 : !> \details Read the main configurations commonly used by mHM, mRM and MPR, namely:
30 : !! project_description, directories_general, mainconfig, processSelection, LCover
31 : !> \changelog
32 : !! - Robert Schweppe Dec 2018
33 : !! - refactoring and restructuring
34 : !! - Sebastian Müller Mar 2023
35 : !! - added check_L0Domain
36 : !> \authors Matthias Zink
37 : !> \date Dec 2012
38 14 : subroutine common_read_config(file_namelist, unamelist)
39 :
40 : use mo_common_constants, only : maxNLcovers, maxNoDomains
41 : use mo_common_variables, only : Conventions, LC_year_end, LC_year_start, LCfilename, contact, &
42 : dirCommonFiles, dirConfigOut, dirLCover, dirMorpho, dirOut, &
43 : mhmFileRestartOut, mrmFileRestartOut, &
44 : fileLatLon, history, iFlag_cordinate_sys, mHM_details, domainMeta, nLcoverScene, &
45 : nProcesses, nuniqueL0Domains, processMatrix, project_details, resolutionHydrology, &
46 : setup_description, simulation_type, write_restart
47 : use mo_nml, only : close_nml, open_nml, position_nml
48 : use mo_string_utils, only : num2str
49 :
50 : implicit none
51 :
52 : !> name of file
53 : character(*), intent(in) :: file_namelist
54 :
55 : !> id of file
56 : integer, intent(in) :: unamelist
57 :
58 : ! Choosen process description number
59 : integer(i4), dimension(nProcesses) :: processCase
60 :
61 : character(256), dimension(maxNoDomains) :: dir_Morpho
62 :
63 : character(256), dimension(maxNoDomains) :: mhm_file_RestartOut
64 :
65 : character(256), dimension(maxNoDomains) :: mrm_file_RestartOut
66 :
67 : character(256), dimension(maxNoDomains) :: dir_LCover
68 :
69 : character(256), dimension(maxNoDomains) :: dir_Out
70 :
71 : character(256), dimension(maxNoDomains) :: file_LatLon
72 :
73 714 : real(dp), dimension(maxNoDomains) :: resolution_Hydrology
74 :
75 : integer(i4), dimension(maxNoDomains) :: L0Domain
76 :
77 : integer(i4), dimension(maxNoDomains) :: read_opt_domain_data
78 :
79 : ! starting year LCover
80 : integer(i4), dimension(maxNLCovers) :: LCoverYearStart
81 :
82 : ! ending year LCover
83 : integer(i4), dimension(maxNLCovers) :: LCoverYearEnd
84 :
85 : ! filename of Lcover file
86 : character(256), dimension(maxNLCovers) :: LCoverfName
87 :
88 : integer(i4) :: i, newDomainID, domainID, iDomain, nDomains
89 :
90 : ! flag to advance nuniqueL0Domain counter
91 : logical :: addCounter
92 :
93 :
94 : ! define namelists
95 : ! namelist directories
96 : namelist /project_description/ project_details, setup_description, simulation_type, &
97 : Conventions, contact, mHM_details, history
98 : namelist /directories_general/ dirConfigOut, dirCommonFiles, &
99 : dir_Morpho, dir_LCover, &
100 : dir_Out, mhm_file_RestartOut, mrm_file_RestartOut, &
101 : file_LatLon
102 : ! namelist spatial & temporal resolution, optimization information
103 : namelist /mainconfig/ iFlag_cordinate_sys, resolution_Hydrology, nDomains, L0Domain, write_restart, &
104 : read_opt_domain_data
105 : ! namelist process selection
106 : namelist /processSelection/ processCase
107 :
108 : ! namelist for land cover scenes
109 : namelist/LCover/nLcoverScene, LCoverYearStart, LCoverYearEnd, LCoverfName
110 :
111 : !===============================================================
112 : ! Read namelist main directories
113 : !===============================================================
114 14 : call open_nml(file_namelist, unamelist, quiet = .true.)
115 :
116 : !===============================================================
117 : ! Read namelist specifying the project description
118 : !===============================================================
119 14 : call position_nml('project_description', unamelist)
120 14 : read(unamelist, nml = project_description)
121 :
122 : !===============================================================
123 : ! Read namelist specifying the model configuration
124 : !===============================================================
125 14 : call position_nml('mainconfig', unamelist)
126 14 : read(unamelist, nml = mainconfig)
127 :
128 14 : call init_domain_variable(nDomains, read_opt_domain_data(1:nDomains), domainMeta)
129 :
130 14 : if (nDomains .GT. maxNoDomains) then
131 0 : call error_message('***ERROR: Number of domains is resticted to ', trim(num2str(maxNoDomains)), '!')
132 : end if
133 :
134 14 : call check_L0Domain(L0Domain, nDomains)
135 :
136 : ! allocate patharray sizes
137 42 : allocate(resolutionHydrology(domainMeta%nDomains))
138 42 : allocate(dirMorpho(domainMeta%nDomains))
139 28 : allocate(mhmFileRestartOut(domainMeta%nDomains))
140 28 : allocate(mrmFileRestartOut(domainMeta%nDomains))
141 28 : allocate(dirLCover(domainMeta%nDomains))
142 28 : allocate(dirOut(domainMeta%nDomains))
143 28 : allocate(fileLatLon(domainMeta%nDomains))
144 42 : allocate(domainMeta%L0DataFrom(domainMeta%nDomains))
145 28 : allocate(domainMeta%optidata(domainMeta%nDomains))
146 28 : allocate(domainMeta%doRouting(domainMeta%nDomains))
147 :
148 14 : nuniqueL0Domains = 0_i4
149 40 : do iDomain = 1, domainMeta%nDomains
150 26 : domainID = domainMeta%indices(iDomain)
151 26 : resolutionHydrology(iDomain) = resolution_Hydrology(domainID)
152 : ! if a domain uses the same L0 data as a previous one, write
153 : ! the index into domainMeta%L0DataFrom
154 26 : newDomainID = L0Domain(domainID)
155 26 : domainMeta%L0DataFrom(iDomain) = iDomain
156 : !
157 26 : addCounter = .True.
158 59 : do i = 1, iDomain - 1
159 59 : if (newDomainID == domainMeta%indices(i)) then
160 3 : domainMeta%L0DataFrom(iDomain) = i
161 3 : addCounter = .False.
162 : end if
163 : end do
164 40 : if (addCounter) nuniqueL0Domains = nuniqueL0Domains + 1_i4
165 : end do
166 :
167 : ! check for possible options
168 14 : if(.NOT. (iFlag_cordinate_sys == 0 .OR. iFlag_cordinate_sys == 1)) then
169 0 : call error_message('***ERROR: coordinate system for the model run should be 0 or 1')
170 : end if
171 :
172 : !===============================================================
173 : ! Read land cover
174 : !===============================================================
175 14 : call position_nml('LCover', unamelist)
176 14 : read(unamelist, nml = LCover)
177 :
178 : ! put land cover scenes to corresponding file name and LuT
179 : ! this is done already here for MPR, which does not check for the time periods
180 42 : allocate(LCfilename(nLCoverScene))
181 42 : allocate(LC_year_start(nLCoverScene))
182 28 : allocate(LC_year_end(nLCoverScene))
183 56 : LCfilename(:) = LCoverfName(1 : nLCoverScene)
184 42 : LC_year_start(:) = LCoverYearStart(1 : nLCoverScene)
185 42 : LC_year_end(:) = LCoverYearEnd(1 : nLCoverScene)
186 :
187 : !===============================================================
188 : ! Read namelist for mainpaths
189 : !===============================================================
190 14 : call position_nml('directories_general', unamelist)
191 14 : read(unamelist, nml = directories_general)
192 :
193 40 : do iDomain = 1, domainMeta%nDomains
194 26 : domainID = domainMeta%indices(iDomain)
195 26 : domainMeta%optidata(iDomain) = read_opt_domain_data(domainID)
196 26 : dirMorpho(iDomain) = dir_Morpho(domainID)
197 26 : mhmFileRestartOut(iDomain) = mhm_file_RestartOut(domainID)
198 26 : mrmFileRestartOut(iDomain) = mrm_file_RestartOut(domainID)
199 26 : dirLCover(iDomain) = dir_LCover(domainID)
200 26 : dirOut(iDomain) = dir_Out(domainID)
201 40 : fileLatLon(iDomain) = file_LatLon(domainID)
202 : end do
203 :
204 : ! ToDo: add test if opti_function matches at least one domainMeta%optidata
205 : ! as soon as common and common_mRM_mHM are merged, if that is the plan
206 :
207 :
208 : !===============================================================
209 : ! Read process selection list
210 : !===============================================================
211 : ! init the processCase matrix to 0 to be backward compatible
212 : ! if cases were added later (then there would be no values if not init here)
213 14 : processCase = 0_i4
214 14 : call position_nml('processselection', unamelist)
215 14 : read(unamelist, nml = processSelection)
216 :
217 14 : processMatrix = 0_i4
218 168 : processMatrix(:, 1) = processCase
219 14 : if (processMatrix(8, 1) == 0) then
220 2 : domainMeta%doRouting(:) = .FALSE.
221 : else
222 38 : domainMeta%doRouting(:) = .TRUE.
223 : end if
224 :
225 14 : call close_nml(unamelist)
226 :
227 14 : end subroutine common_read_config
228 :
229 :
230 : !> \brief Set land cover scenes IDs
231 : !> \changelog
232 : !! - Robert Schweppe Dec 2018
233 : !! - refactoring and restructuring
234 : !> \authors Matthias Zink
235 : !> \date Dec 2012
236 14 : subroutine set_land_cover_scenes_id(sim_Per, LCyear_Id)
237 :
238 14 : use mo_common_constants, only : nodata_i4
239 : use mo_common_types, only: period
240 : use mo_common_variables, only : LC_year_end, LC_year_start, domainMeta, nLcoverScene
241 : use mo_string_utils, only : num2str
242 :
243 : implicit none
244 :
245 : type(period), dimension(:), intent(in) :: sim_Per !< simulation period
246 : integer(i4), dimension(:, :), allocatable, intent(inout) :: LCyear_Id !< land cover year ID
247 :
248 : integer(i4) :: ii, iDomain
249 :
250 :
251 : ! countercheck if land cover covers simulation period
252 54 : if (LC_year_start(1) .GT. minval(sim_Per(1 : domainMeta%nDomains)%yStart)) then
253 0 : call error_message('***ERROR: Land cover for warming period is missing!', raise=.false.)
254 0 : call error_message(' SimStart : ', trim(num2str(minval(sim_Per(1 : domainMeta%nDomains)%yStart))), raise=.false.)
255 0 : call error_message(' LCoverStart: ', trim(num2str(LC_year_start(1))))
256 : end if
257 54 : if (LC_year_end(nLCoverScene) .LT. maxval(sim_Per(1 : domainMeta%nDomains)%yEnd)) then
258 0 : call error_message('***ERROR: Land cover period shorter than modelling period!', raise=.false.)
259 0 : call error_message(' SimEnd : ', trim(num2str(maxval(sim_Per(1 : domainMeta%nDomains)%yEnd))), raise=.false.)
260 0 : call error_message(' LCoverEnd: ', trim(num2str(LC_year_end(nLCoverScene))))
261 : end if
262 : !
263 14 : allocate(LCyear_Id(minval(sim_Per(1 : domainMeta%nDomains)%yStart) : maxval(sim_Per(1 : domainMeta%nDomains)%yEnd), &
264 136 : domainMeta%nDomains))
265 136 : LCyear_Id = nodata_i4
266 40 : do iDomain = 1, domainMeta%nDomains
267 85 : do ii = 1, nLCoverScene
268 : ! land cover before model period or land cover after model period
269 100 : if ((LC_year_end(ii) .LT. sim_Per(iDomain)%yStart) .OR. &
270 71 : (LC_year_start(ii) .GT. sim_Per(iDomain)%yEnd)) then
271 : cycle
272 : ! land cover period fully covers model period
273 47 : else if ((LC_year_start(ii) .LE. sim_Per(iDomain)%yStart) .AND. &
274 : (LC_year_end(ii) .GE. sim_Per(iDomain)%yEnd)) then
275 13 : LCyear_Id(sim_Per(iDomain)%yStart : sim_Per(iDomain)%yEnd, iDomain) = ii
276 : exit
277 : ! land cover period covers beginning of model period
278 42 : else if ((LC_year_start(ii) .LE. sim_Per(iDomain)%yStart) .AND. &
279 : (LC_year_end(ii) .LT. sim_Per(iDomain)%yEnd)) then
280 42 : LCyear_Id(sim_Per(iDomain)%yStart : LC_year_end(ii), iDomain) = ii
281 : ! land cover period covers end of model period
282 21 : else if ((LC_year_start(ii) .GT. sim_Per(iDomain)%yStart) .AND. &
283 : (LC_year_end(ii) .GE. sim_Per(iDomain)%yEnd)) then
284 55 : LCyear_Id(LC_year_start(ii) : sim_Per(iDomain)%yEnd, iDomain) = ii
285 : ! land cover period covers part of model_period
286 : else
287 0 : LCyear_Id(LC_year_start(ii) : LC_year_end(ii), iDomain) = ii
288 : end if
289 : end do
290 : end do
291 :
292 :
293 14 : end subroutine set_land_cover_scenes_id
294 :
295 :
296 : !> \brief Initialization of the domain variables
297 : !> \details Initialization of the domain variable for all domain loops and if activated for parallelization
298 : !! In case of MPI parallelization domainMeta%overAllNumberOfDomains is a
299 : !! variable where the number of domains from the namelist is stored. By this
300 : !! every process knows the total number of domains. Then, in a loop the
301 : !! domains are distributed onto the processes. There is a master process
302 : !! and several subprocesses. The master process only reads the confings in the
303 : !! mHM driver.
304 : !!
305 : !! The subprocesses get a number of domains. domainMeta%nDomain refers
306 : !! to the number of domains assigned to a specific process. It is a local
307 : !! variable and therefore has a different value for each process.
308 : !!
309 : !! In case more domains are there than processes, currently the domains
310 : !! are distributed round robin, i.e. like cards in a card game.
311 : !!
312 : !! In case less domains than processes exist, all remaining processes
313 : !! are assigned to the routing domains round robin. In that case the
314 : !! local communicator is of interest: It is a group of processes assigned
315 : !! to a routing domain again with a master process
316 : !! (domainMeta%isMasterInComLocal) and subprocesses. This communicator can
317 : !! in future be passed to the routing parallelization.
318 : !> \author Maren Kaluza
319 : !> \date Sep 2019
320 14 : subroutine init_domain_variable(nDomains, optiData, domainMeta)
321 14 : use mo_common_types, only: domain_meta
322 : #ifdef MPI
323 : use mo_common_variables, only: comm
324 : use mpi_f08
325 : #endif
326 : integer(i4), intent(in) :: nDomains !< number of domains
327 : integer(i4), dimension(:), intent(in) :: optiData !< optimization data
328 : type(domain_meta), intent(inout) :: domainMeta !< domain meta info
329 :
330 : integer :: ierror
331 : integer(i4) :: nproc
332 : integer(i4) :: rank
333 : integer(i4) :: iDomain
334 : integer(i4) :: colDomain, colMasters
335 :
336 14 : domainMeta%overallNumberOfDomains = nDomains
337 : #ifdef MPI
338 : ! find number of processes nproc
339 : call MPI_Comm_size(comm, nproc, ierror)
340 : ! find the number the process is referred to, called rank
341 : call MPI_Comm_rank(comm, rank, ierror)
342 : if (nproc < 2) then
343 : call error_message('at least 2 processes are required')
344 : end if
345 : ! if there are more processes than domains
346 : if (nproc > domainMeta%overallNumberOfDomains + 1) then
347 : domainMeta%nDomains = 0
348 : ! master reads only metadata of all domains
349 : if (rank == 0) then
350 : call init_domain_variable_for_master(domainMeta, colMasters, colDomain)
351 : ! all other nodes read metadata but also data of assigned domains
352 : else
353 : ! currently each domain gets one process except it is a routing domain.
354 : ! in that case the remaining processes are distributed round robin to
355 : ! the routing domains.
356 : call distribute_processes_to_domains_according_to_role(optiData, rank, &
357 : domainMeta, colMasters, colDomain)
358 : end if
359 : ! two communicators are created, i.e. groups of processes that talk about
360 : ! a certain topic:
361 : ! comMaster is the communicator of all processes that need to read all
362 : ! data. These are the processes that are masters in the comLocal plus the
363 : ! master over all processes. comLocal is a communicator for a group of
364 : ! processes assigned to the same domain.
365 : call MPI_Comm_split(comm, colMasters, rank, domainMeta%comMaster, ierror)
366 : call MPI_Comm_split(comm, colDomain, rank, domainMeta%comLocal, ierror)
367 : call MPI_Comm_size(domainMeta%comMaster, nproc, ierror)
368 : else
369 : ! in case of more domains than processes, distribute domains round robin
370 : ! onto the processes
371 : call MPI_Comm_dup(comm, domainMeta%comMaster, ierror)
372 : domainMeta%isMasterInComLocal = .true.
373 : domainMeta%nDomains = 0
374 : ! master reads only metadata of all domains
375 : if (rank == 0) then
376 : domainMeta%nDomains = domainMeta%overallNumberOfDomains
377 : allocate(domainMeta%indices(domainMeta%nDomains))
378 : do iDomain = 1, domainMeta%nDomains
379 : domainMeta%indices(iDomain) = iDomain
380 : end do
381 : ! all other nodes read metadata but also data of assigned domains
382 : else
383 : call distributeDomainsRoundRobin(nproc, rank, domainMeta)
384 : end if
385 : end if ! round robin
386 : #else
387 14 : domainMeta%nDomains = nDomains
388 42 : allocate(domainMeta%indices(domainMeta%nDomains))
389 40 : do iDomain = 1, domainMeta%nDomains
390 40 : domainMeta%indices(iDomain) = iDomain
391 : end do
392 : #endif
393 :
394 14 : end subroutine init_domain_variable
395 :
396 : #ifdef MPI
397 : subroutine init_domain_variable_for_master(domainMeta, colMasters, colDomain)
398 : use mo_common_types, only: domain_meta
399 : type(domain_meta), intent(inout) :: domainMeta
400 : integer(i4), intent(out) :: colMasters
401 : integer(i4), intent(out) :: colDomain
402 : !local
403 : integer(i4) :: iDomain
404 :
405 : domainMeta%nDomains = domainMeta%overallNumberOfDomains
406 : allocate(domainMeta%indices(domainMeta%nDomains))
407 : do iDomain = 1, domainMeta%nDomains
408 : domainMeta%indices(iDomain) = iDomain
409 : end do
410 : colMasters = 1
411 : colDomain = 0
412 : domainMeta%isMasterInComLocal = .true.
413 :
414 : end subroutine init_domain_variable_for_master
415 :
416 : subroutine distributeDomainsRoundRobin(nproc, rank, domainMeta)
417 : use mo_common_types, only: domain_meta
418 : integer(i4), intent(in) :: nproc
419 : integer(i4), intent(in) :: rank
420 : type(domain_meta), intent(inout) :: domainMeta
421 :
422 : integer(i4) :: iDomain, iProcDomain
423 :
424 : do iDomain = 1 , domainMeta%overallNumberOfDomains
425 : if (rank == (modulo(iDomain + nproc - 2, (nproc - 1)) + 1)) then
426 : domainMeta%nDomains = domainMeta%nDomains + 1
427 : end if
428 : end do
429 : allocate(domainMeta%indices(domainMeta%nDomains))
430 : iProcDomain = 0
431 : do iDomain = 1 , domainMeta%overallNumberOfDomains
432 : if (rank == (modulo(iDomain + nproc - 2, (nproc - 1)) + 1)) then
433 : iProcDomain = iProcDomain + 1
434 : domainMeta%indices(iProcDomain) = iDomain
435 : end if
436 : end do
437 : end subroutine distributeDomainsRoundRobin
438 :
439 : subroutine distribute_processes_to_domains_according_to_role(optiData, rank, &
440 : domainMeta, colMasters, colDomain)
441 : use mo_common_types, only: domain_meta
442 : integer(i4), dimension(:), intent(in) :: optiData
443 : integer(i4), intent(in) :: rank
444 : type(domain_meta), intent(inout) :: domainMeta
445 : integer(i4), intent(out) :: colMasters
446 : integer(i4), intent(out) :: colDomain
447 :
448 : ! local
449 : integer(i4) :: nDomainsAll, nTreeDomains, i, iDomain
450 : integer(i4), dimension(:), allocatable :: treeDomainList
451 :
452 : nDomainsAll = domainMeta%overallNumberOfDomains
453 : nTreeDomains = 0
454 : do iDomain = 1, nDomainsAll
455 : !ToDo: should also routing but not opti domains be counted?
456 : if (optiData(iDomain) == 1) then
457 : nTreeDomains = nTreeDomains + 1
458 : end if
459 : end do
460 : allocate(treeDomainList(nTreeDomains))
461 : i = 0
462 : do iDomain = 1, nDomainsAll
463 : if (optiData(iDomain) == 1) then
464 : i = i + 1
465 : treeDomainList(i) = iDomain
466 : end if
467 : end do
468 : if (rank < nDomainsAll + 1) then
469 : colMasters = 1
470 : colDomain = rank
471 : domainMeta%isMasterInComLocal = .true.
472 : domainMeta%nDomains = 1
473 : allocate(domainMeta%indices(domainMeta%nDomains))
474 : domainMeta%indices(1) = rank
475 : else
476 : colMasters = 0
477 : if (nTreeDomains > 0) then
478 : colDomain = treeDomainList(mod(rank, nTreeDomains) + 1)
479 : else
480 : colDomain = 1
481 : end if
482 : domainMeta%isMasterInComLocal = .false.
483 : domainMeta%nDomains = 1
484 : allocate(domainMeta%indices(domainMeta%nDomains))
485 : ! ToDo : temporary solution, this should either not read data at all
486 : ! or data corresponding to the master process
487 : domainMeta%indices(1) = 1
488 : end if
489 : deallocate(treeDomainList)
490 : end subroutine
491 : #endif
492 :
493 : ! \brief check the L0Domain variable from the namelist
494 : !> \authors Sebastian Müller
495 : !> \date Mar 2023
496 14 : subroutine check_L0Domain(L0Domain, nDomains)
497 14 : use mo_common_constants, only : maxNoDomains
498 : use mo_string_utils, only : num2str
499 :
500 : integer(i4), dimension(maxNoDomains), intent(in) ::L0Domain !< given L0Domain variable
501 : integer(i4), intent(in) :: nDomains !< number of domains
502 :
503 : integer(i4) :: i
504 :
505 40 : do i = 1, nDomains
506 26 : if (L0Domain(i) < 0) call error_message( &
507 : "L0Domain values need to be positive: ", &
508 0 : "L0Domain(", trim(adjustl(num2str(i))), ") = ", trim(adjustl(num2str(L0Domain(i)))))
509 26 : if (L0Domain(i) > i) call error_message( &
510 : "L0Domain values need to be less or equal to the domain index: ", &
511 0 : "L0Domain(", trim(adjustl(num2str(i))), ") = ", trim(adjustl(num2str(L0Domain(i)))))
512 : ! check for increasing values
513 26 : if (i > 1) then
514 12 : if (L0Domain(i) < L0Domain(i-1)) call error_message( &
515 : "L0Domain values need to be increasing: ", &
516 0 : "L0Domain(", trim(adjustl(num2str(i-1))), ") = ", trim(adjustl(num2str(L0Domain(i-1)))), &
517 0 : ", L0Domain(", trim(adjustl(num2str(i))), ") = ", trim(adjustl(num2str(L0Domain(i)))))
518 : end if
519 : ! if lower, check that the reference domain uses its own L0Data
520 40 : if (L0Domain(i) < i) then
521 3 : if (L0Domain(L0Domain(i)) /= L0Domain(i)) call error_message( &
522 : "L0Domain values should be taken from a domain with its own L0 data: ", &
523 0 : "L0Domain(", trim(adjustl(num2str(i))), ") = ", trim(adjustl(num2str(L0Domain(i)))), &
524 0 : ", L0Domain(", trim(adjustl(num2str(L0Domain(i)))), ") = ", trim(adjustl(num2str(L0Domain(L0Domain(i))))))
525 : end if
526 : end do
527 :
528 14 : end subroutine check_L0Domain
529 :
530 : END MODULE mo_common_read_config
|