MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
MeshNCModel.f90
Go to the documentation of this file.
1 !> @brief This module contains the MeshModelModule
2 !!
3 !! This module defines a base class for UGRID based
4 !! (mesh) model netcdf exports. It is dependent on
5 !! external netcdf libraries.
6 !<
8 
9  use kindmodule, only: dp, i4b, lgp
19  use netcdfcommonmodule, only: nf_verify
20  use netcdf
21 
22  implicit none
23  private
25  public :: mesh2dmodeltype
26  public :: ncvar_chunk
27  public :: ncvar_deflate
28  public :: ncvar_gridmap
29  public :: ncvar_mf6attr
30  public :: ncvar_layer
31 
32  !> @brief type for storing model export dimension ids
33  !<
35  integer(I4B) :: nmesh_node !< number of nodes in mesh
36  integer(I4B) :: nmesh_face !< number of faces in mesh
37  integer(I4B) :: max_nmesh_face_nodes !< max number of nodes in a single face
38  integer(I4B) :: time !< number of steps
39  integer(I4B) :: layer !< number of layers
40  contains
41  end type meshncdimidtype
42 
43  !> @brief type for storing model export variable ids
44  !<
46  integer(I4B) :: mesh !< mesh container variable
47  integer(I4B) :: mesh_node_x !< mesh nodes x array
48  integer(I4B) :: mesh_node_y !< mesh nodes y array
49  integer(I4B) :: mesh_face_x !< mesh faces x location array
50  integer(I4B) :: mesh_face_y !< mesh faces y location array
51  integer(I4B) :: mesh_face_xbnds !< mesh faces 2D x bounds array
52  integer(I4B) :: mesh_face_ybnds !< mesh faces 2D y bounds array
53  integer(I4B) :: mesh_face_nodes !< mesh faces 2D nodes array
54  integer(I4B) :: time !< time coordinate variable
55  integer(I4B) :: layer !< layer coordinate variable
56  integer(I4B), dimension(:), allocatable :: export !< in scope layer export
57  integer(I4B), dimension(:), allocatable :: dependent !< layered dependent variables array
58  integer(I4B), dimension(:), allocatable :: elevation !< z_lN per-layer cell center elevation variables array
59  contains
60  end type meshncvaridtype
61 
62  !> @brief base ugrid netcdf export type
63  !<
64  type, abstract, extends(ncbasemodelexporttype) :: meshmodeltype
65  type(meshncdimidtype) :: dim_ids !< dimension ids
66  type(meshncvaridtype) :: var_ids !< variable ids
67  integer(I4B) :: nlay !< number of layers
68  integer(I4B), pointer :: chunk_face !< chunking parameter for face dimension
69  contains
70  procedure :: mesh_init
71  procedure :: mesh_destroy
72  procedure :: df_export
73  procedure :: export_df
74  procedure :: create_timeseries
75  procedure :: add_global_att
76  procedure(nc_array_export_if), deferred :: export_input_array
77  procedure :: export_input_arrays
78  procedure :: add_pkg_data
79  procedure :: define_dependent
80  procedure :: define_gridmap
81  end type meshmodeltype
82 
83  !> @brief abstract interfaces for derived ugrid netcd export types
84  !<
85  abstract interface
86  subroutine nc_array_export_if(this, pkgtype, pkgname, mempath, idt)
88  class(meshmodeltype), intent(inout) :: this
89  character(len=*), intent(in) :: pkgtype
90  character(len=*), intent(in) :: pkgname
91  character(len=*), intent(in) :: mempath
92  type(inputparamdefinitiontype), pointer, intent(in) :: idt
93  end subroutine
94  end interface
95 
96  type, abstract, extends(meshmodeltype) :: mesh2dmodeltype
97  contains
98  procedure :: create_mesh
99  end type mesh2dmodeltype
100 
101 contains
102 
103  !> @brief initialize
104  !<
105  subroutine mesh_init(this, modelname, modeltype, modelfname, nc_fname, &
106  disenum, nctype, lenuni, iout)
108  class(meshmodeltype), intent(inout) :: this
109  character(len=*), intent(in) :: modelname
110  character(len=*), intent(in) :: modeltype
111  character(len=*), intent(in) :: modelfname
112  character(len=*), intent(in) :: nc_fname
113  integer(I4B), intent(in) :: disenum
114  integer(I4B), intent(in) :: nctype
115  integer(I4B), intent(in) :: lenuni
116  integer(I4B), intent(in) :: iout
117  logical(LGP) :: found
118  integer(I4B) :: latsz, lonsz
119 
120  ! initialize base class
121  call this%NCModelExportType%init(modelname, modeltype, modelfname, nc_fname, &
122  disenum, nctype, iout)
123 
124  if (this%ncf_mempath /= '') then
125  latsz = 0
126  lonsz = 0
127  call get_isize('LATITUDE', this%ncf_mempath, latsz)
128  call get_isize('LONGITUDE', this%ncf_mempath, lonsz)
129  if (latsz > 0 .or. lonsz > 0) then
130  write (warnmsg, '(a)') 'LATITUDE and LONGITUDE griddata are not &
131  &supported for a NETCDF_MESH2D export and will be ignored. &
132  &Applies to file "'//trim(nc_fname)//'".'
133  call store_warning(warnmsg)
134  end if
135  end if
136 
137  ! allocate and initialize
138  allocate (this%chunk_face)
139  this%chunk_face = -1
140 
141  ! update values from input context
142  if (this%ncf_mempath /= '') then
143  call mem_set_value(this%chunk_face, 'CHUNK_FACE', this%ncf_mempath, found)
144  end if
145 
146  if (this%chunk_time > 0 .and. this%chunk_face > 0) then
147  this%chunking_active = .true.
148  else if (this%chunk_time > 0 .or. this%chunk_face > 0) then
149  this%chunk_face = -1
150  this%chunk_time = -1
151  write (warnmsg, '(a)') 'Ignoring user provided NetCDF chunking parameter. &
152  &Define chunk_time and chunk_face input parameters to see an effect in &
153  &file "'//trim(nc_fname)//'".'
154  call store_warning(warnmsg)
155  end if
156 
157  if (lenuni == 1) then
158  this%lenunits = 'ft'
159  else if (lenuni == 3) then
160  this%lenunits = 'cm'
161  else
162  this%lenunits = 'm'
163  end if
164 
165  ! create the netcdf file
166  call nf_verify(nf90_create(this%nc_fname, &
167  ior(nf90_clobber, nf90_netcdf4), this%ncid), &
168  this%nc_fname)
169  end subroutine mesh_init
170 
171  !> @brief initialize
172  !<
173  subroutine mesh_destroy(this)
175  class(meshmodeltype), intent(inout) :: this
176  call nf_verify(nf90_close(this%ncid), this%nc_fname)
177  deallocate (this%chunk_face)
178  nullify (this%chunk_face)
179  end subroutine mesh_destroy
180 
181  !> @brief define timeseries input variables
182  !<
183  subroutine df_export(this)
185  class(meshmodeltype), intent(inout) :: this
186  class(exportpackagetype), pointer :: export_pkg
187  integer(I4B) :: idx
188  do idx = 1, this%pkglist%Count()
189  export_pkg => this%get(idx)
190  call this%export_df(export_pkg)
191  end do
192  end subroutine df_export
193 
194  !> @brief define export package
195  !<
196  subroutine export_df(this, export_pkg)
199  class(meshmodeltype), intent(inout) :: this
200  class(exportpackagetype), pointer, intent(in) :: export_pkg
201  type(inputparamdefinitiontype), pointer :: idt
202  integer(I4B) :: iparam, iaux, layer
203 
204  ! export defined period input
205  do iparam = 1, export_pkg%nparam
206  ! initialize
207  iaux = 0
208  layer = 0
209  ! set input definition
210  idt => &
211  get_param_definition_type(export_pkg%mf6_input%param_dfns, &
212  export_pkg%mf6_input%component_type, &
213  export_pkg%mf6_input%subcomponent_type, &
214  'PERIOD', export_pkg%param_names(iparam), '')
215 
216  select case (idt%shape)
217  case ('NCPL')
218  call this%create_timeseries(idt, iparam, iaux, layer, export_pkg)
219  case ('NODES')
220  do layer = 1, this%nlay
221  call this%create_timeseries(idt, iparam, iaux, layer, export_pkg)
222  end do
223  case ('NAUX NCPL')
224  do iaux = 1, export_pkg%naux
225  call this%create_timeseries(idt, iparam, iaux, layer, export_pkg)
226  end do
227  case ('NAUX NODES')
228  do iaux = 1, export_pkg%naux
229  do layer = 1, this%nlay
230  call this%create_timeseries(idt, iparam, iaux, layer, export_pkg)
231  end do
232  end do
233  case default
234  end select
235  end do
236  end subroutine export_df
237 
238  !> @brief create timeseries export variable
239  !<
240  subroutine create_timeseries(this, idt, iparam, iaux, layer, export_pkg)
241  use constantsmodule, only: dnodata
243  class(meshmodeltype), intent(inout) :: this
244  type(inputparamdefinitiontype), pointer, intent(in) :: idt
245  integer(I4B), intent(in) :: iparam
246  integer(I4B), intent(in) :: iaux
247  integer(I4B), intent(in) :: layer
248  class(exportpackagetype), pointer, intent(in) :: export_pkg
249  character(len=LINELENGTH) :: varname, longname, nc_tag
250  integer(I4B) :: varid
251 
252  ! set variable input tag
253  nc_tag = this%input_attribute(export_pkg%mf6_input%subcomponent_name, &
254  idt)
255 
256  ! set names
257  varname = export_varname(export_pkg%mf6_input%subcomponent_name, &
258  idt%tagname, export_pkg%mf6_input%mempath, &
259  layer=layer, iaux=iaux)
260  longname = export_longname(idt%longname, &
261  export_pkg%mf6_input%subcomponent_name, &
262  idt%tagname, export_pkg%mf6_input%mempath, &
263  layer=layer, iaux=iaux, &
264  component_type=idt%component_type, &
265  subcomponent_type=idt%subcomponent_type)
266 
267  ! create the netcdf dependent layer variable
268  select case (idt%datatype)
269  case ('DOUBLE1D', 'DOUBLE2D')
270  call nf_verify(nf90_def_var(this%ncid, varname, nf90_double, &
271  (/this%dim_ids%nmesh_face, &
272  this%dim_ids%time/), &
273  varid), &
274  this%nc_fname)
275  call nf_verify(nf90_put_att(this%ncid, varid, &
276  '_FillValue', (/dnodata/)), &
277  this%nc_fname)
278  case ('INTEGER1D')
279  call nf_verify(nf90_def_var(this%ncid, varname, nf90_int, &
280  (/this%dim_ids%nmesh_face, &
281  this%dim_ids%time/), &
282  varid), &
283  this%nc_fname)
284  call nf_verify(nf90_put_att(this%ncid, varid, &
285  '_FillValue', (/nf90_fill_int/)), &
286  this%nc_fname)
287  end select
288 
289  ! apply chunking parameters
290  if (this%chunking_active) then
291  call nf_verify(nf90_def_var_chunking(this%ncid, &
292  varid, &
293  nf90_chunked, &
294  (/this%chunk_face, &
295  this%chunk_time/)), &
296  this%nc_fname)
297  end if
298 
299  ! deflate and shuffle
300  call ncvar_deflate(this%ncid, varid, this%deflate, &
301  this%shuffle, this%nc_fname)
302 
303  ! assign variable attributes
304  call nf_verify(nf90_put_att(this%ncid, varid, &
305  'units', this%lenunits), this%nc_fname)
306  call nf_verify(nf90_put_att(this%ncid, varid, &
307  'long_name', longname), this%nc_fname)
308 
309  ! add grid mapping and mf6 attr (mesh, location, coordinates, grid_mapping)
310  call ncvar_gridmap(this%ncid, varid, &
311  this%gridmap_name, layer, this%nc_fname)
312  call ncvar_mf6attr(this%ncid, varid, layer, iaux, nc_tag, this%nc_fname)
313 
314  ! store variable id
315  if (idt%tagname == 'AUX') then
316  if (layer > 0) then
317  export_pkg%varids_aux(iaux, layer) = varid
318  else
319  export_pkg%varids_aux(iaux, 1) = varid
320  end if
321  else
322  if (layer > 0) then
323  export_pkg%varids_param(iparam, layer) = varid
324  else
325  export_pkg%varids_param(iparam, 1) = varid
326  end if
327  end if
328  end subroutine create_timeseries
329 
330  !> @brief create file (group) attributes
331  !<
332  subroutine add_global_att(this)
333  class(meshmodeltype), intent(inout) :: this
334  ! file scoped title
335  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'title', &
336  this%annotation%title), this%nc_fname)
337  ! source (MODFLOW 6)
338  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'source', &
339  this%annotation%source), this%nc_fname)
340  ! grid type (MODFLOW 6)
341  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'modflow_grid', &
342  this%annotation%grid), this%nc_fname)
343  ! mesh type (MODFLOW 6)
344  if (this%annotation%mesh /= '') then
345  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'modflow_mesh', &
346  this%annotation%mesh), this%nc_fname)
347 
348  end if
349  ! MODFLOW 6 model type
350  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'modflow_model', &
351  this%annotation%model), this%nc_fname)
352  ! generation datetime
353  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'history', &
354  this%annotation%history), this%nc_fname)
355  ! supported conventions
356  call nf_verify(nf90_put_att(this%ncid, nf90_global, 'Conventions', &
357  this%annotation%conventions), &
358  this%nc_fname)
359  end subroutine add_global_att
360 
361  !> @brief write package gridded input data
362  !<
363  subroutine export_input_arrays(this, pkgtype, pkgname, mempath, param_dfns)
364  use memorymanagermodule, only: get_isize
365  class(meshmodeltype), intent(inout) :: this
366  character(len=*), intent(in) :: pkgtype
367  character(len=*), intent(in) :: pkgname
368  character(len=*), intent(in) :: mempath
369  type(inputparamdefinitiontype), dimension(:), pointer, &
370  intent(in) :: param_dfns
371  type(inputparamdefinitiontype), pointer :: idt
372  integer(I4B) :: iparam, isize
373  ! export griddata block parameters
374  do iparam = 1, size(param_dfns)
375  ! assign param definition pointer
376  idt => param_dfns(iparam)
377  ! for now only griddata is exported
378  if (idt%blockname == 'GRIDDATA') then
379  ! veriy variable is allocated
380  call get_isize(idt%mf6varname, mempath, isize)
381  if (isize > 0) then
382  call this%export_input_array(pkgtype, pkgname, mempath, idt)
383  end if
384  end if
385  end do
386  end subroutine export_input_arrays
387 
388  !> @brief determine packages to write gridded input
389  !<
390  subroutine add_pkg_data(this)
397  class(meshmodeltype), intent(inout) :: this
398  character(LENCOMPONENTNAME) :: ptype, pname, pkgtype
399  character(len=LENMEMPATH) :: input_mempath
400  type(characterstringtype), dimension(:), contiguous, &
401  pointer :: pkgtypes => null()
402  type(characterstringtype), dimension(:), contiguous, &
403  pointer :: pkgnames => null()
404  type(characterstringtype), dimension(:), contiguous, &
405  pointer :: mempaths => null()
406  type(inputparamdefinitiontype), dimension(:), pointer :: param_dfns
407  character(len=LENMEMPATH) :: mempath
408  integer(I4B) :: n
409  integer(I4B), pointer :: export_arrays
410  logical(LGP) :: found
411 
412  input_mempath = create_mem_path(component=this%modelname, context=idm_context)
413 
414  ! set pointers to model path package info
415  call mem_setptr(pkgtypes, 'PKGTYPES', input_mempath)
416  call mem_setptr(pkgnames, 'PKGNAMES', input_mempath)
417  call mem_setptr(mempaths, 'MEMPATHS', input_mempath)
418 
419  allocate (export_arrays)
420 
421  do n = 1, size(mempaths)
422  ! initialize export_arrays
423  export_arrays = 0
424 
425  ! set package attributes
426  mempath = mempaths(n)
427  pname = pkgnames(n)
428  ptype = pkgtypes(n)
429 
430  ! export input arrays
431  if (mempath /= '') then
432  ! update export
433  call mem_set_value(export_arrays, 'EXPORT_NC', mempath, found, &
434  release=.false.)
435  if (export_arrays > 0) then
436  pkgtype = idm_subcomponent_type(this%modeltype, ptype)
437  param_dfns => param_definitions(this%modeltype, pkgtype)
438  call this%export_input_arrays(ptype, pname, mempath, param_dfns)
439  end if
440  end if
441  end do
442 
443  ! cleanup
444  deallocate (export_arrays)
445  end subroutine add_pkg_data
446 
447  !> @brief create the model layer dependent variables
448  !<
449  subroutine define_dependent(this)
450  class(meshmodeltype), intent(inout) :: this
451  character(len=LINELENGTH) :: varname, longname
452  integer(I4B) :: k
453 
454  ! create a dependent variable for each layer
455  do k = 1, this%nlay
456  ! initialize names
457  varname = ''
458  longname = ''
459 
460  ! set layer variable and longnames
461  write (varname, '(a,i0)') trim(this%xname)//'_l', k
462  write (longname, '(a,i0,a)') trim(this%annotation%longname)// &
463  ' (layer ', k, ')'
464 
465  ! create the netcdf dependent layer variable
466  call nf_verify(nf90_def_var(this%ncid, varname, nf90_double, &
467  (/this%dim_ids%nmesh_face, &
468  this%dim_ids%time/), &
469  this%var_ids%dependent(k)), &
470  this%nc_fname)
471 
472  ! apply chunking parameters
473  if (this%chunking_active) then
474  call nf_verify(nf90_def_var_chunking(this%ncid, &
475  this%var_ids%dependent(k), &
476  nf90_chunked, &
477  (/this%chunk_face, &
478  this%chunk_time/)), &
479  this%nc_fname)
480  end if
481 
482  ! deflate and shuffle
483  call ncvar_deflate(this%ncid, this%var_ids%dependent(k), this%deflate, &
484  this%shuffle, this%nc_fname)
485 
486  ! assign variable attributes
487  call nf_verify(nf90_put_att(this%ncid, this%var_ids%dependent(k), &
488  'units', this%lenunits), this%nc_fname)
489  call nf_verify(nf90_put_att(this%ncid, this%var_ids%dependent(k), &
490  'long_name', longname), this%nc_fname)
491  call nf_verify(nf90_put_att(this%ncid, this%var_ids%dependent(k), &
492  '_FillValue', (/dhnoflo/)), &
493  this%nc_fname)
494  ! cell_methods (CF-1.13 7.3): dependent variable values are the
495  ! instantaneous simulated state at each output time, not a time
496  ! mean/accumulation over the interval -- an intensive quantity whose
497  ! default method is already "point" per CF's own Appendix E, stated
498  ! explicitly here per CF's recommendation to do so for every
499  ! spatio-temporal dimension.
500  call nf_verify(nf90_put_att(this%ncid, this%var_ids%dependent(k), &
501  'cell_methods', 'time: point'), &
502  this%nc_fname)
503 
504  ! add grid mapping (mesh, location, coordinates, grid_mapping)
505  call ncvar_gridmap(this%ncid, this%var_ids%dependent(k), &
506  this%gridmap_name, k, this%nc_fname)
507 
508  ! add layer attribute
509  call ncvar_layer(this%ncid, this%var_ids%dependent(k), k, &
510  this%nc_fname)
511  end do
512  end subroutine define_dependent
513 
514  !> @brief create the file grid mapping container variable
515  !<
516  subroutine define_gridmap(this)
517  class(meshmodeltype), intent(inout) :: this
518  integer(I4B) :: var_id
519  character(len=LINELENGTH) :: gmname
520  character(len=LENBIGLINE) :: effective_crs_wkt
521 
522  ! was projection info provided
523  if (this%wkt /= '' .or. this%crs_wkt /= '') then
524  ! create projection variable
525  call nf_verify(nf90_redef(this%ncid), this%nc_fname)
526  call nf_verify(nf90_def_var(this%ncid, this%gridmap_name, nf90_int, &
527  var_id), this%nc_fname)
528  ! wkt (WKT1, OGC 01-009) -- for legacy/QGIS compatibility
529  if (this%wkt /= '') then
530  call nf_verify(nf90_put_att(this%ncid, var_id, 'wkt', this%wkt), &
531  this%nc_fname)
532  end if
533  ! crs_wkt (WKT2, ISO 19162:2019) -- required by CF-1.13
534  if (this%crs_wkt /= '') then
535  effective_crs_wkt = this%crs_wkt
536  else
537  effective_crs_wkt = this%wkt
538  end if
539  call nf_verify(nf90_put_att(this%ncid, var_id, 'crs_wkt', &
540  trim(effective_crs_wkt)), this%nc_fname)
541  ! grid_mapping_name derived from WKT projection keyword
542  gmname = wkt_to_cf_gridmapping(trim(effective_crs_wkt))
543  if (gmname /= '') then
544  call nf_verify(nf90_put_att(this%ncid, var_id, 'grid_mapping_name', &
545  trim(gmname)), this%nc_fname)
546  end if
547  call nf_verify(nf90_enddef(this%ncid), this%nc_fname)
548  call nf_verify(nf90_put_var(this%ncid, var_id, 1), &
549  this%nc_fname)
550  end if
551  end subroutine define_gridmap
552 
553  !> @brief create the file mesh container variable
554  !<
555  subroutine create_mesh(this)
556  class(mesh2dmodeltype), intent(inout) :: this
557 
558  ! create mesh container variable
559  call nf_verify(nf90_def_var(this%ncid, this%mesh_name, nf90_int, &
560  this%var_ids%mesh), this%nc_fname)
561 
562  ! assign container variable attributes
563  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, 'cf_role', &
564  'mesh_topology'), this%nc_fname)
565  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, 'long_name', &
566  '2D mesh topology'), this%nc_fname)
567  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, &
568  'topology_dimension', 2), this%nc_fname)
569  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, 'face_dimension', &
570  'nmesh_face'), this%nc_fname)
571  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, &
572  'node_coordinates', 'mesh_node_x mesh_node_y'), &
573  this%nc_fname)
574  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, &
575  'face_coordinates', 'mesh_face_x mesh_face_y'), &
576  this%nc_fname)
577  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh, &
578  'face_node_connectivity', 'mesh_face_nodes'), &
579  this%nc_fname)
580 
581  ! create mesh x node (mesh vertex) variable
582  call nf_verify(nf90_def_var(this%ncid, 'mesh_node_x', nf90_double, &
583  (/this%dim_ids%nmesh_node/), &
584  this%var_ids%mesh_node_x), this%nc_fname)
585 
586  ! assign mesh x node variable attributes
587  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_x, &
588  'units', this%lenunits), this%nc_fname)
589  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_x, &
590  'standard_name', 'projection_x_coordinate'), &
591  this%nc_fname)
592  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_x, &
593  'long_name', 'Easting'), this%nc_fname)
594 
595  if (this%gridmap_name /= '') then
596  ! associate with projection
597  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_x, &
598  'grid_mapping', this%gridmap_name), &
599  this%nc_fname)
600  end if
601 
602  ! create mesh y node (mesh vertex) variable
603  call nf_verify(nf90_def_var(this%ncid, 'mesh_node_y', nf90_double, &
604  (/this%dim_ids%nmesh_node/), &
605  this%var_ids%mesh_node_y), this%nc_fname)
606 
607  ! assign mesh y variable attributes
608  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_y, &
609  'units', this%lenunits), this%nc_fname)
610  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_y, &
611  'standard_name', 'projection_y_coordinate'), &
612  this%nc_fname)
613  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_y, &
614  'long_name', 'Northing'), this%nc_fname)
615 
616  if (this%gridmap_name /= '') then
617  ! associate with projection
618  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_node_y, &
619  'grid_mapping', this%gridmap_name), &
620  this%nc_fname)
621  end if
622 
623  ! create mesh x face (cell vertex) variable
624  call nf_verify(nf90_def_var(this%ncid, 'mesh_face_x', nf90_double, &
625  (/this%dim_ids%nmesh_face/), &
626  this%var_ids%mesh_face_x), this%nc_fname)
627 
628  ! assign mesh x face variable attributes
629  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_x, &
630  'units', this%lenunits), this%nc_fname)
631  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_x, &
632  'standard_name', 'projection_x_coordinate'), &
633  this%nc_fname)
634  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_x, &
635  'long_name', 'Easting'), this%nc_fname)
636  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_x, 'bounds', &
637  'mesh_face_xbnds'), this%nc_fname)
638  if (this%gridmap_name /= '') then
639  ! associate with projection
640  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_x, &
641  'grid_mapping', this%gridmap_name), &
642  this%nc_fname)
643  end if
644 
645  ! create mesh x cell bounds variable
646  call nf_verify(nf90_def_var(this%ncid, 'mesh_face_xbnds', nf90_double, &
647  (/this%dim_ids%max_nmesh_face_nodes, &
648  this%dim_ids%nmesh_face/), &
649  this%var_ids%mesh_face_xbnds), &
650  this%nc_fname)
651 
652  ! create mesh y face (cell vertex) variable
653  call nf_verify(nf90_def_var(this%ncid, 'mesh_face_y', nf90_double, &
654  (/this%dim_ids%nmesh_face/), &
655  this%var_ids%mesh_face_y), this%nc_fname)
656 
657  ! assign mesh y face variable attributes
658  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_y, &
659  'units', this%lenunits), this%nc_fname)
660  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_y, &
661  'standard_name', 'projection_y_coordinate'), &
662  this%nc_fname)
663  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_y, &
664  'long_name', 'Northing'), this%nc_fname)
665  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_y, 'bounds', &
666  'mesh_face_ybnds'), this%nc_fname)
667 
668  if (this%gridmap_name /= '') then
669  ! associate with projection
670  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_y, &
671  'grid_mapping', this%gridmap_name), &
672  this%nc_fname)
673  end if
674 
675  ! create mesh y cell bounds variable
676  call nf_verify(nf90_def_var(this%ncid, 'mesh_face_ybnds', nf90_double, &
677  (/this%dim_ids%max_nmesh_face_nodes, &
678  this%dim_ids%nmesh_face/), &
679  this%var_ids%mesh_face_ybnds), &
680  this%nc_fname)
681 
682  ! create mesh face nodes variable
683  call nf_verify(nf90_def_var(this%ncid, 'mesh_face_nodes', nf90_int, &
684  (/this%dim_ids%max_nmesh_face_nodes, &
685  this%dim_ids%nmesh_face/), &
686  this%var_ids%mesh_face_nodes), &
687  this%nc_fname)
688 
689  ! assign variable attributes
690  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_nodes, &
691  'cf_role', 'face_node_connectivity'), &
692  this%nc_fname)
693  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_nodes, &
694  'long_name', &
695  'Vertices bounding cell (counterclockwise)'), &
696  this%nc_fname)
697  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_nodes, &
698  '_FillValue', (/nf90_fill_int/)), &
699  this%nc_fname)
700  call nf_verify(nf90_put_att(this%ncid, this%var_ids%mesh_face_nodes, &
701  'start_index', 1), this%nc_fname)
702  end subroutine create_mesh
703 
704  !> @brief define variable chunking
705  !<
706  subroutine ncvar_chunk(ncid, varid, chunk_face, nc_fname)
707  integer(I4B), intent(in) :: ncid
708  integer(I4B), intent(in) :: varid
709  integer(I4B), intent(in) :: chunk_face
710  character(len=*), intent(in) :: nc_fname
711  if (chunk_face > 0) then
712  call nf_verify(nf90_def_var_chunking(ncid, varid, nf90_chunked, &
713  (/chunk_face/)), nc_fname)
714  end if
715  end subroutine ncvar_chunk
716 
717  !> @brief define variable compression
718  !<
719  subroutine ncvar_deflate(ncid, varid, deflate, shuffle, nc_fname)
720  integer(I4B), intent(in) :: ncid
721  integer(I4B), intent(in) :: varid
722  integer(I4B), intent(in) :: deflate
723  integer(I4B), intent(in) :: shuffle
724  character(len=*), intent(in) :: nc_fname
725  if (deflate >= 0) then
726  call nf_verify(nf90_def_var_deflate(ncid, varid, shuffle=shuffle, &
727  deflate=1, deflate_level=deflate), &
728  nc_fname)
729  end if
730  end subroutine ncvar_deflate
731 
732  !> @brief put variable gridmap attributes
733  !!
734  !! layer must be the 1-based layer number when varid is a per-layer
735  !! variable (e.g. npf_k_l3), or 0 when it is not layered (e.g. a flat
736  !! NCPL-shaped array). z_l{layer} is only referenced from coordinates
737  !! when layer > 0, since it is the only case where z_l{layer} shares
738  !! nmesh_face with varid (CF-1.13 5.2 subset rule).
739  !<
740  subroutine ncvar_gridmap(ncid, varid, gridmap_name, layer, nc_fname)
741  integer(I4B), intent(in) :: ncid
742  integer(I4B), intent(in) :: varid
743  character(len=*), intent(in) :: gridmap_name
744  integer(I4B), intent(in) :: layer
745  character(len=*), intent(in) :: nc_fname
746  character(len=LINELENGTH) :: coords
747  ! UGRID topology attrs are CRS-independent -- always written on face vars
748  call nf_verify(nf90_put_att(ncid, varid, 'mesh', 'mesh'), nc_fname)
749  call nf_verify(nf90_put_att(ncid, varid, 'location', 'face'), nc_fname)
750  if (layer > 0) then
751  write (coords, '(a,i0)') 'mesh_face_x mesh_face_y z_l', layer
752  else
753  coords = 'mesh_face_x mesh_face_y'
754  end if
755  call nf_verify(nf90_put_att(ncid, varid, 'coordinates', trim(coords)), &
756  nc_fname)
757  ! grid_mapping only written when a CRS is configured
758  if (gridmap_name /= '') then
759  call nf_verify(nf90_put_att(ncid, varid, 'grid_mapping', &
760  gridmap_name), nc_fname)
761  end if
762  end subroutine ncvar_gridmap
763 
764  !> @brief put variable internal attributes
765  !<
766  subroutine ncvar_mf6attr(ncid, varid, layer, iaux, nc_tag, nc_fname)
767  integer(I4B), intent(in) :: ncid
768  integer(I4B), intent(in) :: varid
769  integer(I4B), intent(in) :: layer
770  integer(I4B), intent(in) :: iaux
771  character(len=*), intent(in) :: nc_tag
772  character(len=*), intent(in) :: nc_fname
773  if (nc_tag /= '') then
774  call nf_verify(nf90_put_att(ncid, varid, 'modflow_input', &
775  nc_tag), nc_fname)
776  call ncvar_layer(ncid, varid, layer, nc_fname)
777  if (iaux > 0) then
778  call nf_verify(nf90_put_att(ncid, varid, 'modflow_iaux', &
779  iaux), nc_fname)
780  end if
781  end if
782  end subroutine ncvar_mf6attr
783 
784  !> @brief put the layer attribute (only when layer > 0)
785  !!
786  !! layer identifies which layer a per-layer-split mesh variable belongs
787  !! to (e.g. head_l3, npf_k_l3) -- distinct from the layer dimension
788  !! coordinate. Not a CF/UGRID attribute; MF6-internal. Applies to every
789  !! per-layer-split variable.
790  !<
791  subroutine ncvar_layer(ncid, varid, layer, nc_fname)
792  integer(I4B), intent(in) :: ncid
793  integer(I4B), intent(in) :: varid
794  integer(I4B), intent(in) :: layer
795  character(len=*), intent(in) :: nc_fname
796  if (layer > 0) then
797  call nf_verify(nf90_put_att(ncid, varid, 'layer', layer), nc_fname)
798  end if
799  end subroutine ncvar_layer
800 
801 end module meshmodelmodule
abstract interfaces for derived ugrid netcd export types
Definition: MeshNCModel.f90:86
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
integer(i4b), parameter lencomponentname
maximum length of a component name
Definition: Constants.f90:18
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
integer(i4b), parameter lenbigline
maximum length of a big line
Definition: Constants.f90:15
real(dp), parameter dhnoflo
real no flow constant
Definition: Constants.f90:93
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
This module contains the DefinitionSelectModule.
type(inputparamdefinitiontype) function, pointer, public get_param_definition_type(input_definition_types, component_type, subcomponent_type, blockname, tagname, filename, found)
Return parameter definition.
type(inputparamdefinitiontype) function, dimension(:), pointer, public param_definitions(component, subcomponent)
logical function, public idm_multi_package(component, subcomponent)
Input definition module.
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
subroutine, public get_isize(name, mem_path, isize)
@ brief Get the number of elements for this variable
This module contains the MeshModelModule.
Definition: MeshNCModel.f90:7
subroutine, public ncvar_mf6attr(ncid, varid, layer, iaux, nc_tag, nc_fname)
put variable internal attributes
subroutine, public ncvar_gridmap(ncid, varid, gridmap_name, layer, nc_fname)
put variable gridmap attributes
subroutine define_gridmap(this)
create the file grid mapping container variable
subroutine create_timeseries(this, idt, iparam, iaux, layer, export_pkg)
create timeseries export variable
subroutine, public ncvar_chunk(ncid, varid, chunk_face, nc_fname)
define variable chunking
subroutine mesh_init(this, modelname, modeltype, modelfname, nc_fname, disenum, nctype, lenuni, iout)
initialize
subroutine mesh_destroy(this)
initialize
subroutine add_global_att(this)
create file (group) attributes
subroutine add_pkg_data(this)
determine packages to write gridded input
subroutine df_export(this)
define timeseries input variables
subroutine export_df(this, export_pkg)
define export package
subroutine, public ncvar_layer(ncid, varid, layer, nc_fname)
put the layer attribute (only when layer > 0)
subroutine export_input_arrays(this, pkgtype, pkgname, mempath, param_dfns)
write package gridded input data
subroutine define_dependent(this)
create the model layer dependent variables
subroutine, public ncvar_deflate(ncid, varid, deflate, shuffle, nc_fname)
define variable compression
subroutine create_mesh(this)
create the file mesh container variable
This module contains the NCModelExportModule.
Definition: NCModel.f90:8
character(len=linelength) function, public wkt_to_cf_gridmapping(wkt)
map a WKT string to a CF-1.13 grid_mapping_name
Definition: NCModel.f90:574
character(len=linelength) function, public export_varname(pkgname, tagname, mempath, layer, iaux)
build netcdf variable name
Definition: NCModel.f90:455
character(len=linelength) function, public export_longname(longname, pkgname, tagname, mempath, layer, iaux, component_type, subcomponent_type)
build netcdf variable longname
Definition: NCModel.f90:496
This module contains the NetCDFCommonModule.
Definition: NetCDFCommon.f90:6
subroutine, public nf_verify(res, nc_fname)
error check a netcdf-fortran interface call
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_warning(msg, substring)
Store warning message.
Definition: Sim.f90:237
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
subroutine, public store_error_filename(filename, terminate)
Store the erroring file name.
Definition: Sim.f90:204
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
character(len=linelength) idm_context
character(len=maxcharlen) warnmsg
warning message string
This module contains the SourceCommonModule.
Definition: SourceCommon.f90:7
character(len=lencomponentname) function, public idm_subcomponent_type(component, subcomponent)
component from package or model type
This class is used to store a single deferred-length character string. It was designed to work in an ...
Definition: CharString.f90:23
Input parameter definition. Describes an input parameter.
base ugrid netcdf export type
Definition: MeshNCModel.f90:64
type for storing model export dimension ids
Definition: MeshNCModel.f90:34
type for storing model export variable ids
Definition: MeshNCModel.f90:45
abstract type for model netcdf export type
Definition: NCModel.f90:111