MOM6
MOM_dyn_horgrid.F90
Go to the documentation of this file.
2 
3 !***********************************************************************
4 !* GNU General Public License *
5 !* This file is a part of MOM. *
6 !* *
7 !* MOM is free software; you can redistribute it and/or modify it and *
8 !* are expected to follow the terms of the GNU General Public License *
9 !* as published by the Free Software Foundation; either version 2 of *
10 !* the License, or (at your option) any later version. *
11 !* *
12 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
13 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
14 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
15 !* License for more details. *
16 !* *
17 !* For the full text of the GNU General Public License, *
18 !* write to: Free Software Foundation, Inc., *
19 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
20 !* or see: http://www.gnu.org/licenses/gpl.html *
21 !***********************************************************************
22 
23 use mom_hor_index, only : hor_index_type
24 use mom_domains, only : mom_domain_type
25 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning
26 
27 implicit none ; private
28 
30 
31 type, public :: dyn_horgrid_type
32  type(mom_domain_type), pointer :: domain => null()
33  type(mom_domain_type), pointer :: domain_aux => null() ! A non-symmetric auxiliary domain type.
34 
35  ! These elements can be copied from a provided hor_index_type.
36  type(hor_index_type) :: hi ! Make this a pointer?
37  integer :: isc, iec, jsc, jec ! The range of the computational domain indices
38  integer :: isd, ied, jsd, jed ! and data domain indices at tracer cell centers.
39  integer :: isg, ieg, jsg, jeg ! The range of the global domain tracer cell indices.
40  integer :: iscb, iecb, jscb, jecb ! The range of the computational domain indices
41  integer :: isdb, iedb, jsdb, jedb ! and data domain indices at tracer cell vertices.
42  integer :: isgb, iegb, jsgb, jegb ! The range of the global domain vertex indices.
43  integer :: isd_global ! The values of isd and jsd in the global
44  integer :: jsd_global ! (decomposition invariant) index space.
45  integer :: idg_offset ! The offset between the corresponding global
46  integer :: jdg_offset ! and local array indices.
47  logical :: symmetric ! True if symmetric memory is used.
48 
49  logical :: nonblocking_updates ! If true, non-blocking halo updates are
50  ! allowed. The default is .false. (for now).
51  integer :: first_direction ! An integer that indicates which direction is
52  ! to be updated first in directionally split
53  ! parts of the calculation. This can be altered
54  ! during the course of the run via calls to
55  ! set_first_direction.
56 
57  real, allocatable, dimension(:,:) :: &
58  mask2dt, & ! 0 for land points and 1 for ocean points on the h-grid. Nd.
59  geolatt, & ! The geographic latitude at q points in degrees of latitude or m.
60  geolont, & ! The geographic longitude at q points in degrees of longitude or m.
61  dxt, idxt, & ! dxT is delta x at h points, in m, and IdxT is 1/dxT in m-1.
62  dyt, idyt, & ! dyT is delta y at h points, in m, and IdyT is 1/dyT in m-1.
63  areat, & ! areaT is the area of an h-cell, in m2.
64  iareat, & ! IareaT = 1/areaT, in m-2.
65  sin_rot, & ! The sine and cosine of the angular rotation between the local
66  cos_rot ! model grid's northward and the true northward directions.
67 
68  real, allocatable, dimension(:,:) :: &
69  mask2dcu, & ! 0 for boundary points and 1 for ocean points on the u grid. Nondim.
70  geolatcu, & ! The geographic latitude at u points in degrees of latitude or m.
71  geoloncu, & ! The geographic longitude at u points in degrees of longitude or m.
72  dxcu, idxcu, & ! dxCu is delta x at u points, in m, and IdxCu is 1/dxCu in m-1.
73  dycu, idycu, & ! dyCu is delta y at u points, in m, and IdyCu is 1/dyCu in m-1.
74  dy_cu, & ! The unblocked lengths of the u-faces of the h-cell in m.
75  dy_cu_obc, & ! The unblocked lengths of the u-faces of the h-cell in m for OBC.
76  iareacu, & ! The masked inverse areas of u-grid cells in m2.
77  areacu ! The areas of the u-grid cells in m2.
78 
79  real, allocatable, dimension(:,:) :: &
80  mask2dcv, & ! 0 for boundary points and 1 for ocean points on the v grid. Nondim.
81  geolatcv, & ! The geographic latitude at v points in degrees of latitude or m.
82  geoloncv, & ! The geographic longitude at v points in degrees of longitude or m.
83  dxcv, idxcv, & ! dxCv is delta x at v points, in m, and IdxCv is 1/dxCv in m-1.
84  dycv, idycv, & ! dyCv is delta y at v points, in m, and IdyCv is 1/dyCv in m-1.
85  dx_cv, & ! The unblocked lengths of the v-faces of the h-cell in m.
86  dx_cv_obc, & ! The unblocked lengths of the v-faces of the h-cell in m for OBC.
87  iareacv, & ! The masked inverse areas of v-grid cells in m2.
88  areacv ! The areas of the v-grid cells in m2.
89 
90  real, allocatable, dimension(:,:) :: &
91  mask2dbu, & ! 0 for boundary points and 1 for ocean points on the q grid. Nondim.
92  geolatbu, & ! The geographic latitude at q points in degrees of latitude or m.
93  geolonbu, & ! The geographic longitude at q points in degrees of longitude or m.
94  dxbu, idxbu, & ! dxBu is delta x at q points, in m, and IdxBu is 1/dxBu in m-1.
95  dybu, idybu, & ! dyBu is delta y at q points, in m, and IdyBu is 1/dyBu in m-1.
96  areabu, & ! areaBu is the area of a q-cell, in m2
97  iareabu ! IareaBu = 1/areaBu in m-2.
98 
99  real, pointer, dimension(:) :: &
100  gridlatt => null(), gridlatb => null() ! The latitude of T or B points for
101  ! the purpose of labeling the output axes.
102  ! On many grids these are the same as geoLatT & geoLatBu.
103  real, pointer, dimension(:) :: &
104  gridlont => null(), gridlonb => null() ! The longitude of T or B points for
105  ! the purpose of labeling the output axes.
106  ! On many grids these are the same as geoLonT & geoLonBu.
107  character(len=40) :: &
108  x_axis_units, & ! The units that are used in labeling the coordinate
109  y_axis_units ! axes. Except on a Cartesian grid, these are usually
110  ! some variant of "degrees".
111 
112  real, allocatable, dimension(:,:) :: &
113  bathyt ! Ocean bottom depth at tracer points, in m.
114 
115  logical :: bathymetry_at_vel ! If true, there are separate values for the
116  ! basin depths at velocity points. Otherwise the effects of
117  ! of topography are entirely determined from thickness points.
118  real, allocatable, dimension(:,:) :: &
119  dblock_u, & ! Topographic depths at u-points at which the flow is blocked
120  dopen_u ! (Dblock_u) and open at width dy_Cu (Dopen_u), both in m.
121  real, allocatable, dimension(:,:) :: &
122  dblock_v, & ! Topographic depths at v-points at which the flow is blocked
123  dopen_v ! (Dblock_v) and open at width dx_Cv (Dopen_v), both in m.
124  real, allocatable, dimension(:,:) :: &
125  coriolisbu ! The Coriolis parameter at corner points, in s-1.
126  real, allocatable, dimension(:,:) :: &
127  df_dx, df_dy ! Derivatives of f (Coriolis parameter) at h-points, in s-1 m-1.
128 
129  ! These variables are global sums that are useful for 1-d diagnostics
130  real :: areat_global ! Global sum of h-cell area in m2
131  real :: iareat_global ! Global sum of inverse h-cell area (1/areaT_global)
132  ! in m2
133 
134  ! These parameters are run-time parameters that are used during some
135  ! initialization routines (but not all)
136  real :: south_lat ! The latitude (or y-coordinate) of the first v-line
137  real :: west_lon ! The longitude (or x-coordinate) of the first u-line
138  real :: len_lat = 0. ! The latitudinal (or y-coord) extent of physical domain
139  real :: len_lon = 0. ! The longitudinal (or x-coord) extent of physical domain
140  real :: rad_earth = 6.378e6 ! The radius of the planet in meters.
141  real :: max_depth ! The maximum depth of the ocean in meters.
142 end type dyn_horgrid_type
143 
144 contains
145 
146 !---------------------------------------------------------------------
147 !> Allocate memory used by the dyn_horgrid_type and related structures.
148 subroutine create_dyn_horgrid(G, HI, bathymetry_at_vel)
149  type(dyn_horgrid_type), pointer :: G !< A pointer to the dynamic horizontal grid type
150  type(hor_index_type), intent(in) :: HI !< A hor_index_type for array extents
151  logical, optional, intent(in) :: bathymetry_at_vel !< If true, there are
152  !! separate values for the basin depths at velocity
153  !! points. Otherwise the effects of topography are
154  !! entirely determined from thickness points.
155  integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, isg, ieg, jsg, jeg
156 
157  ! This subroutine allocates the lateral elements of the dyn_horgrid_type that
158  ! are always used and zeros them out.
159 
160  if (associated(g)) then
161  call mom_error(warning, "create_dyn_horgrid called with an associated horgrid_type.")
162  else
163  allocate(g)
164  endif
165 
166  g%HI = hi
167 
168  g%isc = hi%isc ; g%iec = hi%iec ; g%jsc = hi%jsc ; g%jec = hi%jec
169  g%isd = hi%isd ; g%ied = hi%ied ; g%jsd = hi%jsd ; g%jed = hi%jed
170  g%isg = hi%isg ; g%ieg = hi%ieg ; g%jsg = hi%jsg ; g%jeg = hi%jeg
171 
172  g%IscB = hi%IscB ; g%IecB = hi%IecB ; g%JscB = hi%JscB ; g%JecB = hi%JecB
173  g%IsdB = hi%IsdB ; g%IedB = hi%IedB ; g%JsdB = hi%JsdB ; g%JedB = hi%JedB
174  g%IsgB = hi%IsgB ; g%IegB = hi%IegB ; g%JsgB = hi%JsgB ; g%JegB = hi%JegB
175 
176  g%idg_offset = hi%idg_offset ; g%jdg_offset = hi%jdg_offset
177  g%isd_global = g%isd + hi%idg_offset ; g%jsd_global = g%jsd + hi%jdg_offset
178  g%symmetric = hi%symmetric
179 
180  g%bathymetry_at_vel = .false.
181  if (present(bathymetry_at_vel)) g%bathymetry_at_vel = bathymetry_at_vel
182 
183  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
184  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
185  isg = g%isg ; ieg = g%ieg ; jsg = g%jsg ; jeg = g%jeg
186 
187  allocate(g%dxT(isd:ied,jsd:jed)) ; g%dxT(:,:) = 0.0
188  allocate(g%dxCu(isdb:iedb,jsd:jed)) ; g%dxCu(:,:) = 0.0
189  allocate(g%dxCv(isd:ied,jsdb:jedb)) ; g%dxCv(:,:) = 0.0
190  allocate(g%dxBu(isdb:iedb,jsdb:jedb)) ; g%dxBu(:,:) = 0.0
191  allocate(g%IdxT(isd:ied,jsd:jed)) ; g%IdxT(:,:) = 0.0
192  allocate(g%IdxCu(isdb:iedb,jsd:jed)) ; g%IdxCu(:,:) = 0.0
193  allocate(g%IdxCv(isd:ied,jsdb:jedb)) ; g%IdxCv(:,:) = 0.0
194  allocate(g%IdxBu(isdb:iedb,jsdb:jedb)) ; g%IdxBu(:,:) = 0.0
195 
196  allocate(g%dyT(isd:ied,jsd:jed)) ; g%dyT(:,:) = 0.0
197  allocate(g%dyCu(isdb:iedb,jsd:jed)) ; g%dyCu(:,:) = 0.0
198  allocate(g%dyCv(isd:ied,jsdb:jedb)) ; g%dyCv(:,:) = 0.0
199  allocate(g%dyBu(isdb:iedb,jsdb:jedb)) ; g%dyBu(:,:) = 0.0
200  allocate(g%IdyT(isd:ied,jsd:jed)) ; g%IdyT(:,:) = 0.0
201  allocate(g%IdyCu(isdb:iedb,jsd:jed)) ; g%IdyCu(:,:) = 0.0
202  allocate(g%IdyCv(isd:ied,jsdb:jedb)) ; g%IdyCv(:,:) = 0.0
203  allocate(g%IdyBu(isdb:iedb,jsdb:jedb)) ; g%IdyBu(:,:) = 0.0
204 
205  allocate(g%areaT(isd:ied,jsd:jed)) ; g%areaT(:,:) = 0.0
206  allocate(g%IareaT(isd:ied,jsd:jed)) ; g%IareaT(:,:) = 0.0
207  allocate(g%areaBu(isdb:iedb,jsdb:jedb)) ; g%areaBu(:,:) = 0.0
208  allocate(g%IareaBu(isdb:iedb,jsdb:jedb)) ; g%IareaBu(:,:) = 0.0
209 
210  allocate(g%mask2dT(isd:ied,jsd:jed)) ; g%mask2dT(:,:) = 0.0
211  allocate(g%mask2dCu(isdb:iedb,jsd:jed)) ; g%mask2dCu(:,:) = 0.0
212  allocate(g%mask2dCv(isd:ied,jsdb:jedb)) ; g%mask2dCv(:,:) = 0.0
213  allocate(g%mask2dBu(isdb:iedb,jsdb:jedb)) ; g%mask2dBu(:,:) = 0.0
214  allocate(g%geoLatT(isd:ied,jsd:jed)) ; g%geoLatT(:,:) = 0.0
215  allocate(g%geoLatCu(isdb:iedb,jsd:jed)) ; g%geoLatCu(:,:) = 0.0
216  allocate(g%geoLatCv(isd:ied,jsdb:jedb)) ; g%geoLatCv(:,:) = 0.0
217  allocate(g%geoLatBu(isdb:iedb,jsdb:jedb)) ; g%geoLatBu(:,:) = 0.0
218  allocate(g%geoLonT(isd:ied,jsd:jed)) ; g%geoLonT(:,:) = 0.0
219  allocate(g%geoLonCu(isdb:iedb,jsd:jed)) ; g%geoLonCu(:,:) = 0.0
220  allocate(g%geoLonCv(isd:ied,jsdb:jedb)) ; g%geoLonCv(:,:) = 0.0
221  allocate(g%geoLonBu(isdb:iedb,jsdb:jedb)) ; g%geoLonBu(:,:) = 0.0
222 
223  allocate(g%dx_Cv(isd:ied,jsdb:jedb)) ; g%dx_Cv(:,:) = 0.0
224  allocate(g%dy_Cu(isdb:iedb,jsd:jed)) ; g%dy_Cu(:,:) = 0.0
225  allocate(g%dx_Cv_obc(isd:ied,jsdb:jedb)) ; g%dx_Cv_obc(:,:) = 0.0
226  allocate(g%dy_Cu_obc(isdb:iedb,jsd:jed)) ; g%dy_Cu_obc(:,:) = 0.0
227 
228  allocate(g%areaCu(isdb:iedb,jsd:jed)) ; g%areaCu(:,:) = 0.0
229  allocate(g%areaCv(isd:ied,jsdb:jedb)) ; g%areaCv(:,:) = 0.0
230  allocate(g%IareaCu(isdb:iedb,jsd:jed)) ; g%IareaCu(:,:) = 0.0
231  allocate(g%IareaCv(isd:ied,jsdb:jedb)) ; g%IareaCv(:,:) = 0.0
232 
233  allocate(g%bathyT(isd:ied, jsd:jed)) ; g%bathyT(:,:) = 0.0
234  allocate(g%CoriolisBu(isdb:iedb, jsdb:jedb)) ; g%CoriolisBu(:,:) = 0.0
235  allocate(g%dF_dx(isd:ied, jsd:jed)) ; g%dF_dx(:,:) = 0.0
236  allocate(g%dF_dy(isd:ied, jsd:jed)) ; g%dF_dy(:,:) = 0.0
237 
238  allocate(g%sin_rot(isd:ied,jsd:jed)) ; g%sin_rot(:,:) = 0.0
239  allocate(g%cos_rot(isd:ied,jsd:jed)) ; g%cos_rot(:,:) = 1.0
240 
241  if (g%bathymetry_at_vel) then
242  allocate(g%Dblock_u(isdb:iedb, jsd:jed)) ; g%Dblock_u(:,:) = 0.0
243  allocate(g%Dopen_u(isdb:iedb, jsd:jed)) ; g%Dopen_u(:,:) = 0.0
244  allocate(g%Dblock_v(isd:ied, jsdb:jedb)) ; g%Dblock_v(:,:) = 0.0
245  allocate(g%Dopen_v(isd:ied, jsdb:jedb)) ; g%Dopen_v(:,:) = 0.0
246  endif
247 
248  ! gridLonB and gridLatB are used as edge values in some cases, so they
249  ! always need to use symmetric memory allcoations.
250  allocate(g%gridLonT(isg:ieg)) ; g%gridLonT(:) = 0.0
251  allocate(g%gridLonB(isg-1:ieg)) ; g%gridLonB(:) = 0.0
252  allocate(g%gridLatT(jsg:jeg)) ; g%gridLatT(:) = 0.0
253  allocate(g%gridLatB(jsg-1:jeg)) ; g%gridLatB(:) = 0.0
254 
255 end subroutine create_dyn_horgrid
256 
257 !> set_derived_dyn_horgrid calculates metric terms that are derived from other metrics.
258 subroutine set_derived_dyn_horgrid(G)
259  type(dyn_horgrid_type), intent(inout) :: G !< The dynamic horizontal grid type
260 ! Various inverse grid spacings and derived areas are calculated within this
261 ! subroutine.
262  integer :: i, j, isd, ied, jsd, jed
263  integer :: IsdB, IedB, JsdB, JedB
264 
265  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
266  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
267 
268  do j=jsd,jed ; do i=isd,ied
269  if (g%dxT(i,j) < 0.0) g%dxT(i,j) = 0.0
270  if (g%dyT(i,j) < 0.0) g%dyT(i,j) = 0.0
271  g%IdxT(i,j) = adcroft_reciprocal(g%dxT(i,j))
272  g%IdyT(i,j) = adcroft_reciprocal(g%dyT(i,j))
273  g%IareaT(i,j) = adcroft_reciprocal(g%areaT(i,j))
274  enddo ; enddo
275 
276  do j=jsd,jed ; do i=isdb,iedb
277  if (g%dxCu(i,j) < 0.0) g%dxCu(i,j) = 0.0
278  if (g%dyCu(i,j) < 0.0) g%dyCu(i,j) = 0.0
279  g%IdxCu(i,j) = adcroft_reciprocal(g%dxCu(i,j))
280  g%IdyCu(i,j) = adcroft_reciprocal(g%dyCu(i,j))
281  enddo ; enddo
282 
283  do j=jsdb,jedb ; do i=isd,ied
284  if (g%dxCv(i,j) < 0.0) g%dxCv(i,j) = 0.0
285  if (g%dyCv(i,j) < 0.0) g%dyCv(i,j) = 0.0
286  g%IdxCv(i,j) = adcroft_reciprocal(g%dxCv(i,j))
287  g%IdyCv(i,j) = adcroft_reciprocal(g%dyCv(i,j))
288  enddo ; enddo
289 
290  do j=jsdb,jedb ; do i=isdb,iedb
291  if (g%dxBu(i,j) < 0.0) g%dxBu(i,j) = 0.0
292  if (g%dyBu(i,j) < 0.0) g%dyBu(i,j) = 0.0
293 
294  g%IdxBu(i,j) = adcroft_reciprocal(g%dxBu(i,j))
295  g%IdyBu(i,j) = adcroft_reciprocal(g%dyBu(i,j))
296  ! areaBu has usually been set to a positive area elsewhere.
297  if (g%areaBu(i,j) <= 0.0) g%areaBu(i,j) = g%dxBu(i,j) * g%dyBu(i,j)
298  g%IareaBu(i,j) = adcroft_reciprocal(g%areaBu(i,j))
299  enddo ; enddo
300 
301 end subroutine set_derived_dyn_horgrid
302 
303 !> Adcroft_reciprocal(x) = 1/x for |x|>0 or 0 for x=0.
304 function adcroft_reciprocal(val) result(I_val)
305  real, intent(in) :: val !< The value being inverted.
306  real :: I_val !< The Adcroft reciprocal of val.
307 
308  i_val = 0.0 ; if (val /= 0.0) i_val = 1.0/val
309 end function adcroft_reciprocal
310 
311 !---------------------------------------------------------------------
312 !> Release memory used by the dyn_horgrid_type and related structures.
313 subroutine destroy_dyn_horgrid(G)
314  type(dyn_horgrid_type), pointer :: G !< The dynamic horizontal grid type
315 
316  if (.not.associated(g)) then
317  call mom_error(fatal, "destroy_dyn_horgrid called with an unassociated horgrid_type.")
318  endif
319 
320  deallocate(g%dxT) ; deallocate(g%dxCu) ; deallocate(g%dxCv) ; deallocate(g%dxBu)
321  deallocate(g%IdxT) ; deallocate(g%IdxCu) ; deallocate(g%IdxCv) ; deallocate(g%IdxBu)
322 
323  deallocate(g%dyT) ; deallocate(g%dyCu) ; deallocate(g%dyCv) ; deallocate(g%dyBu)
324  deallocate(g%IdyT) ; deallocate(g%IdyCu) ; deallocate(g%IdyCv) ; deallocate(g%IdyBu)
325 
326  deallocate(g%areaT) ; deallocate(g%IareaT)
327  deallocate(g%areaBu) ; deallocate(g%IareaBu)
328  deallocate(g%areaCu) ; deallocate(g%IareaCu)
329  deallocate(g%areaCv) ; deallocate(g%IareaCv)
330 
331  deallocate(g%mask2dT) ; deallocate(g%mask2dCu)
332  deallocate(g%mask2dCv) ; deallocate(g%mask2dBu)
333 
334  deallocate(g%geoLatT) ; deallocate(g%geoLatCu)
335  deallocate(g%geoLatCv) ; deallocate(g%geoLatBu)
336  deallocate(g%geoLonT) ; deallocate(g%geoLonCu)
337  deallocate(g%geoLonCv) ; deallocate(g%geoLonBu)
338 
339  deallocate(g%dx_Cv) ; deallocate(g%dy_Cu)
340  deallocate(g%dx_Cv_obc) ; deallocate(g%dy_Cu_obc)
341 
342  deallocate(g%bathyT) ; deallocate(g%CoriolisBu)
343  deallocate(g%dF_dx) ; deallocate(g%dF_dy)
344  deallocate(g%sin_rot) ; deallocate(g%cos_rot)
345 
346  if (allocated(g%Dblock_u)) deallocate(g%Dblock_u)
347  if (allocated(g%Dopen_u)) deallocate(g%Dopen_u)
348  if (allocated(g%Dblock_v)) deallocate(g%Dblock_v)
349  if (allocated(g%Dopen_v)) deallocate(g%Dopen_v)
350 
351  deallocate(g%gridLonT) ; deallocate(g%gridLatT)
352  deallocate(g%gridLonB) ; deallocate(g%gridLatB)
353 
354  deallocate(g%Domain%mpp_domain)
355  deallocate(g%Domain)
356 
357  deallocate(g)
358 
359 end subroutine destroy_dyn_horgrid
360 
361 end module mom_dyn_horgrid
subroutine, public set_derived_dyn_horgrid(G)
set_derived_dyn_horgrid calculates metric terms that are derived from other metrics.
Defines the horizontal index type (hor_index_type) used for providing index ranges.
Container for horizontal index ranges for data, computational and global domains. ...
real function adcroft_reciprocal(val)
Adcroft_reciprocal(x) = 1/x for |x|>0 or 0 for x=0.
subroutine, public destroy_dyn_horgrid(G)
Release memory used by the dyn_horgrid_type and related structures.
subroutine, public mom_mesg(message, verb, all_print)
The MOM_domain_type contains information about the domain decompositoin.
subroutine, public create_dyn_horgrid(G, HI, bathymetry_at_vel)
Allocate memory used by the dyn_horgrid_type and related structures.
subroutine, public mom_error(level, message, all_print)