PartMC
2.2.0
|
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_array "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, aero_data, aero_state, & 00106 gas_data, gas_state, env_state, index, time, del_t, i_repeat, & 00107 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 !> Aerosol data. 00114 type(aero_data_t), intent(in) :: aero_data 00115 !> Aerosol state. 00116 type(aero_state_t), intent(in) :: aero_state 00117 !> Gas data. 00118 type(gas_data_t), intent(in) :: gas_data 00119 !> Gas state. 00120 type(gas_state_t), intent(in) :: gas_state 00121 !> Environment state. 00122 type(env_state_t), intent(in) :: env_state 00123 !> Filename index. 00124 integer, intent(in) :: index 00125 !> Current time (s). 00126 real(kind=dp), intent(in) :: time 00127 !> Current timestep (s). 00128 real(kind=dp), intent(in) :: del_t 00129 !> Current repeat number. 00130 integer, intent(in) :: i_repeat 00131 !> Whether to output particle removal info. 00132 logical, intent(in) :: record_removals 00133 !> Whether to output aerosol optical properties. 00134 logical, intent(in) :: record_optical 00135 !> UUID of the simulation. 00136 character(len=PMC_UUID_LEN), intent(in) :: uuid 00137 00138 integer :: rank, n_proc 00139 #ifdef PMC_USE_MPI 00140 type(env_state_t) :: env_state_write 00141 type(gas_state_t) :: gas_state_write 00142 type(aero_state_t) :: aero_state_write 00143 integer :: ierr, status(MPI_STATUS_SIZE), i_proc, position 00144 character, allocatable :: buffer(:) 00145 #endif 00146 00147 rank = pmc_mpi_rank() 00148 n_proc = pmc_mpi_size() 00149 if (output_type == OUTPUT_TYPE_CENTRAL) then 00150 ! write per-process data to separate files, but do it by 00151 ! transferring data to process 0 and having it do the writes 00152 if (rank == 0) then 00153 call output_state_to_file(prefix, aero_data, aero_state, gas_data, & 00154 gas_state, env_state, index, time, del_t, i_repeat, & 00155 record_removals, record_optical, rank, n_proc, uuid) 00156 #ifdef PMC_USE_MPI 00157 do i_proc = 1,(n_proc - 1) 00158 call recv_output_state_central(prefix, aero_data, gas_data, & 00159 index, time, del_t, i_repeat, record_removals, & 00160 record_optical, uuid, i_proc) 00161 end do 00162 #endif 00163 else ! rank /= 0 00164 call send_output_state_central(aero_state, gas_state, env_state) 00165 end if 00166 elseif (output_type == OUTPUT_TYPE_DIST) then 00167 ! have each process write its own data directly 00168 call output_state_to_file(prefix, aero_data, aero_state, gas_data, & 00169 gas_state, env_state, index, time, del_t, i_repeat, & 00170 record_removals, record_optical, rank, n_proc, uuid) 00171 elseif (output_type == OUTPUT_TYPE_SINGLE) then 00172 if (n_proc == 1) then 00173 call output_state_to_file(prefix, aero_data, aero_state, gas_data, & 00174 gas_state, env_state, index, time, del_t, i_repeat, & 00175 record_removals, record_optical, rank, n_proc, uuid) 00176 else 00177 #ifdef PMC_USE_MPI 00178 ! collect all data onto process 0 and then write it to a 00179 ! single file 00180 call env_state_allocate(env_state_write) 00181 call gas_state_allocate(gas_state_write) 00182 call env_state_copy(env_state, env_state_write) 00183 call gas_state_copy(gas_state, gas_state_write) 00184 call env_state_reduce_avg(env_state_write) 00185 call gas_state_reduce_avg(gas_state_write) 00186 call aero_state_allocate(aero_state_write) 00187 call aero_state_mpi_gather(aero_state, aero_state_write) 00188 if (rank == 0) then 00189 call output_state_to_file(prefix, aero_data, aero_state_write, & 00190 gas_data, gas_state_write, env_state_write, index, time, & 00191 del_t, i_repeat, record_removals, record_optical, rank, 1, & 00192 uuid) 00193 end if 00194 call aero_state_deallocate(aero_state_write) 00195 call env_state_deallocate(env_state_write) 00196 call gas_state_deallocate(gas_state_write) 00197 #endif 00198 end if 00199 else 00200 call die_msg(626743323, "Unknown output_type: " & 00201 // trim(integer_to_string(output_type))) 00202 end if 00203 00204 end subroutine output_state 00205 00206 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00207 00208 !> Helper routine to write various global attributes. Do not call 00209 !> directly. 00210 subroutine write_header_and_time(ncid, time, del_t, index, uuid) 00211 00212 !> NetCDF file ID, in data mode. 00213 integer, intent(in) :: ncid 00214 !> Current time (s). 00215 real(kind=dp), intent(in) :: time 00216 !> Current timestep (s). 00217 real(kind=dp), intent(in) :: del_t 00218 !> Filename index. 00219 integer, intent(in) :: index 00220 !> UUID of the simulation. 00221 character(len=PMC_UUID_LEN), intent(in) :: uuid 00222 00223 character(len=500) :: history 00224 00225 call pmc_nc_check(nf90_redef(ncid)) 00226 00227 call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "source", & 00228 "PartMC version 2.2.0")) 00229 call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "UUID", uuid)) 00230 call iso8601_date_and_time(history) 00231 history((len_trim(history)+1):) = " created by PartMC" 00232 call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "history", history)) 00233 call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "Conventions", & 00234 "CF-1.4")) 00235 00236 call pmc_nc_check(nf90_enddef(ncid)) 00237 00238 call pmc_nc_write_real(ncid, time, "time", unit="s", & 00239 description="time elapsed since simulation start") 00240 call pmc_nc_write_real(ncid, del_t, "timestep", unit="s", & 00241 description="current timestep size") 00242 call pmc_nc_write_integer(ncid, index, "timestep_index", & 00243 description="an integer that is 1 on the first timestep, " & 00244 // "2 on the second timestep, etc.") 00245 00246 end subroutine write_header_and_time 00247 00248 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00249 00250 !> Write the current state for a single process. Do not call this 00251 !> subroutine directly, but rather call output_state(). 00252 subroutine output_state_to_file(prefix, aero_data, aero_state, gas_data, & 00253 gas_state, env_state, index, time, del_t, i_repeat, record_removals, & 00254 record_optical, write_rank, write_n_proc, uuid) 00255 00256 !> Prefix of state file. 00257 character(len=*), intent(in) :: prefix 00258 !> Aerosol data. 00259 type(aero_data_t), intent(in) :: aero_data 00260 !> Aerosol state. 00261 type(aero_state_t), intent(in) :: aero_state 00262 !> Gas data. 00263 type(gas_data_t), intent(in) :: gas_data 00264 !> Gas state. 00265 type(gas_state_t), intent(in) :: gas_state 00266 !> Environment state. 00267 type(env_state_t), intent(in) :: env_state 00268 !> Filename index. 00269 integer, intent(in) :: index 00270 !> Current time (s). 00271 real(kind=dp), intent(in) :: time 00272 !> Current timestep (s). 00273 real(kind=dp), intent(in) :: del_t 00274 !> Current repeat number. 00275 integer, intent(in) :: i_repeat 00276 !> Whether to output particle removal info. 00277 logical, intent(in) :: record_removals 00278 !> Whether to output aerosol optical properties. 00279 logical, intent(in) :: record_optical 00280 !> Rank to write into file. 00281 integer, intent(in) :: write_rank 00282 !> Number of processes to write into file. 00283 integer, intent(in) :: write_n_proc 00284 !> UUID of the simulation. 00285 character(len=PMC_UUID_LEN), intent(in) :: uuid 00286 00287 character(len=len(prefix)+100) :: filename 00288 integer :: ncid 00289 00290 #ifdef PMC_USE_MPI 00291 if (write_n_proc > 1) then 00292 write(filename, '(a,a,i4.4,a,i4.4,a,i8.8,a)') trim(prefix), & 00293 '_', i_repeat, '_', (write_rank + 1), '_', index, '.nc' 00294 else 00295 write(filename, '(a,a,i4.4,a,i8.8,a)') trim(prefix), & 00296 '_', i_repeat, '_', index, '.nc' 00297 end if 00298 #else 00299 write(filename, '(a,a,i4.4,a,i8.8,a)') trim(prefix), & 00300 '_', i_repeat, '_', index, '.nc' 00301 #endif 00302 call pmc_nc_check_msg(nf90_create(filename, NF90_CLOBBER, ncid), & 00303 "opening " // trim(filename)) 00304 00305 !> \page output_format_general Output File Format: General Information 00306 !! 00307 !! The general information global NetCDF attributes are: 00308 !! - \b title: always set to the string "PartMC output file" 00309 !! - \b source: set to the string "PartMC version V.V.V" where V.V.V 00310 !! is the PartMC version that created the file 00311 !! - \b UUID: a string of the form F47AC10B-58CC-4372-A567-0E02B2C3D479 00312 !! which is the same for all files generated by a single call of 00313 !! PartMC. 00314 !! - \b Conventions: set to the string "CF-1.4", indicating 00315 !! compliance with the <a 00316 !! href="http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.4">CF 00317 !! convention format</a> 00318 !! - \b history: set to the string 00319 !! "YYYY-MM-DDThh:mm:ss[+-]ZZ:zz created by PartMC" where the first 00320 !! term is the file creation time in the 00321 !! <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601 00322 !! format</a>. For example, noon Pacific Standard Time (PST) on 00323 !! February 1st, 2000 would be written 2000-02-01T12:00:00-08:00. 00324 !! The date and time variables are: 00325 !! - YYYY: four-digit year 00326 !! - MM: two-digit month number 00327 !! - DD: two-digit day within month 00328 !! - T: literal "T" character 00329 !! - hh: two-digit hour in 24-hour format 00330 !! - mm: two-digit minute 00331 !! - ss: two-digit second 00332 !! - [+-]: a literal "+" or "-" character giving the time zone 00333 !! offset sign 00334 !! - ZZ: two-digit hours of the time zone offset from UTC 00335 !! - zz: two-digit minutes of the time zone offset from UTC 00336 !! 00337 !! The general information NetCDF variables are: 00338 !! - \b time (unit s): time elapsed since the simulation start time, 00339 !! as specified in the \ref output_format_env_state section 00340 !! - \b timestep (unit s): the current timestep size 00341 !! - \b repeat: the repeat number of this simulation (starting from 1) 00342 !! - \b timestep_index: an integer that is 1 on the first timestep, 2 00343 !! on the second timestep, etc. 00344 !! - \b process (MPI only): the process number (starting from 1) 00345 !! that output this data file 00346 !! - \b total_processes (MPI only): the total number of processes 00347 !! involved in writing data (may be less than the total number of 00348 !! processes that computed the data) 00349 00350 call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "title", & 00351 "PartMC output file")) 00352 call pmc_nc_check(nf90_enddef(ncid)) 00353 00354 call write_header_and_time(ncid, time, del_t, index, uuid) 00355 call pmc_nc_write_integer(ncid, i_repeat, "repeat", & 00356 description="repeat repeat number of this simulation " & 00357 // "(starting from 1)") 00358 #ifdef PMC_USE_MPI 00359 call pmc_nc_write_integer(ncid, write_rank + 1, "process", & 00360 description="the process number (starting from 1) " & 00361 // "that output this data file") 00362 call pmc_nc_write_integer(ncid, write_n_proc, "total_processes", & 00363 description="total number of processes") 00364 #endif 00365 00366 call env_state_output_netcdf(env_state, ncid) 00367 call gas_data_output_netcdf(gas_data, ncid) 00368 call gas_state_output_netcdf(gas_state, ncid, gas_data) 00369 call aero_data_output_netcdf(aero_data, ncid) 00370 call aero_state_output_netcdf(aero_state, ncid, aero_data, & 00371 record_removals, record_optical) 00372 00373 call pmc_nc_check(nf90_close(ncid)) 00374 00375 end subroutine output_state_to_file 00376 00377 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00378 00379 !> Send the state for the "central" output method to the root process. 00380 subroutine send_output_state_central(aero_state, gas_state, env_state) 00381 00382 !> Aerosol state. 00383 type(aero_state_t), intent(in) :: aero_state 00384 !> Gas state. 00385 type(gas_state_t), intent(in) :: gas_state 00386 !> Environment state. 00387 type(env_state_t), intent(in) :: env_state 00388 00389 #ifdef PMC_USE_MPI 00390 integer :: buffer_size, max_buffer_size, position, ierr 00391 character, allocatable :: buffer(:) 00392 00393 call assert(645797304, pmc_mpi_rank() /= 0) 00394 00395 max_buffer_size = 0 00396 max_buffer_size = max_buffer_size & 00397 + pmc_mpi_pack_size_env_state(env_state) 00398 max_buffer_size = max_buffer_size & 00399 + pmc_mpi_pack_size_gas_state(gas_state) 00400 max_buffer_size = max_buffer_size & 00401 + pmc_mpi_pack_size_aero_state(aero_state) 00402 allocate(buffer(max_buffer_size)) 00403 position = 0 00404 call pmc_mpi_pack_env_state(buffer, position, env_state) 00405 call pmc_mpi_pack_gas_state(buffer, position, gas_state) 00406 call pmc_mpi_pack_aero_state(buffer, position, aero_state) 00407 call assert(839343839, position <= max_buffer_size) 00408 buffer_size = position 00409 call mpi_send(buffer, buffer_size, MPI_CHARACTER, 0, & 00410 TAG_OUTPUT_STATE_CENTRAL, MPI_COMM_WORLD, ierr) 00411 call pmc_mpi_check_ierr(ierr) 00412 deallocate(buffer) 00413 #endif 00414 00415 end subroutine send_output_state_central 00416 00417 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00418 00419 !> Receive the state for the "central" output method on the root 00420 !> process. 00421 subroutine recv_output_state_central(prefix, aero_data, gas_data, index, & 00422 time, del_t, i_repeat, record_removals, record_optical, uuid, & 00423 remote_proc) 00424 00425 !> Prefix of state file. 00426 character(len=*), intent(in) :: prefix 00427 !> Aerosol data. 00428 type(aero_data_t), intent(in) :: aero_data 00429 !> Gas data. 00430 type(gas_data_t), intent(in) :: gas_data 00431 !> Filename index. 00432 integer, intent(in) :: index 00433 !> Current time (s). 00434 real(kind=dp), intent(in) :: time 00435 !> Current timestep (s). 00436 real(kind=dp), intent(in) :: del_t 00437 !> Current repeat number. 00438 integer, intent(in) :: i_repeat 00439 !> Whether to output particle removal info. 00440 logical, intent(in) :: record_removals 00441 !> Whether to output aerosol_optical_properties. 00442 logical, intent(in) :: record_optical 00443 !> UUID of the simulation. 00444 character(len=PMC_UUID_LEN), intent(in) :: uuid 00445 !> Process number to receive from. 00446 integer, intent(in) :: remote_proc 00447 00448 #ifdef PMC_USE_MPI 00449 type(env_state_t) :: env_state 00450 type(gas_state_t) :: gas_state 00451 type(aero_state_t) :: aero_state 00452 integer :: buffer_size, position, status(MPI_STATUS_SIZE) 00453 integer :: n_proc, ierr 00454 character, allocatable :: buffer(:) 00455 00456 call assert(206980035, pmc_mpi_rank() == 0) 00457 call assert(291452117, remote_proc /= 0) 00458 n_proc = pmc_mpi_size() 00459 00460 ! get buffer size 00461 call mpi_probe(remote_proc, TAG_OUTPUT_STATE_CENTRAL, MPI_COMM_WORLD, & 00462 status, ierr) 00463 call pmc_mpi_check_ierr(ierr) 00464 call mpi_get_count(status, MPI_CHARACTER, buffer_size, ierr) 00465 00466 ! get message 00467 allocate(buffer(buffer_size)) 00468 call mpi_recv(buffer, buffer_size, MPI_CHARACTER, remote_proc, & 00469 TAG_OUTPUT_STATE_CENTRAL, MPI_COMM_WORLD, status, ierr) 00470 call pmc_mpi_check_ierr(ierr) 00471 00472 ! unpack message 00473 position = 0 00474 call env_state_allocate(env_state) 00475 call gas_state_allocate(gas_state) 00476 call aero_state_allocate(aero_state) 00477 call pmc_mpi_unpack_env_state(buffer, position, env_state) 00478 call pmc_mpi_unpack_gas_state(buffer, position, gas_state) 00479 call pmc_mpi_unpack_aero_state(buffer, position, aero_state) 00480 call assert(279581330, position == buffer_size) 00481 deallocate(buffer) 00482 00483 call output_state_to_file(prefix, aero_data, aero_state, gas_data, & 00484 gas_state, env_state, index, time, del_t, i_repeat, & 00485 record_removals, record_optical, remote_proc, n_proc, uuid) 00486 00487 call env_state_deallocate(env_state) 00488 call gas_state_deallocate(gas_state) 00489 call aero_state_deallocate(aero_state) 00490 #endif 00491 00492 end subroutine recv_output_state_central 00493 00494 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00495 00496 !> Read the current state. 00497 subroutine input_state(filename, index, time, del_t, i_repeat, uuid, & 00498 aero_data, aero_state, gas_data, gas_state, env_state) 00499 00500 !> Prefix of state file. 00501 character(len=*), intent(in) :: filename 00502 !> Filename index. 00503 integer, intent(out) :: index 00504 !> Current time (s). 00505 real(kind=dp), intent(out) :: time 00506 !> Current timestep (s). 00507 real(kind=dp), intent(out) :: del_t 00508 !> Current repeat number. 00509 integer, intent(out) :: i_repeat 00510 !> UUID of the simulation. 00511 character(len=PMC_UUID_LEN), intent(out) :: uuid 00512 !> Aerosol data. 00513 type(aero_data_t), optional, intent(inout) :: aero_data 00514 !> Aerosol state. 00515 type(aero_state_t), optional, intent(inout) :: aero_state 00516 !> Gas data. 00517 type(gas_data_t), optional, intent(inout) :: gas_data 00518 !> Gas state. 00519 type(gas_state_t), optional, intent(inout) :: gas_state 00520 !> Environment state. 00521 type(env_state_t), optional, intent(inout) :: env_state 00522 00523 integer :: ncid 00524 00525 call assert_msg(819739354, pmc_mpi_rank() == 0, & 00526 "can only call from process 0") 00527 00528 call pmc_nc_open_read(filename, ncid) 00529 00530 call pmc_nc_check(nf90_get_att(ncid, NF90_GLOBAL, "UUID", uuid)) 00531 00532 call pmc_nc_read_real(ncid, time, "time") 00533 call pmc_nc_read_real(ncid, del_t, "timestep") 00534 call pmc_nc_read_integer(ncid, i_repeat, "repeat") 00535 call pmc_nc_read_integer(ncid, index, "timestep_index") 00536 00537 if (present(aero_data)) then 00538 call aero_data_input_netcdf(aero_data, ncid) 00539 if (present(aero_state)) then 00540 call aero_state_input_netcdf(aero_state, ncid, aero_data) 00541 end if 00542 else 00543 call assert_msg(289621231, present(aero_state) .eqv. .false., & 00544 "cannot input aero_state without aero_data") 00545 end if 00546 00547 if (present(gas_data)) then 00548 call gas_data_input_netcdf(gas_data, ncid) 00549 if (present(gas_state)) then 00550 call gas_state_input_netcdf(gas_state, ncid, gas_data) 00551 end if 00552 else 00553 call assert_msg(874298496, present(gas_state) .eqv. .false., & 00554 "cannot input gas_state without gas_data") 00555 end if 00556 00557 if (present(env_state)) then 00558 call env_state_input_netcdf(env_state, ncid) 00559 end if 00560 00561 call pmc_nc_close(ncid) 00562 00563 end subroutine input_state 00564 00565 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00566 00567 !> Find all NetCDF (.nc) filenames that match the given prefix. 00568 subroutine input_filename_list(prefix, filename_list) 00569 00570 !> Filename prefix to search for. 00571 character(len=*), intent(in) :: prefix 00572 !> Filename list. 00573 character(len=*), intent(inout), allocatable :: filename_list(:) 00574 00575 integer :: n_file, index, unit, ios 00576 character(len=len(prefix)+100) :: filename 00577 logical :: done 00578 00579 call assert_msg(277193351, pmc_mpi_rank() == 0, & 00580 "can only call from process 0") 00581 00582 index = 1 00583 done = .false. 00584 unit = get_unit() 00585 do while (.not. done) 00586 write(filename, '(a,a,i8.8,a)') trim(prefix), '_', index, '.nc' 00587 open(unit=unit, file=filename, status='old', iostat=ios) 00588 if (ios /= 0) then 00589 done = .true. 00590 else 00591 index = index + 1 00592 close(unit) 00593 end if 00594 end do 00595 call free_unit(unit) 00596 00597 n_file = index - 1 00598 if (size(filename_list) /= n_file) then 00599 deallocate(filename_list) 00600 allocate(filename_list(n_file)) 00601 end if 00602 00603 do index = 1,n_file 00604 write(filename, '(a,a,i8.8,a)') trim(prefix), '_', index, '.nc' 00605 filename_list(index) = filename 00606 end do 00607 00608 end subroutine input_filename_list 00609 00610 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00611 00612 !> Write the current sectional data. 00613 subroutine output_sectional(prefix, bin_grid, aero_data, aero_binned, & 00614 gas_data, gas_state, env_state, index, time, del_t, uuid) 00615 00616 !> Prefix of filename to write 00617 character(len=*), intent(in) :: prefix 00618 !> Bin grid. 00619 type(bin_grid_t), intent(in) :: bin_grid 00620 !> Aerosol data. 00621 type(aero_data_t), intent(in) :: aero_data 00622 !> Binned aerosol data. 00623 type(aero_binned_t), intent(in) :: aero_binned 00624 !> Gas data. 00625 type(gas_data_t), intent(in) :: gas_data 00626 !> Gas state. 00627 type(gas_state_t), intent(in) :: gas_state 00628 !> Environment state. 00629 type(env_state_t), intent(in) :: env_state 00630 !> Filename index. 00631 integer, intent(in) :: index 00632 !> Current time (s). 00633 real(kind=dp), intent(in) :: time 00634 !> Current output time-step (s). 00635 real(kind=dp), intent(in) :: del_t 00636 !> UUID of the simulation. 00637 character(len=PMC_UUID_LEN), intent(in) :: uuid 00638 00639 integer :: ncid 00640 character(len=len(prefix)+100) :: filename 00641 00642 write(filename, '(a,a,i8.8,a)') trim(prefix), & 00643 '_', index, '.nc' 00644 call pmc_nc_check_msg(nf90_create(filename, NF90_CLOBBER, ncid), & 00645 "opening " // trim(filename)) 00646 00647 ! write header attributes 00648 call pmc_nc_check(nf90_put_att(ncid, NF90_GLOBAL, "title", & 00649 "PartMC sectional output file")) 00650 call pmc_nc_check(nf90_enddef(ncid)) 00651 00652 call write_header_and_time(ncid, time, del_t, index, uuid) 00653 00654 ! write data 00655 call env_state_output_netcdf(env_state, ncid) 00656 call gas_data_output_netcdf(gas_data, ncid) 00657 call gas_state_output_netcdf(gas_state, ncid, gas_data) 00658 call aero_data_output_netcdf(aero_data, ncid) 00659 call aero_binned_output_netcdf(aero_binned, ncid, bin_grid, & 00660 aero_data) 00661 00662 call pmc_nc_check(nf90_close(ncid)) 00663 00664 end subroutine output_sectional 00665 00666 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00667 00668 !> Input sectional data. 00669 subroutine input_sectional(filename, index, time, del_t, uuid, bin_grid, & 00670 aero_data, aero_binned, gas_data, gas_state, env_state) 00671 00672 !> Filename to read. 00673 character(len=*), intent(in) :: filename 00674 !> Filename index. 00675 integer, intent(out) :: index 00676 !> Current time (s). 00677 real(kind=dp), intent(out) :: time 00678 !> Current output time-step (s). 00679 real(kind=dp), intent(out) :: del_t 00680 !> UUID of the simulation. 00681 character(len=PMC_UUID_LEN), intent(out) :: uuid 00682 !> Bin grid. 00683 type(bin_grid_t), optional, intent(inout) :: bin_grid 00684 !> Aerosol data. 00685 type(aero_data_t), optional, intent(inout) :: aero_data 00686 !> Binned aerosol data. 00687 type(aero_binned_t), optional, intent(inout) :: aero_binned 00688 !> Gas data. 00689 type(gas_data_t), optional, intent(inout) :: gas_data 00690 !> Gas state. 00691 type(gas_state_t), optional, intent(inout) :: gas_state 00692 !> Environment state. 00693 type(env_state_t), optional, intent(inout) :: env_state 00694 00695 integer :: ncid 00696 00697 call assert_msg(559676785, pmc_mpi_rank() == 0, & 00698 "can only call from process 0") 00699 00700 call pmc_nc_open_read(filename, ncid) 00701 00702 call pmc_nc_check(nf90_get_att(ncid, NF90_GLOBAL, "UUID", uuid)) 00703 00704 call pmc_nc_read_real(ncid, time, "time") 00705 call pmc_nc_read_real(ncid, del_t, "timestep") 00706 call pmc_nc_read_integer(ncid, index, "timestep_index") 00707 00708 if (present(bin_grid)) then 00709 call bin_grid_input_netcdf(bin_grid, ncid) 00710 end if 00711 if (present(aero_data)) then 00712 call aero_data_input_netcdf(aero_data, ncid) 00713 end if 00714 if (present(aero_binned)) then 00715 call assert_msg(585353528, & 00716 present(bin_grid) .and. present(aero_data), & 00717 "cannot input aero_binned without bin_grid and aero_data") 00718 call aero_binned_input_netcdf(aero_binned, ncid, bin_grid, & 00719 aero_data) 00720 end if 00721 00722 if (present(gas_data)) then 00723 call gas_data_input_netcdf(gas_data, ncid) 00724 if (present(gas_state)) then 00725 call gas_state_input_netcdf(gas_state, ncid, gas_data) 00726 end if 00727 else 00728 call assert_msg(214545112, present(gas_state) .eqv. .false., & 00729 "cannot input gas_state without gas_data") 00730 end if 00731 00732 if (present(env_state)) then 00733 call env_state_input_netcdf(env_state, ncid) 00734 end if 00735 00736 call pmc_nc_close(ncid) 00737 00738 end subroutine input_sectional 00739 00740 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00741 00742 !> Read the specification for an output type from a spec file and 00743 !> generate it. 00744 subroutine spec_file_read_output_type(file, output_type) 00745 00746 !> Spec file. 00747 type(spec_file_t), intent(inout) :: file 00748 !> Kernel type. 00749 integer, intent(out) :: output_type 00750 00751 character(len=SPEC_LINE_MAX_VAR_LEN) :: output_type_name 00752 00753 !> \page input_format_output Input File Format: Output Type 00754 !! 00755 !! The output type is specified by the parameter: 00756 !! - \b output_type (string): type of disk output --- must be 00757 !! one of: \c central to write one file per process, but all 00758 !! written by process 0; \c dist for every process to 00759 !! write its own state file; or \c single to transfer all data 00760 !! to process 0 and write a single unified output file 00761 !! 00762 !! See also: 00763 !! - \ref spec_file_format --- the input file text format 00764 00765 call spec_file_read_string(file, 'output_type', output_type_name) 00766 if (trim(output_type_name) == 'central') then 00767 output_type = OUTPUT_TYPE_CENTRAL 00768 elseif (trim(output_type_name) == 'dist') then 00769 output_type = OUTPUT_TYPE_DIST 00770 elseif (trim(output_type_name) == 'single') then 00771 output_type = OUTPUT_TYPE_SINGLE 00772 else 00773 call spec_file_die_msg(392313600, file, & 00774 "Unknown output type: " // trim(output_type_name)) 00775 end if 00776 00777 end subroutine spec_file_read_output_type 00778 00779 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00780 00781 end module pmc_output