FV3 Bundle
nc_diag_write_mod.F90
Go to the documentation of this file.
1 ! nc_diag_write - NetCDF Layer Diag Writing Module
2 ! Copyright 2015 Albert Huang - SSAI/NASA for NASA GSFC GMAO (610.1).
3 !
4 ! Licensed under the Apache License, Version 2.0 (the "License");
5 ! you may not use this file except in compliance with the License.
6 ! You may obtain a copy of the License at
7 !
8 ! http://www.apache.org/licenses/LICENSE-2.0
9 !
10 ! Unless required by applicable law or agreed to in writing, software
11 ! distributed under the License is distributed on an "AS IS" BASIS,
12 ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 ! implied. See the License for the specific language governing
14 ! permissions and limitations under the License.
15 !
16 ! Main module - nc_diag_write_mod
17 !
18 
20  ! Library that provides a high level interface for storing channel-
21  ! based and observation-based data.
22  !
23  ! This library allows developers to easily store channel-based data
24  ! (e.g. chaninfo) and observation-based data (metadata and data2d)
25  ! to a NetCDF file via an easy to use API.
26  !
27  ! Internally, the process for storing this data looks like this:
28  ! -> When the developer calls nc_diag_init, the NetCDF file is
29  ! opened internally. The corresponding NCID is stored, and
30  ! any memory allocation needed is done at this step.
31  ! => If the file was opened in append mode, nc_diag_write will
32  ! attempt to load any existing variable definitions for all
33  ! types of variables - chaninfo, metadata, and data2d.
34  ! Appropriate variable counters and data for each variable
35  ! type will be set during init, and data writing will start
36  ! at the end of the variable.
37  !
38  ! -> Headers are essentially NetCDF global attributes, or
39  ! attributes that describe a file. These can be added at any
40  ! time during the writing session.
41  !
42  ! -> varattr, or variable attributes, describe an associated
43  ! variable. (This is a NetCDF4 variable attribute!) These can
44  ! only be added after variable definitions have been locked.
45  !
46  ! -> chaninfo variables:
47  ! => nc_diag_chaninfo_dim_set must be called first to set
48  ! the nchans dimension. If it isn't called, doing any
49  ! chaninfo operation will result in an error.
50  ! => chaninfo variables are 1D, with nchans number of elements.
51  !
52  ! -> metadata and data2d variables:
53  ! => metadata and data2d variables do not require any initial
54  ! dimension setting - nc_diag_write will keep track of your
55  ! number of observations for you!
56  ! => metadata variables are 1D, with nobs number of elements.
57  ! nobs can increase infinitely to fit the number of
58  ! observations recorded.
59  ! => data2d variables are 2D, with dimensions of nobs by
60  ! another fixed dimension.
61  !
62  ! -> Definition locking is sometimes necessary for certain
63  ! operations, such as defining variable attributes. They are
64  ! necessary due to needing information from NetCDF after
65  ! variables are defined, or needing to assert that certain
66  ! variable properties are constant. Locking uses the following
67  ! steps:
68  ! => nc_diag_*_write_def is called to send the variable
69  ! definitions to NetCDF. This include defining any
70  ! dimensions necessary, as well as defining the variables
71  ! stored as well.
72  ! => Once each nc_diag_*_write_def completes, their
73  ! corresponding def_lock state will be set to TRUE, locking
74  ! the definitions in place.
75  ! => Attempts to make repeated calls will result in an error,
76  ! due to the def_lock state being set to TRUE.
77  !
78  ! -> Data calls will store the input data into memory. The
79  ! implementation and design of the variable storage is
80  ! dependent on the variable type being stored. chaninfo
81  ! variables have a certain storage format, and metadata/data2d
82  ! variables have another storage format. Note that metadata
83  ! and data2d code have a few similarities in data storage
84  ! since the variables themselves share common features, like
85  ! the nobs dimension.
86  !
87  ! -> Sometimes, there is a significant amount of data that needs
88  ! to be processed and stored. Since nc_diag_write stores all
89  ! of the data into memory (RAM) before it is written out,
90  ! there may not be enough memory to store the entirety of the
91  ! data. To alleviate that, nc_diag_flush_buffer can be called
92  ! to flush the data from the memory and write them to disk.
93  ! In reality, this doesn't actually free any memory... but the
94  ! memory savings gained is still there. Calling the flushing
95  ! subroutine performs the following steps:
96  ! => It first checks to make sure that definitions are locked.
97  ! The NetCDF variable IDs are needed in order to actually
98  ! write (or "put") any data into the file.
99  ! => It also checks to see if the data has already been locked.
100  ! No more data can be written if the data has been locked.
101  ! => It then calls all of the nc_diag_*_write_data subroutines
102  ! with a special flag to indicate data flushing. When the
103  ! data flushing flag is set, each of the variable
104  ! subroutines will take measures to operate as a buffer
105  ! flush, and not as a finalized data write.
106  ! => When flushing within the variable subroutine, the
107  ! subroutine first writes out any data using the variable-
108  ! specific, memory-stored data.
109  ! => It then resets any internal data counters that it may use
110  ! to store and keep track of the data.
111  ! => As mentioned before, it does not actually free any memory
112  ! since deallocating and subsequently reallocating from
113  ! scratch will take a long time, and is inefficient. With
114  ! a counter reset, each variable type's internal data
115  ! storage will start at the beginning of the data array,
116  ! effectively avoiding any need to add any more memory, and
117  ! thus achieving the goal of not using any more memory.
118  ! => Finally, since the writing is in buffer flushing mode,
119  ! the data_lock flag for each variable type is NOT set.
120  ! This is so that more data can be written, either with
121  ! the flushing method or with the regular write.
122  !
123  ! -> Once data is done being queued ("stored"), nc_diag_write can
124  ! be called. The variables will have their data re-read from
125  ! memory and actually written to the file. This is also very
126  ! much variable type independent, since every variable has its
127  ! own way of storing variable data. Again, metadata and data2d
128  ! have similar code, with the only difference being the
129  ! dimensionality. Note that this is where NetCDF calls are
130  ! made to define and "put" data. Once done, if we are NOT in
131  ! append mode, we call nf90_enddef to end define mode.
132  !
133  ! -> Once all the data has been queued and/or written out, it is
134  ! safe to call nc_diag_finish. We call this from nc_diag_write.
135  ! => This will first write definitions and data, if applicable.
136  ! The calls will have a special flag set to ensure that no
137  ! errors are triggered for already having a lock set, since
138  ! this subroutine will be closing the file anyways.
139  ! => Once all of the data has been sent to NetCDF, this will
140  ! tell NetCDF to close the file being written. Note that
141  ! NetCDF also keeps a memory cache of the data being stored
142  ! as well, so actual I/O writing may not be completely done
143  ! until here. After the writing and closing on the NetCDF
144  ! side completes, everything will be completely deallocated,
145  ! and everything will be reset.
146  !
147  ! -> Upon reset, nc_diag_write is again ready to write a new file
148  ! via nc_diag_create!
149  !
150  ! Note that only ONE file is written as a time. This is due to the
151  ! nature of the library focusing and storing data for a single
152  ! file. Attempting to create another file without closing the
153  ! previous one will result in an error.
154 
155  ! Load state variables! We need to know:
156  ! init_done - ...whether a file is currently loaded or
157  ! not.
158  ! append_only - ...whether we are in append mode or not.
159  ! ncid - ...the current NCID of our file.
160  ! enable_trim - ...whether we need to automatically trim
161  ! our strings for chaninfo string storage or
162  ! not.
163  ! diag_chaninfo_store - ...chaninfo variable information.
164  ! Specifically, whether it's allocated or
165  ! not, and if it's allocated, whether the
166  ! definitions are locked or not. (def_lock)
167  ! diag_metadata_store - ...metadata variable information.
168  ! Specifically, whether it's allocated or
169  ! not, and if it's allocated, whether the
170  ! definitions are locked or not. (def_lock)
171  ! diag_data2d_store - ...data2d variable information.
172  ! Specifically, whether it's allocated or
173  ! not, and if it's allocated, whether the
174  ! definitions are locked or not. (def_lock)
175  use ncdw_state, only: init_done, append_only, ncid, &
179 
180  ! Load needed NetCDF functions and constants
181  use netcdf, only: nf90_inq_libvers, nf90_open, nf90_create, &
182  nf90_enddef, nf90_close, nf90_sync, &
183  nf90_write, nf90_netcdf4, nf90_clobber
184 
185  !------------------------------------------------------------------
186  ! API imports to expose API from this module
187  ! (Plus general imports for this module as well!)
188  !------------------------------------------------------------------
189 
190  ! Load necessary command line message subroutines and state
191  ! variables
192  use ncdw_climsg, only: &
193 #ifdef enable_action_msgs
194  nclayer_enable_action, nclayer_actionm, &
195 #endif
196  nclayer_error, nclayer_warning, nclayer_info, nclayer_check, &
197  nc_set_info_display, nc_set_action_display
198 
199  ! Load nc_diag_write specific types
202 
203  ! Load header writing API
204  use ncdw_lheader, only: nc_diag_header
205 
206  ! Load chaninfo writing API + auxillary functions for our use
214 
215  ! Load metadata writing API + auxillary functions for our use
216  use ncdw_metadata, only: nc_diag_metadata, &
224 
225  ! Load data2d writing API + auxillary functions for our use
226  use ncdw_data2d, only: nc_diag_data2d, &
234 
235  ! Load varattr (variable attribute) writing API
236  use ncdw_varattr, only: nc_diag_varattr
237 
238  implicit none
239 
240  contains
241  ! Creates or appends to a new NetCDF file for data writing.
242  !
243  ! Given the target NetCDF file name, attempt to create or open
244  ! the file and set everything up for writing data to the file.
245  ! This includes any internal memory allocation required for
246  ! buffering any data sent to this file.
247  !
248  ! If the file is opened in non-append mode (default), this will
249  ! attempt to create a new file and start data writing from
250  ! scratch. If the file already exists, it will be OVERWRITTEN
251  ! without any prompt.
252  !
253  ! If the file is opened in append mode, this will attempt to
254  ! open the file specified, read the file's dimension and
255  ! variable storage information, and set things up so that
256  ! data writing starts at the end of the file's existing data.
257  ! Note that append mode only works for nc_diag_write NetCDF
258  ! files. Attempting to open a non-nc_diag_write file could
259  ! result in errors!
260  !
261  ! In order for the file to be written to successfully,
262  ! nc_diag_finish MUST be called for all of the data to be
263  ! flushed, and the corresponding memory to be freed.
264  !
265  ! nc_diag_write may only operate on one file at a time. This is
266  ! due to the nature of nc_diag_write focusing on a single file.
267  !
268  ! If a NetCDF file is already open, this will raise an error
269  ! and the program will terminate.
270  !
271  ! Args:
272  ! filename (character(len=*)): NetCDF file name to create or
273  ! append to.
274  ! append (logical, optional): whether to open the NetCDF
275  ! file in append mode or not. By default, if this is
276  ! not specified, the file will be opened regularly (not
277  ! in append mode).
278  !
279  ! Raises:
280  ! If a file is already open, an error occurs and the program
281  ! will exit.
282  !
283  ! If the file specified does not exist, or there are issues
284  ! with NetCDF creating/opening/using the file, an error
285  ! will occur with the corresponding NetCDF error.
286  !
287  ! Issues with storage allocation are bugs, and will also
288  ! result in an error with an indication that a bug has
289  ! occurred.
290  !
291  subroutine nc_diag_init(filename, append)
292  character(len=*),intent(in) :: filename
293  logical, intent(in), optional :: append
294 
295  ! Buffer size variable for NetCDF optimization settings
296  ! (Not sure if this helps much...)
297  integer :: bsize = 16777216;
298 
299 #ifdef ENABLE_ACTION_MSGS
300  character(len=1000) :: action_str
301 
302  if (nclayer_enable_action) then
303  if (present(append)) then
304  write(action_str, "(A, L, A)") "nc_diag_init(filename = " // trim(filename) // &
305  ", append = ", append, ")"
306  else
307  write(action_str, "(A)") "nc_diag_init(filename = " // trim(filename) // &
308  ", append = (not specified))"
309  end if
310  call nclayer_actionm(trim(action_str))
311  end if
312 #endif
313 
314  ! Inform user about NetCDF version
315  call nclayer_info('Initializing netcdf layer library, version ' // trim(nf90_inq_libvers()) // '...')
316 
317  ! Make sure we haven't initialized yet. If we have, it
318  ! means that another file is open that hasn't been closed
319  ! yet!
320  if (.NOT. init_done) then
321  ! Special append mode - that means that we need to
322  ! assume that all definitions are set and locked.
323  if (present(append) .AND. (append .eqv. .true.)) then
324  ! Open the file in append mode!
325  call nclayer_check( nf90_open(filename, nf90_write, ncid, &
326  bsize, cache_nelems = 16777216) ) ! Optimization settings
327 
328  ! Set the append flag
329  append_only = .true.
330  else
331  ! Create the file from scratch!
332 
333  ! nf90_create creates the NetCDF file, and initializes
334  ! everything needed to write a NetCDF file.
335  !
336  ! NF90_CLOBBER forces overwriting the file, even if it already
337  ! exists.
338  !
339  ! ncid is a special ID that the NetCDF library uses to keep
340  ! track of what file you're working on. We're returning that
341  ! here.
342  call nclayer_check( nf90_create(filename, or(nf90_netcdf4, nf90_clobber), ncid, &
343  0, bsize, cache_nelems = 16777216) ) ! Optimization settings
344  end if
345 
346  ! Allocation sanity checks...
347  ! These storage variables should NOT be allocated.
348  ! If they are, it indicate that we have a serious problem.
349  if (allocated(diag_chaninfo_store)) then
350  call nclayer_error("BUG! diag_chaninfo_store is allocated, but init_done is not set!")
351  end if
352 
353  if (allocated(diag_metadata_store)) then
354  call nclayer_error("BUG! diag_metadata_store is allocated, but init_done is not set!")
355  end if
356 
357  if (allocated(diag_data2d_store)) then
358  call nclayer_error("BUG! diag_data2d_store is allocated, but init_done is not set!")
359  end if
360 
361  if (allocated(diag_varattr_store)) then
362  call nclayer_error("BUG! diag_data2d_store is allocated, but init_done is not set!")
363  end if
364 
365  ! All good, allocate the storage variables!
366  allocate(diag_chaninfo_store)
367  allocate(diag_metadata_store)
368  allocate(diag_data2d_store)
369  allocate(diag_varattr_store)
370 
371  ! Set the current file being written to...
372  cur_nc_file = filename
373 
374  ! Set the flag state to indicate that a file is open,
375  ! and that initialization is done.
376  init_done = .true.
377 
378  ! "Lock and load" the definitions... or simply ask
379  ! chaninfo/metadata/data2d to read the NetCDF files,
380  ! build a cache, and set up anything necessary to be
381  ! able to resume writing from before.
382  if (present(append) .AND. (append .eqv. .true.)) then
383  call nclayer_info("Loading chaninfo variables/dimensions from file:")
385 
386  call nclayer_info("Loading metadata variables/dimensions from file:")
388 
389  call nclayer_info("Loading data2d variables/dimensions from file:")
391  end if
392  else
393  ! Opening a new file while another file is still open is
394  ! bad... let's yell at the user/developer!
395  call nclayer_error("Attempted to initialize without closing previous nc_diag file!" &
396  // char(10) &
397  // " (Previous file: " // trim(cur_nc_file) &
398  // char(10) &
399  // " Attempted to open file: " // trim(filename) // ")")
400  end if
401  end subroutine nc_diag_init
402 
403  ! Lock and commit the variable definitions for the current
404  ! NetCDF file.
405  !
406  ! Attempt to commit the currently stored variable definitions
407  ! to the NetCDF file via NetCDF API calls. Once done, this will
408  ! set the flag for locking the variable definitions, preventing
409  ! any additional variables from being created or changed.
410  !
411  ! Locking the definitions here will enable functions that
412  ! require variable definition locking. This include
413  ! nc_diag_varattr and nc_diag_flush_buffer, both of which
414  ! require the variable definitions to be committed and locked.
415  !
416  ! Definitions may not be locked more than once. In addition,
417  ! creating new variables after definitions are locked will
418  ! result in errors.
419  !
420  ! Args:
421  ! None
422  !
423  ! Raises:
424  ! The following errors will trigger indirectly from other
425  ! subroutines called here:
426  !
427  ! If definitions have already been locked, this will result
428  ! in an error.
429  !
430  ! If there is no file open, this will result in an error.
431  !
432  ! Other errors may result from invalid data storage, NetCDF
433  ! errors, or even a bug. See the called subroutines'
434  ! documentation for details.
435  !
436  subroutine nc_diag_lock_def
437 #ifdef ENABLE_ACTION_MSGS
438  if (nclayer_enable_action) then
439  call nclayer_actionm("nc_diag_lock_def()")
440  end if
441 #endif
442  call nclayer_info("Locking all variable definitions!")
443 
444  ! Call all of the variable write_def
445  call nclayer_info("Defining chaninfo:")
447 
448  call nclayer_info("Defining metadata:")
450 
451  call nclayer_info("Defining data2d:")
453 
454  call nclayer_info("All variable definitions locked!")
455  end subroutine nc_diag_lock_def
456 
457  ! Write all of the variables to the NetCDF file, including the
458  ! variable definitions and data, and close the file.
459  !
460  ! Attempt to write the currently stored variable definitions
461  ! and data to the NetCDF file via NetCDF API calls.
462  !
463  ! Once done, this will lock both the definitions and the data,
464  ! preventing any new variables or new data from being written
465  ! after this call completes.
466  !
467  ! Once data has been written and locked, the file itself will be
468  ! closed. NetCDF may internally cache/buffer variable data in
469  ! memory, so actual writing may occur at this time to let NetCDF
470  ! actually commit the data to disk.
471  !
472  ! Finally, nc_diag_write state cleanup and memory deallocation
473  ! will occur via a call to nc_diag_finish.
474  !
475  ! Writing may not occur more than once. In addition, writing any
476  ! new variables or adding any new data will result in an error.
477  ! (Not that you can write any more data after this, since the
478  ! file is closed and everything is reset...)
479  !
480  ! Args:
481  ! None
482  !
483  ! Raises:
484  ! The following errors will trigger indirectly from other
485  ! subroutines called here:
486  !
487  ! If the variable definitions have already been locked, this
488  ! will NOT result in an error. This is due to the fact that
489  ! we could've locked definitions earlier, and that we
490  ! can assume that with locked definitions, we are able to
491  ! write data.
492  !
493  ! Data writing is the critical part. If the variable data
494  ! writing has already been locked, this will result in an
495  ! error.
496  !
497  ! If there is no file open (or the file is already closed),
498  ! this will result in an error.
499  !
500  ! Other errors may result from invalid data storage, NetCDF
501  ! errors, or even a bug. See the called subroutines'
502  ! documentation for details.
503  !
504  subroutine nc_diag_write
505 #ifdef ENABLE_ACTION_MSGS
506  if (nclayer_enable_action) then
507  call nclayer_actionm("nc_diag_write()")
508  end if
509 #endif
510 
511  ! Call all variable write_def, with an extra option to make
512  ! sure that no errors occur during write, even when locked!
513  ! (We could have previously locked, but here we're doing it
514  ! on purpose!)
515  call nclayer_info("Defining chaninfo:")
516  call nc_diag_chaninfo_write_def(.true.)
517 
518  call nclayer_info("Defining metadata:")
519  call nc_diag_metadata_write_def(.true.)
520 
521  call nclayer_info("Defining data2d:")
522  call nc_diag_data2d_write_def(.true.)
523 
524  ! Lock definition writing!
525  if ((.NOT. append_only) .AND. ((.NOT. diag_chaninfo_store%def_lock) .OR. &
526  (.NOT. diag_metadata_store%def_lock) .OR. &
527  (.NOT. diag_data2d_store%def_lock))) &
528  call nclayer_check(nf90_enddef(ncid))
529 
530  ! Call all variable write_data
531  call nclayer_info("Writing chaninfo:")
533 
534  call nclayer_info("Writing metadata:")
536 
537  call nclayer_info("Writing data2d:")
539 
540  ! Call nf90_close to save everything to disk!
541  call nclayer_info("All done queuing in data, letting NetCDF take over!")
542  call nclayer_check(nf90_close(ncid))
543 
544  call nclayer_info("All done!")
545 
546  ! Call our cleanup subroutine
547  call nc_diag_finish
548  end subroutine nc_diag_write
549 
550  ! Reset nc_diag_write state, and deallocate all of the variable
551  ! storage in preparation for another new NetCDF file write.
552  !
553  ! Attempt to reset nc_diag_write state and deallocate all of
554  ! the variable storage. This frees up memory, and allows for
555  ! nc_diag_init to work again for a new file.
556  !
557  ! This can only be called once per open. (You can't call this
558  ! without a nc_diag_init happening before it!) Calling this
559  ! without any file opened (or data stored) will result in an
560  ! error.
561  !
562  ! This is an internal subroutine, and is NOT meant to be called
563  ! outside of nc_diag_write. Calling this subroutine in your
564  ! program may result in unexpected behavior and/or data
565  ! corruption!
566  !
567  ! Args:
568  ! None
569  !
570  ! Raises:
571  ! If there is no file open, or if no data/state needs to be
572  ! cleaned up, this will result in an error.
573  !
574  ! Issues with storage deallocation are bugs, and will also
575  ! result in an error with an indication that a bug has
576  ! occurred.
577  !
578  subroutine nc_diag_finish
579 #ifdef ENABLE_ACTION_MSGS
580  if (nclayer_enable_action) then
581  call nclayer_actionm("nc_diag_finish()")
582  end if
583 #endif
584  ! Make sure that we only deallocate if we have something
585  ! open/initialized!
586  if (init_done) then
587  call nclayer_info("Cleaning up...")
588 
589  ! Do some quick sanity checks!
590  if (.NOT. allocated(diag_chaninfo_store)) then
591  call nclayer_error("BUG! diag_chaninfo_store is not allocated, but init_done is set!")
592  end if
593 
594  if (.NOT. allocated(diag_metadata_store)) then
595  call nclayer_error("BUG! diag_metadata_store is not allocated, but init_done is set!")
596  end if
597 
598  if (.NOT. allocated(diag_data2d_store)) then
599  call nclayer_error("BUG! diag_data2d_store is not allocated, but init_done is set!")
600  end if
601 
602  if (.NOT. allocated(diag_varattr_store)) then
603  call nclayer_error("BUG! diag_data2d_store is not allocated, but init_done is set!")
604  end if
605 
606  ! Deallocate everything! Note that this deallocates
607  ! everything within the derived type as well.
608  ! (See? Fortran is better than C!)
609  deallocate(diag_chaninfo_store)
610  deallocate(diag_metadata_store)
611  deallocate(diag_data2d_store)
612  deallocate(diag_varattr_store)
613 
614  ! Clear initialization, append, and current file name
615  ! state.
616  init_done = .false.
617  append_only = .false.
618  cur_nc_file = ""
619  else
620  call nclayer_error("Attempted to deallocate without initializing!")
621  end if
622  end subroutine nc_diag_finish
623 
624  ! Flush all of the current variable data to NetCDF, and reset
625  ! all of the variable storage to an initial state.
626  !
627  ! Attempt to write the currently stored variable definitions
628  ! and data to the NetCDF file via NetCDF API calls.
629  !
630  ! Once done, this will effectively "flush" the data from the
631  ! current variable buffers. Internally, this sets a starting
632  ! counter and resets the buffer counter so that new data can
633  ! be stored sequentially without requiring more memory, at least
634  ! until memory runs out for the current buffer.
635  !
636  ! Definitions MUST be locked in order for flushing to work.
637  ! Without definition locking, nc_diag_write is unable to make
638  ! calls to NetCDF due to the lack of variable IDs.
639  !
640  ! If definitions are not locked, calling this will result in an
641  ! error.
642  !
643  ! Data locking does NOT occur with flushing. As a result, this
644  ! subroutine may be called multiple times, and a final
645  ! nc_diag_write can be called once after this call.
646  !
647  ! (Note that calling nc_diag_write will lock the data and close
648  ! the file, regardless of flushing the buffer here!)
649  !
650  ! Args:
651  ! None
652  !
653  ! Raises:
654  ! If definitions have not been locked, this will result in
655  ! an error.
656  !
657  ! The following errors will trigger indirectly from other
658  ! subroutines called here:
659  !
660  ! If the variable data writing has already been locked, this
661  ! will result in an error.
662  !
663  ! If there is no file open (or the file is already closed),
664  ! this will result in an error.
665  !
666  ! Other errors may result from invalid data storage, NetCDF
667  ! errors, or even a bug. See the called subroutines'
668  ! documentation for details.
669  !
670  subroutine nc_diag_flush_buffer
671 #ifdef ENABLE_ACTION_MSGS
672  if (nclayer_enable_action) then
673  call nclayer_actionm("nc_diag_flush_buffer()")
674  end if
675 #endif
676  if (.NOT. init_done) &
677  call nclayer_error("Attempted to flush nc_diag_write buffers without initializing!")
678 
679  if ((.NOT. diag_chaninfo_store%def_lock) .OR. &
680  (.NOT. diag_metadata_store%def_lock) .OR. &
681  (.NOT. diag_data2d_store%def_lock)) &
682  call nclayer_error("Definitions must be locked in order to flush the buffer!")
683 
684  ! Perform writes with the buffer flag set!
685  call nclayer_info("Flushing chaninfo:")
686  call nc_diag_chaninfo_write_data(.true.)
687 
688  call nclayer_info("Flushing metadata:")
689  call nc_diag_metadata_write_data(.true.)
690 
691  call nclayer_info("Flushing data2d:")
692  call nc_diag_data2d_write_data(.true.)
693 
694  call nclayer_info("Flushing done!")
695  end subroutine nc_diag_flush_buffer
696 
697  ! Force NetCDF to flush its buffers and write any data stored to
698  ! disk.
699  !
700  ! Attempt to force the write of NetCDF's stored variable data to
701  ! the NetCDF file via NetCDF API calls.
702  !
703  ! This does NOT flush nc_diag_write's buffers. It only attempts
704  ! to flush NetCDF's internal buffers to disk.
705  !
706  ! If there is no file open, or the file is already closed, this
707  ! will result in an error.
708  !
709  ! Args:
710  ! None
711  !
712  ! Raises:
713  ! If there is no file open (or the file is already closed),
714  ! this will result in an error.
715  !
716  ! Other errors may result from NetCDF errors. Any errors
717  ! from NetCDF are likely to occur if there are problems
718  ! writing to disk. Errors resulting from problems with
719  ! manipulating NetCDF memory or a glitch are unlikely, but
720  ! still possible.
721  !
722  subroutine nc_diag_flush_to_file
723 #ifdef ENABLE_ACTION_MSGS
724  if (nclayer_enable_action) then
725  call nclayer_actionm("nc_diag_flush_to_file()")
726  end if
727 #endif
728  ! Make sure we have something open + initialized
729  if (.NOT. init_done) &
730  call nclayer_error("Attempted to flush NetCDF buffers without initializing!")
731 
732  ! Call nf90_sync to try and commit the put'd data to disk
733  call nclayer_check(nf90_sync(ncid))
734  end subroutine nc_diag_flush_to_file
735 
736  ! Toggle whether nc_diag_write should be strict about dimensions
737  ! and variable consistency.
738  !
739  ! Set the strictness of nc_diag_write for checking dimensions
740  ! and stored variable consistency.
741  !
742  ! If set to TRUE, nc_diag_write will error when consistency
743  ! checks fail.
744  !
745  ! If set to FALSE, nc_diag_write will only display a warning
746  ! when these checks fail.
747  !
748  ! To see more details about what checks are made, see the
749  ! corresponding called subroutine documentation for details.
750  !
751  ! Args:
752  ! enable_strict (logical): whether to be strict with
753  ! consistency checks or not.
754  !
755  ! Raises:
756  ! If there is no file open (or the file is already closed),
757  ! this will result in an error.
758  !
759  ! Although unlikely, other errors may indirectly occur.
760  ! They may be general storage errors, or even a bug.
761  ! See the called subroutines' documentation for details.
762  !
763  subroutine nc_diag_set_strict(enable_strict)
764  logical, intent(in) :: enable_strict
765 
766  ! Make sure we have something open + initialized
767  if (init_done) then
768  ! Call all of the variable set_strict subroutines
769  call nc_diag_chaninfo_set_strict(enable_strict)
770  call nc_diag_metadata_set_strict(enable_strict)
771  call nc_diag_data2d_set_strict(enable_strict)
772  else
773  call nclayer_error("Can't set strictness level - NetCDF4 layer not initialized yet!")
774  end if
775  end subroutine nc_diag_set_strict
776 
777  ! Toggle whether nc_diag_write should trim strings or keep their
778  ! original length.
779  !
780  ! Set the option to trim strings automatically with string
781  ! variable data or not.
782  !
783  ! If set to TRUE, nc_diag_write will automatically trim strings
784  ! to the minimum needed to hold the string. (Extra spaces at
785  ! the end will be trimmed off the largest string in an array,
786  ! and the result will be the bounds for that string array!)
787  !
788  ! If set to FALSE, nc_diag_write will NOT trim any strings. The
789  ! given string length is assumed to be the bounds for holding
790  ! the string. However, nc_diag_write will enforce strict
791  ! checking of the input string length. If the length of the
792  ! string changes during subsequent storage, nc_diag_write
793  ! will error.
794  !
795  ! Note that this only applies to variable string storage.
796  ! Attribute string storage is handled directly by NetCDF.
797  ! From testing, it seems that NetCDF will trim your string when
798  ! storing headers (global attributes).
799  !
800  ! Args:
801  ! do_trim (logical): whether to automatically trim the
802  ! stored strings or not.
803  !
804  ! Raises:
805  ! Nothing... at least here. See above for potential errors
806  ! outside of this subroutine.
807  !
808  subroutine nc_diag_set_trim(do_trim)
809  logical, intent(in) :: do_trim
810 
811  enable_trim = do_trim
812  end subroutine nc_diag_set_trim
813 end module nc_diag_write_mod
type(diag_data2d), allocatable diag_data2d_store
Definition: ncdw_state.f90:18
type(diag_chaninfo), allocatable diag_chaninfo_store
Definition: ncdw_state.f90:16
subroutine nc_diag_data2d_load_def
subroutine nc_diag_data2d_allocmulti(multiplier)
subroutine nc_diag_chaninfo_write_def(internal)
integer(i_byte), parameter nlayer_short
Definition: ncdw_types.F90:11
type(diag_metadata), allocatable diag_metadata_store
Definition: ncdw_state.f90:17
subroutine nc_diag_metadata_prealloc_vars_storage_all(num_of_addl_slots)
subroutine nc_diag_metadata_prealloc_vars_storage(nclayer_type, num_of_addl_slots)
subroutine nc_diag_metadata_allocmulti(multiplier)
logical init_done
Definition: ncdw_state.f90:9
integer(i_byte), parameter nlayer_double
Definition: ncdw_types.F90:14
subroutine nc_diag_metadata_set_strict(enable_strict)
logical enable_trim
Definition: ncdw_state.f90:12
subroutine nc_diag_flush_buffer
subroutine nc_diag_init(filename, append)
subroutine nc_diag_metadata_write_data(flush_data_only)
type(diag_varattr), allocatable diag_varattr_store
Definition: ncdw_state.f90:19
integer(i_byte), parameter nlayer_string
Definition: ncdw_types.F90:15
subroutine nc_diag_data2d_write_data(flush_data_only)
integer(i_long) ncid
Definition: ncdw_state.f90:8
subroutine nc_diag_metadata_prealloc_vars(num_of_addl_vars)
subroutine nc_diag_set_trim(do_trim)
subroutine nc_diag_data2d_prealloc_vars(num_of_addl_vars)
subroutine nc_diag_flush_to_file
subroutine nc_diag_data2d_prealloc_vars_storage_all(num_of_addl_slots)
subroutine nc_diag_chaninfo_dim_set(nchans)
logical append_only
Definition: ncdw_state.f90:10
subroutine nc_diag_chaninfo_set_strict(enable_strict)
subroutine nc_diag_set_strict(enable_strict)
subroutine nc_diag_data2d_write_def(internal)
subroutine nc_diag_chaninfo_write_data(flush_data_only)
subroutine nc_diag_data2d_prealloc_vars_storage(nclayer_type, num_of_addl_slots)
subroutine nc_diag_chaninfo_prealloc_vars_storage(nclayer_type, num_of_addl_slots)
integer(i_byte), parameter nlayer_byte
Definition: ncdw_types.F90:10
character(len=200) cur_nc_file
Definition: ncdw_state.f90:14
subroutine nc_diag_metadata_load_def
subroutine nc_diag_data2d_set_strict(enable_strict)
subroutine nc_diag_chaninfo_allocmulti(multiplier)
subroutine nc_diag_chaninfo_load_def
subroutine nc_diag_chaninfo_prealloc_vars(num_of_addl_vars)
subroutine nc_diag_metadata_write_def(internal)
integer(i_byte), parameter nlayer_float
Definition: ncdw_types.F90:13
integer(i_byte), parameter nlayer_long
Definition: ncdw_types.F90:12