PartMC 2.1.2
output.F90
Go to the documentation of this file.
00001 ! Copyright (C) 2005-2011 Nicole Riemer and Matthew West
00002 ! Licensed under the GNU General Public License version 2 or (at your
00003 ! option) any later version. See the file COPYING for details.
00004 
00005 !> \file
00006 !> The pmc_output module.
00007 
00008 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00009 
00010 !> \page output_format Output File Format
00011 !!
00012 !! PartMC output files are in the <a
00013 !! href="http://www.unidata.ucar.edu/software/netcdf/">NetCDF Classic
00014 !! Format</a> (also known as NetCDF-3 format). The dimensions and
00015 !! variables in the files will depend on the type of run (particle,
00016 !! analytical solution, etc), and options in the spec file (e.g. \c
00017 !! record_removals and \c do_optical).
00018 !!
00019 !! The state of the simulation is periodically output during the run,
00020 !! with frequency determined by the \c t_output input parameter. Each
00021 !! output file has a filename of the form \c PREFIX_RRRR_SSSSSSSS.nc,
00022 !! where \c PREFIX is given by the \c output_prefix input parameter,
00023 !! \c RRRR is the four-digit repeat number (starting from 1), and \c
00024 !! SSSSSSSS is the eight-digit output index (starting at 1 and
00025 !! incremented each time the state is output). For exact and sectional
00026 !! simulations all repeats would be identical so there is no support
00027 !! for repeating and the filename is of the format \c
00028 !! PREFIX_SSSSSSSS.nc.
00029 !!
00030 !! If run in parallel and \c output_type is \c central or \c dist,
00031 !! then the output files have names like \c
00032 !! PREFIX_RRRR_PPPP_SSSSSSSS.nc, where \c PPPP is a four-digit
00033 !! process number (starting from 1) and the other variables are as
00034 !! above. If \c output_type is \c single then the output file naming
00035 !! scheme as the same as for serial runs.
00036 !!
00037 !! The data in each output file comes in several different groups, as
00038 !! follows:
00039 !!
00040 !! \subpage output_format_general "General Information"
00041 !!
00042 !! \subpage output_format_env_state "Environment State"
00043 !!
00044 !! \subpage output_format_gas_data "Gas Material Data"
00045 !!
00046 !! \subpage output_format_gas_state "Gas State"
00047 !!
00048 !! \subpage output_format_aero_data "Aerosol Material Data"
00049 !!
00050 !! \subpage output_format_aero_state "Aerosol Particle State"
00051 !! (only for particle-resolved simulations)
00052 !!
00053 !! \subpage output_format_aero_removed "Aerosol Particle Removal Information"
00054 !! (only for particle-resolved simulations, if \c record_removals is \c yes)
00055 !!
00056 !! \subpage output_format_aero_weight "Aerosol Weighting Function"
00057 !! (only for particle-resolved simulations)
00058 !!
00059 !! \subpage output_format_bin_grid "Bin Grid Data"
00060 !! (only for exact and sectional simulations)
00061 !!
00062 !! \subpage output_format_aero_binned "Aerosol Binned Sectional State"
00063 !! (only for exact and sectional simulations)
00064 
00065 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00066 
00067 !> Write data in NetCDF format.
00068 module pmc_output
00069 
00070   use pmc_bin_grid
00071   use pmc_aero_data
00072   use pmc_aero_state
00073   use pmc_aero_binned
00074   use pmc_netcdf
00075   use pmc_env_state
00076   use pmc_util
00077   use pmc_gas_data
00078   use pmc_mpi
00079 #ifdef PMC_USE_MPI
00080   use mpi
00081 #endif
00082 
00083   !> Type code for undefined or invalid output.
00084   integer, parameter :: OUTPUT_TYPE_INVALID = 0
00085   !> Type code for centralized output (one file per process, all written
00086   !> by process 0).
00087   integer, parameter :: OUTPUT_TYPE_CENTRAL = 1
00088   !> Type code for distributed output (one file per process, written by
00089   !> each process).
00090   integer, parameter :: OUTPUT_TYPE_DIST    = 2
00091   !> Type code for single output (one file for all processes, written by
00092   !> process 0).
00093   integer, parameter :: OUTPUT_TYPE_SINGLE  = 3
00094 
00095   !> Internal-use variable only.
00096   integer, parameter :: TAG_OUTPUT_STATE_CENTRAL = 4341
00097   !> Internal-use variable only.
00098   integer, parameter :: TAG_OUTPUT_STATE_SINGLE  = 4342
00099   
00100 contains
00101 
00102 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00103 
00104   !> Write the current state.
00105   subroutine output_state(prefix, output_type, bin_grid, aero_data, &
00106        aero_weight, aero_state, gas_data, gas_state, env_state, index, &
00107        time, del_t, i_repeat, record_removals, record_optical, uuid)
00108 
00109     !> Prefix of state file.
00110     character(len=*), intent(in) :: prefix
00111     !> Output type for parallel runs (see module constants).
00112     integer, intent(in) :: output_type
00113     !> Bin grid.
00114     type(bin_grid_t), intent(in) :: bin_grid
00115     !> Aerosol data.
00116     type(aero_data_t), intent(in) :: aero_data
00117     !> Aerosol weight.
00118     type(aero_weight_t), intent(in) :: aero_weight
00119     !> Aerosol state.
00120     type(aero_state_t), intent(in) :: aero_state
00121     !> Gas data.
00122     type(gas_data_t), intent(in) :: gas_data
00123     !> Gas state.
00124     type(gas_state_t), intent(in) :: gas_state
00125     !> Environment state.
00126     type(env_state_t), intent(in) :: env_state
00127     !> Filename index.
00128     integer, intent(in) :: index
00129     !> Current time (s).
00130     real(kind=dp), intent(in) :: time
00131     !> Current timestep (s).
00132     real(kind=dp), intent(in) :: del_t
00133     !> Current repeat number.
00134     integer, intent(in) :: i_repeat
00135     !> Whether to output particle removal info.
00136     logical, intent(in) :: record_removals
00137     !> Whether to output aerosol optical properties.
00138     logical, intent(in) :: record_optical
00139     !> UUID of the simulation.
00140     character(len=PMC_UUID_LEN), intent(in) :: uuid
00141     
00142     integer :: rank, n_proc
00143 #ifdef PMC_USE_MPI
00144     type(env_state_t) :: env_state_write
00145     type(gas_state_t) :: gas_state_write
00146     type(aero_state_t) :: aero_state_write
00147     integer :: ierr, status(MPI_STATUS_SIZE), i_proc, position
00148     character, allocatable :: buffer(:)
00149 #endif
00150 
00151     rank = pmc_mpi_rank()
00152     n_proc = pmc_mpi_size()
00153     if (output_type == OUTPUT_TYPE_CENTRAL) then
00154        ! write per-process data to separate files, but do it by
00155        ! transferring data to process 0 and having it do the writes
00156        if (rank == 0) then
00157           call output_state_to_file(prefix, bin_grid, aero_data, &
00158                aero_weight, aero_state, gas_data, gas_state, env_state, &
00159                index, time, del_t, i_repeat, record_removals, &
00160                record_optical, rank, n_proc, uuid)
00161 #ifdef PMC_USE_MPI
00162           do i_proc = 1,(n_proc - 1)
00163              call recv_output_state_central(prefix, bin_grid, &
00164                   aero_data, aero_weight, gas_data, index, time, del_t, &
00165                   i_repeat, record_removals, record_optical, uuid, i_proc)
00166           end do
00167 #endif
00168        else ! rank /= 0
00169           call send_output_state_central(aero_state, gas_state, env_state)
00170        end if
00171     elseif (output_type == OUTPUT_TYPE_DIST) then
00172        ! have each process write its own data directly
00173        call output_state_to_file(prefix, bin_grid, aero_data, &
00174             aero_weight, aero_state, gas_data, gas_state, env_state, &
00175             index, time, del_t, i_repeat, record_removals, record_optical, &
00176             rank, n_proc, uuid)
00177     elseif (output_type == OUTPUT_TYPE_SINGLE) then
00178        if (n_proc == 1) then
00179           call output_state_to_file(prefix, bin_grid, aero_data, &
00180                aero_weight, aero_state, gas_data, gas_state, &
00181                env_state, index, time, del_t, i_repeat, &
00182                record_removals, record_optical, rank, n_proc, uuid)
00183        else
00184 #ifdef PMC_USE_MPI
00185           ! collect all data onto process 0 and then write it to a
00186           ! single file
00187           call env_state_allocate(env_state_write)
00188           call gas_state_allocate(gas_state_write)
00189           call env_state_copy(env_state, env_state_write)
00190           call gas_state_copy(gas_state, gas_state_write)
00191           call env_state_reduce_avg(env_state_write)
00192           call gas_state_reduce_avg(gas_state_write)
00193           call aero_state_allocate(aero_state_write)
00194           call aero_state_mpi_gather(aero_state, aero_state_write)
00195           if (rank == 0) then
00196              call output_state_to_file(prefix, bin_grid, aero_data, &
00197                   aero_weight, aero_state_write, gas_data, gas_state_write, &
00198                   env_state_write, index, time, del_t, i_repeat, &
00199                   record_removals, record_optical, rank, 1, uuid)
00200           end if
00201           call aero_state_deallocate(aero_state_write)
00202           call env_state_deallocate(env_state_write)
00203           call gas_state_deallocate(gas_state_write)
00204 #endif
00205        end if
00206     else
00207        call die_msg(626743323, "Unknown output_type: " &
00208             // trim(integer_to_string(output_type)))
00209     end if
00210 
00211   end subroutine output_state
00212 
00213 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00214 
00215   !> Helper routine to write various global attributes. Do not call
00216   !> directly.
00217   subroutine write_header_and_time(ncid, time, del_t, index, uuid)
00218 
00219     !> NetCDF file ID, in data mode.
00220     integer, intent(in) :: ncid
00221     !> Current time (s).
00222     real(kind=dp), intent(in) :: time
00223     !> Current timestep (s).
00224     real(kind=dp), intent(in) :: del_t
00225     !> Filename index.
00226     integer, intent(in) :: index
00227     !> UUID of the simulation.
00228     character(len=PMC_UUID_LEN), intent(in) :: uuid
00229 
00230     character(len=500) :: history
00231 
00232     call pmc_nc_check(nf90_redef(ncid))
00233 
00234     call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "source", &
00235          "PartMC version 2.1.2"))
00236     call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "UUID", uuid))
00237     call iso8601_date_and_time(history)
00238     history((len_trim(history)+1):) = " created by PartMC"
00239     call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "history", history))
00240     call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "Conventions", &
00241          "CF-1.4"))
00242     
00243     call pmc_nc_check(nf90_enddef(ncid))
00244     
00245     call pmc_nc_write_real(ncid, time, "time", unit="s", &
00246          description="time elapsed since simulation start")
00247     call pmc_nc_write_real(ncid, del_t, "timestep", unit="s", &
00248          description="current timestep size")
00249     call pmc_nc_write_integer(ncid, index, "timestep_index", &
00250          description="an integer that is 1 on the first timestep, " &
00251          // "2 on the second timestep, etc.")
00252 
00253   end subroutine write_header_and_time
00254 
00255 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00256 
00257   !> Write the current state for a single process. Do not call this
00258   !> subroutine directly, but rather call output_state().
00259   subroutine output_state_to_file(prefix, bin_grid, aero_data, &
00260        aero_weight, aero_state, gas_data, gas_state, env_state, index, &
00261        time, del_t, i_repeat, record_removals, record_optical, write_rank, &
00262        write_n_proc, uuid)
00263 
00264     !> Prefix of state file.
00265     character(len=*), intent(in) :: prefix
00266     !> Bin grid.
00267     type(bin_grid_t), intent(in) :: bin_grid
00268     !> Aerosol data.
00269     type(aero_data_t), intent(in) :: aero_data
00270     !> Aerosol weight.
00271     type(aero_weight_t), intent(in) :: aero_weight
00272     !> Aerosol state.
00273     type(aero_state_t), intent(in) :: aero_state
00274     !> Gas data.
00275     type(gas_data_t), intent(in) :: gas_data
00276     !> Gas state.
00277     type(gas_state_t), intent(in) :: gas_state
00278     !> Environment state.
00279     type(env_state_t), intent(in) :: env_state
00280     !> Filename index.
00281     integer, intent(in) :: index
00282     !> Current time (s).
00283     real(kind=dp), intent(in) :: time
00284     !> Current timestep (s).
00285     real(kind=dp), intent(in) :: del_t
00286     !> Current repeat number.
00287     integer, intent(in) :: i_repeat
00288     !> Whether to output particle removal info.
00289     logical, intent(in) :: record_removals
00290     !> Whether to output aerosol optical properties.
00291     logical, intent(in) :: record_optical
00292     !> Rank to write into file.
00293     integer, intent(in) :: write_rank
00294     !> Number of processes to write into file.
00295     integer, intent(in) :: write_n_proc
00296     !> UUID of the simulation.
00297     character(len=PMC_UUID_LEN), intent(in) :: uuid
00298     
00299     character(len=len(prefix)+100) :: filename
00300     integer :: ncid
00301 
00302 #ifdef PMC_USE_MPI
00303     if (write_n_proc > 1) then
00304        write(filename, '(a,a,i4.4,a,i4.4,a,i8.8,a)') trim(prefix), &
00305             '_', i_repeat, '_', (write_rank + 1), '_', index, '.nc'
00306     else
00307        write(filename, '(a,a,i4.4,a,i8.8,a)') trim(prefix), &
00308             '_', i_repeat, '_', index, '.nc'
00309     end if
00310 #else
00311     write(filename, '(a,a,i4.4,a,i8.8,a)') trim(prefix), &
00312          '_', i_repeat, '_', index, '.nc'
00313 #endif
00314     call pmc_nc_check_msg(nf90_create(filename, NF90_CLOBBER, ncid), &
00315          "opening " // trim(filename))
00316     
00317     !> \page output_format_general Output File Format: General Information
00318     !!
00319     !! The general information global NetCDF attributes are:
00320     !!   - \b title: always set to the string "PartMC output file"
00321     !!   - \b source: set to the string "PartMC version V.V.V" where V.V.V
00322     !!     is the PartMC version that created the file
00323     !!   - \b UUID: a string of the form F47AC10B-58CC-4372-A567-0E02B2C3D479
00324     !!     which is the same for all files generated by a single call of
00325     !!     PartMC.
00326     !!   - \b Conventions: set to the string "CF-1.4", indicating
00327     !!     compliance with the <a
00328     !!     href="http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.4">CF
00329     !!     convention format</a>
00330     !!   - \b history: set to the string
00331     !!     "YYYY-MM-DDThh:mm:ss[+-]ZZ:zz created by PartMC" where the first
00332     !!     term is the file creation time in the
00333     !!     <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601
00334     !!     format</a>. For example, noon Pacific Standard Time (PST) on
00335     !!     February 1st, 2000 would be written 2000-02-01T12:00:00-08:00.
00336     !!     The date and time variables are:
00337     !!     - YYYY: four-digit year
00338     !!     - MM: two-digit month number
00339     !!     - DD: two-digit day within month
00340     !!     - T: literal "T" character
00341     !!     - hh: two-digit hour in 24-hour format
00342     !!     - mm: two-digit minute
00343     !!     - ss: two-digit second
00344     !!     - [+-]: a literal "+" or "-" character giving the time zone
00345     !!       offset sign
00346     !!     - ZZ: two-digit hours of the time zone offset from UTC
00347     !!     - zz: two-digit minutes of the time zone offset from UTC
00348     !!
00349     !! The general information NetCDF variables are:
00350     !!   - \b time (unit s): time elapsed since the simulation start time,
00351     !!     as specified in the \ref output_format_env_state section
00352     !!   - \b timestep (unit s): the current timestep size
00353     !!   - \b repeat: the repeat number of this simulation (starting from 1)
00354     !!   - \b timestep_index: an integer that is 1 on the first timestep, 2
00355     !!     on the second timestep, etc.
00356     !!   - \b process (MPI only): the process number (starting from 1)
00357     !!     that output this data file
00358     !!   - \b total_processes (MPI only): the total number of processes
00359     !!     involved in writing data (may be less than the total number of
00360     !!     processes that computed the data)
00361 
00362     call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "title", &
00363          "PartMC output file"))
00364     call pmc_nc_check(nf90_enddef(ncid))
00365 
00366     call write_header_and_time(ncid, time, del_t, index, uuid)
00367     call pmc_nc_write_integer(ncid, i_repeat, "repeat", &
00368          description="repeat repeat number of this simulation " &
00369          // "(starting from 1)")
00370 #ifdef PMC_USE_MPI
00371     call pmc_nc_write_integer(ncid, write_rank + 1, "process", &
00372          description="the process number (starting from 1) " &
00373          // "that output this data file")
00374     call pmc_nc_write_integer(ncid, write_n_proc, "total_processes", &
00375          description="total number of processes")
00376 #endif
00377 
00378     call env_state_output_netcdf(env_state, ncid)
00379     call gas_data_output_netcdf(gas_data, ncid)
00380     call gas_state_output_netcdf(gas_state, ncid, gas_data)
00381     call aero_data_output_netcdf(aero_data, ncid)
00382     call aero_weight_output_netcdf(aero_weight, ncid)
00383     call aero_state_output_netcdf(aero_state, ncid, bin_grid, &
00384          aero_data, aero_weight, record_removals, record_optical)
00385 
00386     call pmc_nc_check(nf90_close(ncid))
00387     
00388   end subroutine output_state_to_file
00389 
00390 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00391 
00392   !> Send the state for the "central" output method to the root process.
00393   subroutine send_output_state_central(aero_state, gas_state, env_state)
00394 
00395     !> Aerosol state.
00396     type(aero_state_t), intent(in) :: aero_state
00397     !> Gas state.
00398     type(gas_state_t), intent(in) :: gas_state
00399     !> Environment state.
00400     type(env_state_t), intent(in) :: env_state
00401 
00402 #ifdef PMC_USE_MPI
00403     integer :: buffer_size, max_buffer_size, position, ierr
00404     character, allocatable :: buffer(:)
00405 
00406     call assert(645797304, pmc_mpi_rank() /= 0)
00407 
00408     max_buffer_size = 0
00409     max_buffer_size = max_buffer_size &
00410          + pmc_mpi_pack_size_env_state(env_state)
00411     max_buffer_size = max_buffer_size &
00412          + pmc_mpi_pack_size_gas_state(gas_state)
00413     max_buffer_size = max_buffer_size &
00414          + pmc_mpi_pack_size_aero_state(aero_state)
00415     allocate(buffer(max_buffer_size))
00416     position = 0
00417     call pmc_mpi_pack_env_state(buffer, position, env_state)
00418     call pmc_mpi_pack_gas_state(buffer, position, gas_state)
00419     call pmc_mpi_pack_aero_state(buffer, position, aero_state)
00420     call assert(839343839, position <= max_buffer_size)
00421     buffer_size = position
00422     call mpi_send(buffer, buffer_size, MPI_CHARACTER, 0, &
00423          TAG_OUTPUT_STATE_CENTRAL, MPI_COMM_WORLD, ierr)
00424     call pmc_mpi_check_ierr(ierr)
00425     deallocate(buffer)
00426 #endif
00427 
00428   end subroutine send_output_state_central
00429 
00430 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00431 
00432   !> Receive the state for the "central" output method on the root
00433   !> process.
00434   subroutine recv_output_state_central(prefix, bin_grid, aero_data, &
00435        aero_weight, gas_data, index, time, del_t, i_repeat, &
00436        record_removals, record_optical, uuid, remote_proc)
00437 
00438     !> Prefix of state file.
00439     character(len=*), intent(in) :: prefix
00440     !> Bin grid.
00441     type(bin_grid_t), intent(in) :: bin_grid
00442     !> Aerosol data.
00443     type(aero_data_t), intent(in) :: aero_data
00444     !> Aerosol weight.
00445     type(aero_weight_t), intent(in) :: aero_weight
00446     !> Gas data.
00447     type(gas_data_t), intent(in) :: gas_data
00448     !> Filename index.
00449     integer, intent(in) :: index
00450     !> Current time (s).
00451     real(kind=dp), intent(in) :: time
00452     !> Current timestep (s).
00453     real(kind=dp), intent(in) :: del_t
00454     !> Current repeat number.
00455     integer, intent(in) :: i_repeat
00456     !> Whether to output particle removal info.
00457     logical, intent(in) :: record_removals
00458     !> Whether to output aerosol_optical_properties.
00459     logical, intent(in) :: record_optical
00460     !> UUID of the simulation.
00461     character(len=PMC_UUID_LEN), intent(in) :: uuid
00462     !> Process number to receive from.
00463     integer, intent(in) :: remote_proc
00464 
00465 #ifdef PMC_USE_MPI
00466     type(env_state_t) :: env_state
00467     type(gas_state_t) :: gas_state
00468     type(aero_state_t) :: aero_state
00469     integer :: buffer_size, position, status(MPI_STATUS_SIZE)
00470     integer :: n_proc, ierr
00471     character, allocatable :: buffer(:)
00472 
00473     call assert(206980035, pmc_mpi_rank() == 0)
00474     call assert(291452117, remote_proc /= 0)
00475     n_proc = pmc_mpi_size()
00476 
00477     ! get buffer size
00478     call mpi_probe(remote_proc, TAG_OUTPUT_STATE_CENTRAL, MPI_COMM_WORLD, &
00479          status, ierr)
00480     call pmc_mpi_check_ierr(ierr)
00481     call mpi_get_count(status, MPI_CHARACTER, buffer_size, ierr)
00482 
00483     ! get message
00484     allocate(buffer(buffer_size))
00485     call mpi_recv(buffer, buffer_size, MPI_CHARACTER, remote_proc, &
00486          TAG_OUTPUT_STATE_CENTRAL, MPI_COMM_WORLD, status, ierr)
00487     call pmc_mpi_check_ierr(ierr)
00488 
00489     ! unpack message
00490     position = 0
00491     call env_state_allocate(env_state)
00492     call gas_state_allocate(gas_state)
00493     call aero_state_allocate(aero_state)
00494     call pmc_mpi_unpack_env_state(buffer, position, env_state)
00495     call pmc_mpi_unpack_gas_state(buffer, position, gas_state)
00496     call pmc_mpi_unpack_aero_state(buffer, position, aero_state)
00497     call assert(279581330, position == buffer_size)
00498     deallocate(buffer)
00499     
00500     call output_state_to_file(prefix, bin_grid, aero_data, &
00501          aero_weight, aero_state, gas_data, gas_state, env_state, &
00502          index, time, del_t, i_repeat, record_removals, record_optical, &
00503          remote_proc, n_proc, uuid)
00504     
00505     call env_state_deallocate(env_state)
00506     call gas_state_deallocate(gas_state)
00507     call aero_state_deallocate(aero_state)
00508 #endif
00509     
00510   end subroutine recv_output_state_central
00511 
00512 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00513 
00514   !> Read the current state.
00515   subroutine input_state(filename, bin_grid, aero_data, &
00516        aero_weight, aero_state, gas_data, gas_state, env_state, index, &
00517        time, del_t, i_repeat, uuid)
00518 
00519     !> Prefix of state file.
00520     character(len=*), intent(in) :: filename
00521     !> Bin grid.
00522     type(bin_grid_t), intent(in) :: bin_grid
00523     !> Aerosol data.
00524     type(aero_data_t), intent(inout) :: aero_data
00525     !> Aerosol weight.
00526     type(aero_weight_t), intent(inout) :: aero_weight
00527     !> Aerosol state.
00528     type(aero_state_t), intent(inout) :: aero_state
00529     !> Gas data.
00530     type(gas_data_t), intent(inout) :: gas_data
00531     !> Gas state.
00532     type(gas_state_t), intent(inout) :: gas_state
00533     !> Environment state.
00534     type(env_state_t), intent(inout) :: env_state
00535     !> Filename index.
00536     integer, intent(out) :: index
00537     !> Current time (s).
00538     real(kind=dp), intent(out) :: time
00539     !> Current timestep (s).
00540     real(kind=dp), intent(out) :: del_t
00541     !> Current repeat number.
00542     integer, intent(out) :: i_repeat
00543     !> UUID of the simulation.
00544     character(len=PMC_UUID_LEN), intent(out) :: uuid
00545     
00546     integer :: ncid
00547 
00548     ! only root process actually reads from the file
00549     if (pmc_mpi_rank() == 0) then
00550        call pmc_nc_open_read(filename, ncid)
00551 
00552        call pmc_nc_check(nf90_get_att(ncid, NF90_GLOBAL, "UUID", uuid))
00553 
00554        call pmc_nc_read_real(ncid, time, "time")
00555        call pmc_nc_read_real(ncid, del_t, "timestep")
00556        call pmc_nc_read_integer(ncid, i_repeat, "repeat")
00557        call pmc_nc_read_integer(ncid, index, "timestep_index")
00558 
00559        call env_state_input_netcdf(env_state, ncid)
00560        call gas_data_input_netcdf(gas_data, ncid)
00561        call gas_state_input_netcdf(gas_state, ncid, gas_data)
00562        call aero_data_input_netcdf(aero_data, ncid)
00563        call aero_weight_input_netcdf(aero_weight, ncid)
00564        call aero_state_input_netcdf(aero_state, ncid, bin_grid, &
00565             aero_data, aero_weight)
00566 
00567        call pmc_nc_close(ncid)
00568     end if
00569     
00570   end subroutine input_state
00571   
00572 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00573 
00574   !> Write the current sectional data.
00575   subroutine output_sectional(prefix, bin_grid, aero_data, aero_binned, &
00576        gas_data, gas_state, env_state, index, time, del_t, uuid)
00577     
00578     !> Prefix of filename to write
00579     character(len=*), intent(in) :: prefix
00580     !> Bin grid.
00581     type(bin_grid_t), intent(in) :: bin_grid
00582     !> Aerosol data.
00583     type(aero_data_t), intent(in) :: aero_data
00584     !> Binned aerosol data.
00585     type(aero_binned_t), intent(in) :: aero_binned
00586     !> Gas data.
00587     type(gas_data_t), intent(in) :: gas_data
00588     !> Gas state.
00589     type(gas_state_t), intent(in) :: gas_state
00590     !> Environment state.
00591     type(env_state_t), intent(in) :: env_state
00592     !> Filename index.
00593     integer, intent(in) :: index
00594     !> Current time (s).
00595     real(kind=dp), intent(in) :: time
00596     !> Current output time-step (s).
00597     real(kind=dp), intent(in) :: del_t
00598     !> UUID of the simulation.
00599     character(len=PMC_UUID_LEN), intent(in) :: uuid
00600 
00601     integer :: ncid
00602     character(len=len(prefix)+100) :: filename
00603 
00604     write(filename, '(a,a,i8.8,a)') trim(prefix), &
00605          '_', index, '.nc'
00606     call pmc_nc_check_msg(nf90_create(filename, NF90_CLOBBER, ncid), &
00607          "opening " // trim(filename))
00608 
00609     ! write header attributes
00610     call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "title", &
00611          "PartMC sectional output file"))
00612     call pmc_nc_check(nf90_enddef(ncid))
00613 
00614     call write_header_and_time(ncid, time, del_t, index, uuid)
00615 
00616     ! write data
00617     call env_state_output_netcdf(env_state, ncid)
00618     call gas_data_output_netcdf(gas_data, ncid)
00619     call gas_state_output_netcdf(gas_state, ncid, gas_data)
00620     call aero_data_output_netcdf(aero_data, ncid)
00621     call aero_binned_output_netcdf(aero_binned, ncid, bin_grid, &
00622          aero_data)
00623 
00624     call pmc_nc_check(nf90_close(ncid))
00625 
00626   end subroutine output_sectional
00627   
00628 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00629 
00630   !> Read the specification for an output type from a spec file and
00631   !> generate it.
00632   subroutine spec_file_read_output_type(file, output_type)
00633     
00634     !> Spec file.
00635     type(spec_file_t), intent(inout) :: file
00636     !> Kernel type.
00637     integer, intent(out) :: output_type
00638     
00639     character(len=SPEC_LINE_MAX_VAR_LEN) :: output_type_name
00640     
00641     !> \page input_format_output Input File Format: Output Type
00642     !!
00643     !! The output type is specified by the parameter:
00644     !!   - \b output_type (string): type of disk output --- must be
00645     !!     one of: \c central to write one file per process, but all
00646     !!     written by process 0; \c dist for every process to
00647     !!     write its own state file; or \c single to transfer all data
00648     !!     to process 0 and write a single unified output file
00649     !!
00650     !! See also:
00651     !!   - \ref spec_file_format --- the input file text format
00652 
00653     call spec_file_read_string(file, 'output_type', output_type_name)
00654     if (trim(output_type_name) == 'central') then
00655        output_type = OUTPUT_TYPE_CENTRAL
00656     elseif (trim(output_type_name) == 'dist') then
00657        output_type = OUTPUT_TYPE_DIST
00658     elseif (trim(output_type_name) == 'single') then
00659        output_type = OUTPUT_TYPE_SINGLE
00660     else
00661        call spec_file_die_msg(494684716, file, &
00662             "Unknown output type: " // trim(output_type_name))
00663     end if
00664 
00665   end subroutine spec_file_read_output_type
00666 
00667 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00668   
00669 end module pmc_output