Changeset 4597 for palm/trunk/SOURCE/data_output_netcdf4_module.f90
- Timestamp:
- Jul 9, 2020 7:21:53 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
palm/trunk/SOURCE/data_output_netcdf4_module.f90
r4579 r4597 24 24 ! ----------------- 25 25 ! $Id$ 26 ! bugfix: - allow writing of unlimited dimensions in parallel mode 27 ! - prevent unused-variable warning if preprocessor directives are not given 28 ! change: - set parallel access mode to independent per default 29 ! new : - dimension variables can be written by every PE 30 ! 31 ! 4579 2020-06-25 20:05:07Z gronemeier 26 32 ! corrected formatting to follow PALM coding standard 27 33 ! … … 53 59 !> NetCDF output module to write data to NetCDF files. 54 60 !> This is either done in parallel mode via parallel NetCDF4 I/O or in serial mode only by PE0. 61 !> 62 !> @bug 'mode' is not always checked. If a routine is called with an unknown mode (e.g. a typo), 63 !> this does not throw any error. 55 64 !--------------------------------------------------------------------------------------------------! 56 65 MODULE data_output_netcdf4_module … … 82 91 INTEGER :: global_id_in_file = -1 !< value of global ID within a file 83 92 INTEGER :: master_rank !< master rank for tasks to be executed by single PE only 93 INTEGER :: my_rank !< MPI rank of processor 84 94 INTEGER :: output_group_comm !< MPI communicator addressing all MPI ranks which participate in output 85 95 … … 150 160 program_debug_output_unit, debug_output, dom_global_id ) 151 161 162 CHARACTER(LEN=*), PARAMETER :: routine_name = 'netcdf4_init_module' !< name of this routine 163 152 164 CHARACTER(LEN=*), INTENT(IN) :: file_suffix_of_output_group !> file-name suffix added to each file; 153 165 !> must be unique for each output group … … 157 169 INTEGER, INTENT(IN) :: mpi_comm_of_output_group !< MPI communicator specifying the rank group participating in output 158 170 INTEGER, INTENT(IN) :: program_debug_output_unit !< file unit number for debug output 171 INTEGER :: return_value !< return value 159 172 160 173 LOGICAL, INTENT(IN) :: debug_output !< if true, debug output is printed … … 165 178 master_rank = master_output_rank 166 179 180 #if defined( __parallel ) 181 CALL MPI_COMM_RANK( output_group_comm, my_rank, return_value ) 182 IF ( return_value /= 0 ) THEN 183 CALL internal_message( 'error', routine_name // ': MPI_COMM_RANK error' ) 184 ENDIF 185 #else 186 my_rank = master_rank 187 return_value = 0 188 ! 189 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 190 IF ( .FALSE. ) CALL internal_message( 'debug', routine_name // ': dummy message' ) 191 #endif 192 167 193 debug_output_unit = program_debug_output_unit 168 194 print_debug_output = debug_output … … 185 211 186 212 INTEGER, INTENT(OUT) :: file_id !< file ID 187 INTEGER :: my_rank !< MPI rank of processor188 213 INTEGER :: nc_stat !< netcdf return value 189 214 INTEGER, INTENT(OUT) :: return_value !< return value … … 199 224 200 225 #if defined( __netcdf4 ) 201 #if defined( __parallel ) 202 CALL MPI_COMM_RANK( output_group_comm, my_rank, return_value ) 203 IF ( return_value /= 0 ) THEN 204 CALL internal_message( 'error', routine_name // ': MPI_COMM_RANK error' ) 205 ENDIF 206 IF ( my_rank /= master_rank ) THEN 207 return_value = 1 208 CALL internal_message( 'error', routine_name // & 209 ': trying to define a NetCDF file in serial mode by an MPI ' // & 210 'rank other than the master output rank. Serial NetCDF ' // & 211 'files can only be defined by the master output rank!' ) 212 ENDIF 213 #else 214 my_rank = master_rank 215 return_value = 0 216 #endif 217 218 IF ( return_value == 0 ) & 219 nc_stat = NF90_CREATE( TRIM( file_name ) // TRIM( file_suffix ), & 220 IOR( NF90_NOCLOBBER, NF90_NETCDF4 ), file_id ) 226 227 IF ( return_value == 0 ) THEN 228 IF ( my_rank == master_rank ) THEN 229 nc_stat = NF90_CREATE( TRIM( file_name ) // TRIM( file_suffix ), & 230 IOR( NF90_NOCLOBBER, NF90_NETCDF4 ), & 231 file_id ) 232 ELSE 233 nc_stat = 0 234 ENDIF 235 ENDIF 221 236 #else 222 237 nc_stat = 0 … … 245 260 nc_stat = 0 246 261 return_value = 1 247 CALL internal_message( 'error', routine_name // ': selected mode "' //&248 TRIM( mode ) // '" must be either "' //&249 262 CALL internal_message( 'error', routine_name // & 263 ': selected mode "' // TRIM( mode ) // '" must be either "' // & 264 mode_serial // '" or "' // mode_parallel // '"' ) 250 265 ENDIF 251 266 … … 266 281 !> Write attribute to netcdf file. 267 282 !--------------------------------------------------------------------------------------------------! 268 SUBROUTINE netcdf4_write_attribute( file_id, variable_id, attribute_name,&283 SUBROUTINE netcdf4_write_attribute( mode, file_id, variable_id, attribute_name, & 269 284 value_char, value_int8, value_int16, value_int32, & 270 285 value_real32, value_real64, return_value ) … … 273 288 274 289 CHARACTER(LEN=*), INTENT(IN) :: attribute_name !< name of attribute 290 CHARACTER(LEN=*), INTENT(IN) :: mode !< operation mode (either parallel or serial) 275 291 CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: value_char !< value of attribute 276 292 … … 292 308 return_value = 0 293 309 294 IF ( variable_id == global_id_in_file ) THEN 295 target_id = NF90_GLOBAL 296 ELSE 297 target_id = variable_id 298 ENDIF 299 300 CALL internal_message( 'debug', routine_name // & 301 ': write attribute "' // TRIM( attribute_name ) // '"' ) 302 303 IF ( PRESENT( value_char ) ) THEN 304 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), TRIM( value_char ) ) 305 ELSEIF ( PRESENT( value_int8 ) ) THEN 306 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_int8 ) 307 ELSEIF ( PRESENT( value_int16 ) ) THEN 308 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_int16 ) 309 ELSEIF ( PRESENT( value_int32 ) ) THEN 310 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_int32 ) 311 ELSEIF ( PRESENT( value_real32 ) ) THEN 312 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_real32 ) 313 ELSEIF ( PRESENT( value_real64 ) ) THEN 314 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_real64 ) 315 ELSE 316 return_value = 1 317 CALL internal_message( 'error', routine_name // & 318 ': no value given for attribute "' // TRIM( attribute_name ) // '"' ) 319 ENDIF 320 321 IF ( return_value == 0 ) THEN 322 IF ( nc_stat /= NF90_NOERR ) THEN 310 IF ( .NOT. ( TRIM( mode ) == mode_serial .AND. my_rank /= master_rank ) ) THEN 311 312 IF ( variable_id == global_id_in_file ) THEN 313 target_id = NF90_GLOBAL 314 ELSE 315 target_id = variable_id 316 ENDIF 317 318 CALL internal_message( 'debug', routine_name // & 319 ': write attribute "' // TRIM( attribute_name ) // '"' ) 320 321 IF ( PRESENT( value_char ) ) THEN 322 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), TRIM( value_char ) ) 323 ELSEIF ( PRESENT( value_int8 ) ) THEN 324 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_int8 ) 325 ELSEIF ( PRESENT( value_int16 ) ) THEN 326 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_int16 ) 327 ELSEIF ( PRESENT( value_int32 ) ) THEN 328 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_int32 ) 329 ELSEIF ( PRESENT( value_real32 ) ) THEN 330 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_real32 ) 331 ELSEIF ( PRESENT( value_real64 ) ) THEN 332 nc_stat = NF90_PUT_ATT( file_id, target_id, TRIM( attribute_name ), value_real64 ) 333 ELSE 323 334 return_value = 1 324 335 CALL internal_message( 'error', routine_name // & 325 ': NetCDF error while writing attribute "' // & 326 TRIM( attribute_name ) // '": ' // NF90_STRERROR( nc_stat ) ) 327 ENDIF 336 ': no value given for attribute "' // TRIM( attribute_name ) // & 337 '"' ) 338 ENDIF 339 340 IF ( return_value == 0 ) THEN 341 IF ( nc_stat /= NF90_NOERR ) THEN 342 return_value = 1 343 CALL internal_message( 'error', routine_name // & 344 ': NetCDF error while writing attribute "' // & 345 TRIM( attribute_name ) // '": ' // NF90_STRERROR( nc_stat ) ) 346 ENDIF 347 ENDIF 348 328 349 ENDIF 329 350 #else 330 351 return_value = 1 352 ! 353 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 354 IF ( .FALSE. ) THEN 355 nc_stat = LEN( routine_name ) 356 target_id = 0 357 ENDIF 331 358 #endif 332 359 … … 339 366 !--------------------------------------------------------------------------------------------------! 340 367 SUBROUTINE netcdf4_init_dimension( mode, file_id, dimension_id, variable_id, & 341 dimension_name, dimension_type, dimension_length, return_value ) 368 dimension_name, dimension_type, dimension_length, & 369 write_only_by_master_rank, return_value ) 342 370 343 371 CHARACTER(LEN=*), PARAMETER :: routine_name = 'netcdf4_init_dimension' !< name of this routine … … 355 383 INTEGER, INTENT(OUT) :: variable_id !< variable ID 356 384 385 LOGICAL, INTENT(IN) :: write_only_by_master_rank !< true if only master rank shall write variable 386 357 387 358 388 #if defined( __netcdf4 ) 359 389 return_value = 0 360 390 variable_id = -1 361 362 CALL internal_message( 'debug', routine_name // & 363 ': init dimension "' // TRIM( dimension_name ) // '"' ) 364 ! 365 !-- Check if dimension is unlimited 366 IF ( dimension_length < 0 ) THEN 367 nc_dimension_length = NF90_UNLIMITED 368 ELSE 369 nc_dimension_length = dimension_length 370 ENDIF 371 ! 372 !-- Define dimension in file 373 nc_stat = NF90_DEF_DIM( file_id, dimension_name, nc_dimension_length, dimension_id ) 374 375 IF ( nc_stat == NF90_NOERR ) THEN 376 ! 377 !-- Define variable holding dimension values in file 378 CALL netcdf4_init_variable( mode, file_id, variable_id, dimension_name, dimension_type, & 379 (/ dimension_id /), is_global=.TRUE., return_value=return_value ) 380 381 ELSE 382 return_value = 1 383 CALL internal_message( 'error', routine_name // & 384 ': NetCDF error while initializing dimension "' // & 385 TRIM( dimension_name ) // '": ' // NF90_STRERROR( nc_stat ) ) 391 dimension_id = -1 392 393 IF ( .NOT. ( TRIM( mode ) == mode_serial .AND. my_rank /= master_rank ) ) THEN 394 395 CALL internal_message( 'debug', routine_name // & 396 ': init dimension "' // TRIM( dimension_name ) // '"' ) 397 ! 398 !-- Check if dimension is unlimited 399 IF ( dimension_length < 0 ) THEN 400 nc_dimension_length = NF90_UNLIMITED 401 ELSE 402 nc_dimension_length = dimension_length 403 ENDIF 404 ! 405 !-- Define dimension in file 406 nc_stat = NF90_DEF_DIM( file_id, dimension_name, nc_dimension_length, dimension_id ) 407 408 IF ( nc_stat == NF90_NOERR ) THEN 409 ! 410 !-- Define variable holding dimension values in file 411 CALL netcdf4_init_variable( mode, file_id, variable_id, dimension_name, dimension_type, & 412 (/ dimension_id /), & 413 write_only_by_master_rank=write_only_by_master_rank, & 414 return_value=return_value ) 415 416 ELSE 417 return_value = 1 418 CALL internal_message( 'error', routine_name // & 419 ': NetCDF error while initializing dimension "' // & 420 TRIM( dimension_name ) // '": ' // NF90_STRERROR( nc_stat ) ) 421 ENDIF 422 386 423 ENDIF 387 424 #else … … 389 426 variable_id = -1 390 427 dimension_id = -1 428 ! 429 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 430 IF ( .FALSE. ) THEN 431 nc_stat = LEN( routine_name ) 432 nc_dimension_length = 0 433 ENDIF 391 434 #endif 392 435 … … 399 442 !--------------------------------------------------------------------------------------------------! 400 443 SUBROUTINE netcdf4_init_variable( mode, file_id, variable_id, variable_name, variable_type, & 401 dimension_ids, is_global, return_value )444 dimension_ids, write_only_by_master_rank, return_value ) 402 445 403 446 CHARACTER(LEN=*), PARAMETER :: routine_name = 'netcdf4_init_variable' !< name of this routine … … 407 450 CHARACTER(LEN=*), INTENT(IN) :: variable_type !< data type of variable 408 451 409 INTEGER, INTENT(IN) :: file_id !< file ID 410 INTEGER :: nc_stat !< netcdf return value 411 INTEGER :: nc_variable_type !< netcdf data type 412 INTEGER, INTENT(OUT) :: return_value !< return value 413 INTEGER, INTENT(OUT) :: variable_id !< variable ID 414 452 INTEGER, INTENT(IN) :: file_id !< file ID 453 INTEGER :: nc_stat !< netcdf return value 454 INTEGER :: nc_variable_type !< netcdf data type 455 INTEGER, INTENT(OUT) :: return_value !< return value 456 INTEGER, INTENT(OUT) :: variable_id !< variable ID 457 #if defined( __netcdf4_parallel ) 458 INTEGER :: parallel_access_mode !< either NF90_INDEPENDENT or NF90_COLLECTIVE 459 INTEGER :: unlimited_dimension_id !< ID of unlimited dimension in file 460 #endif 415 461 INTEGER, DIMENSION(:), INTENT(IN) :: dimension_ids !< list of dimension IDs used by variable 416 462 417 LOGICAL, INTENT(IN) :: is_global !< true if variable is global (same on all PE)463 LOGICAL, INTENT(IN) :: write_only_by_master_rank !< true if only master rank shall write variable 418 464 419 465 420 466 #if defined( __netcdf4 ) 421 467 return_value = 0 422 423 WRITE( temp_string, * ) is_global 424 CALL internal_message( 'debug', routine_name // & 425 ': init variable "' // TRIM( variable_name ) // & 426 '" ( is_global = ' // TRIM( temp_string ) // ')' ) 427 428 nc_variable_type = get_netcdf_data_type( variable_type ) 429 430 IF ( nc_variable_type /= -1 ) THEN 431 ! 432 !-- Define variable in file 433 nc_stat = NF90_DEF_VAR( file_id, variable_name, nc_variable_type, dimension_ids, variable_id ) 434 435 ! 436 !-- Define how variable can be accessed by PEs in parallel netcdf file 437 IF ( nc_stat == NF90_NOERR .AND. TRIM( mode ) == mode_parallel ) THEN 468 variable_id = -1 469 470 IF ( ( TRIM( mode ) == mode_serial .AND. my_rank == master_rank ) & 471 .OR. TRIM( mode ) == mode_parallel ) THEN 472 473 WRITE( temp_string, * ) write_only_by_master_rank 474 CALL internal_message( 'debug', routine_name // & 475 ': init variable "' // TRIM( variable_name ) // & 476 '" ( write_only_by_master_rank = ' // TRIM( temp_string ) // ')' ) 477 478 nc_variable_type = get_netcdf_data_type( variable_type ) 479 480 IF ( nc_variable_type /= -1 ) THEN 481 ! 482 !-- Define variable in file 483 nc_stat = NF90_DEF_VAR( file_id, variable_name, nc_variable_type, & 484 dimension_ids, variable_id ) 485 438 486 #if defined( __netcdf4_parallel ) 439 IF ( is_global ) THEN 440 nc_stat = NF90_VAR_PAR_ACCESS( file_id, variable_id, NF90_INDEPENDENT ) 441 ELSE 442 nc_stat = NF90_VAR_PAR_ACCESS( file_id, variable_id, NF90_COLLECTIVE ) 487 ! 488 !-- Define how variable can be accessed by PEs in parallel netcdf file 489 IF ( nc_stat == NF90_NOERR .AND. TRIM( mode ) == mode_parallel ) THEN 490 ! 491 !-- If the variable uses an unlimited dimension, its access mode must be 'collective', 492 !-- otherwise it can be set to independent. 493 !-- Hence, get ID of unlimited dimension in file (if any) and check if it is used by 494 !-- the variable. 495 nc_stat = NF90_INQUIRE( file_id, UNLIMITEDDIMID=unlimited_dimension_id ) 496 497 IF ( nc_stat == NF90_NOERR ) THEN 498 IF ( ANY( dimension_ids == unlimited_dimension_id ) ) THEN 499 parallel_access_mode = NF90_COLLECTIVE 500 ELSE 501 parallel_access_mode = NF90_INDEPENDENT 502 ENDIF 503 504 nc_stat = NF90_VAR_PAR_ACCESS( file_id, variable_id, parallel_access_mode ) 505 ENDIF 443 506 ENDIF 444 #else 445 CONTINUE 446 #endif 447 ENDIF 448 449 IF ( nc_stat /= NF90_NOERR ) THEN 507 #endif 508 509 IF ( nc_stat /= NF90_NOERR ) THEN 510 return_value = 1 511 CALL internal_message( 'error', routine_name // & 512 ': NetCDF error while initializing variable "' // & 513 TRIM( variable_name ) // '": ' // NF90_STRERROR( nc_stat ) ) 514 ENDIF 515 516 ELSE 450 517 return_value = 1 451 CALL internal_message( 'error', routine_name // & 452 ': NetCDF error while initializing variable "' // & 453 TRIM( variable_name ) // '": ' // NF90_STRERROR( nc_stat ) ) 454 ENDIF 455 456 ELSE 518 ENDIF 519 520 ELSEIF ( TRIM( mode ) /= mode_serial .AND. TRIM( mode ) /= mode_parallel ) THEN 457 521 return_value = 1 522 CALL internal_message( 'error', routine_name // & 523 ': selected mode "' // TRIM( mode ) // '" must be either "' // & 524 mode_serial // '" or "' // mode_parallel // '"' ) 458 525 ENDIF 459 526 … … 461 528 return_value = 1 462 529 variable_id = -1 530 ! 531 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 532 IF ( .FALSE. ) THEN 533 nc_stat = LEN( routine_name ) 534 nc_variable_type = get_netcdf_data_type( '' ) 535 ENDIF 463 536 #endif 464 537 … … 470 543 !> Leave file definition state. 471 544 !--------------------------------------------------------------------------------------------------! 472 SUBROUTINE netcdf4_stop_file_header_definition( file_id, return_value )545 SUBROUTINE netcdf4_stop_file_header_definition( mode, file_id, return_value ) 473 546 474 547 CHARACTER(LEN=*), PARAMETER :: routine_name = 'netcdf4_stop_file_header_definition' !< name of this routine 548 549 CHARACTER(LEN=*), INTENT(IN) :: mode !< operation mode (either parallel or serial) 475 550 476 551 INTEGER, INTENT(IN) :: file_id !< file ID … … 483 558 return_value = 0 484 559 485 WRITE( temp_string, * ) file_id 486 CALL internal_message( 'debug', routine_name // & 487 ': finalize file definition (file_id=' // TRIM( temp_string ) // ')' ) 488 ! 489 !-- Set general no fill, otherwise the performance drops significantly 490 nc_stat = NF90_SET_FILL( file_id, NF90_NOFILL, old_fill_mode ) 491 492 IF ( nc_stat == NF90_NOERR ) THEN 493 nc_stat = NF90_ENDDEF( file_id ) 494 ENDIF 495 496 IF ( nc_stat /= NF90_NOERR ) THEN 497 return_value = 1 498 CALL internal_message( 'error', routine_name // & 499 ': NetCDF error: ' // NF90_STRERROR( nc_stat ) ) 560 IF ( .NOT. ( TRIM( mode ) == mode_serial .AND. my_rank /= master_rank ) ) THEN 561 562 WRITE( temp_string, * ) file_id 563 CALL internal_message( 'debug', routine_name // & 564 ': finalize file definition (file_id=' // TRIM( temp_string ) // ')' ) 565 ! 566 !-- Set general no fill, otherwise the performance drops significantly 567 nc_stat = NF90_SET_FILL( file_id, NF90_NOFILL, old_fill_mode ) 568 569 IF ( nc_stat == NF90_NOERR ) THEN 570 nc_stat = NF90_ENDDEF( file_id ) 571 ENDIF 572 573 IF ( nc_stat /= NF90_NOERR ) THEN 574 return_value = 1 575 CALL internal_message( 'error', routine_name // & 576 ': NetCDF error: ' // NF90_STRERROR( nc_stat ) ) 577 ENDIF 578 500 579 ENDIF 501 580 #else 502 581 return_value = 1 582 ! 583 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 584 IF ( .FALSE. ) THEN 585 nc_stat = LEN( routine_name ) 586 old_fill_mode = 0 587 ENDIF 503 588 #endif 504 589 … … 511 596 !--------------------------------------------------------------------------------------------------! 512 597 SUBROUTINE netcdf4_write_variable( & 513 file_id, variable_id, bounds_start, value_counts, bounds_origin,&514 is_global,&598 mode, file_id, variable_id, bounds_start, value_counts, bounds_origin, & 599 write_only_by_master_rank, & 515 600 values_char_0d, values_char_1d, values_char_2d, values_char_3d, & 516 601 values_int8_0d, values_int8_1d, values_int8_2d, values_int8_3d, & … … 525 610 CHARACTER(LEN=*), PARAMETER :: routine_name = 'netcdf4_write_variable' !< name of this routine 526 611 612 CHARACTER(LEN=*), INTENT(IN) :: mode !< operation mode (either parallel or serial) 613 527 614 CHARACTER(LEN=1), POINTER, INTENT(IN), OPTIONAL :: values_char_0d !< output variable 528 615 CHARACTER(LEN=1), POINTER, CONTIGUOUS, INTENT(IN), OPTIONAL, DIMENSION(:) :: values_char_1d !< output variable … … 530 617 CHARACTER(LEN=1), POINTER, CONTIGUOUS, INTENT(IN), OPTIONAL, DIMENSION(:,:,:) :: values_char_3d !< output variable 531 618 532 INTEGER :: d !< loop index533 INTEGER, INTENT(IN) :: file_id !< file ID534 INTEGER :: my_rank !< MPI rank of processor535 INTEGER :: n c_stat !< netcdf return value536 INTEGER :: ndims !< number of dimensions of variable in file537 INTEGER , INTENT(OUT) :: return_value !< return value538 INTEGER, INTENT(IN) :: variable_id !< variable ID619 INTEGER :: d !< loop index 620 INTEGER, INTENT(IN) :: file_id !< file ID 621 INTEGER :: nc_stat !< netcdf return value 622 INTEGER :: ndims !< number of dimensions of variable in file 623 INTEGER, INTENT(OUT) :: return_value !< return value 624 INTEGER :: unlimited_dimension_id !< ID of unlimited dimension in file 625 INTEGER, INTENT(IN) :: variable_id !< variable ID 539 626 540 627 INTEGER, DIMENSION(:), INTENT(IN) :: bounds_origin !< starting index of each dimension … … 561 648 INTEGER(iwp), POINTER, CONTIGUOUS, INTENT(IN), OPTIONAL, DIMENSION(:,:,:) :: values_intwp_3d !< output variable 562 649 563 LOGICAL, INTENT(IN) :: is_global !< true if variable is global (same on all PE) 650 LOGICAL, INTENT(IN) :: write_only_by_master_rank !< true if only master rank shall write variable 651 LOGICAL :: write_data !< true if variable shall be written to file 564 652 565 653 REAL(KIND=4), POINTER, INTENT(IN), OPTIONAL :: values_real32_0d !< output variable … … 578 666 579 667 #if defined( __netcdf4 ) 580 581 #if defined( __parallel )582 CALL MPI_COMM_RANK( output_group_comm, my_rank, return_value )583 IF ( return_value /= 0 ) THEN584 CALL internal_message( 'error', routine_name // ': MPI_COMM_RANK error' )585 ENDIF586 #else587 my_rank = master_rank588 668 return_value = 0 589 #endif 590 591 IF ( return_value == 0 .AND. ( .NOT. is_global .OR. my_rank == master_rank ) ) THEN 669 write_data = .FALSE. 670 ! 671 !-- Check whether this PE write any data to file 672 IF ( TRIM( mode ) == mode_serial ) THEN 673 674 IF ( my_rank == master_rank ) write_data = .TRUE. 675 676 ELSEIF ( TRIM( mode ) == mode_parallel ) THEN 677 ! 678 !-- Check for collective access mode. 679 !-- This cannot be checked directly but indirect via the presence of any unlimited dimensions 680 !-- If any dimension is unlimited, variable access must be collective and all PEs must 681 !-- participate in writing 682 ndims = SIZE( bounds_start ) 683 ALLOCATE( dimension_ids(ndims) ) 684 685 nc_stat = NF90_INQUIRE_VARIABLE( file_id, variable_id, DIMIDS=dimension_ids ) 686 nc_stat = NF90_INQUIRE( file_id, UNLIMITEDDIMID=unlimited_dimension_id ) 687 688 IF ( ANY( dimension_ids == unlimited_dimension_id ) ) THEN 689 write_data = .TRUE. 690 ! 691 !-- If access is independent, check if only master rank shall write 692 ELSEIF ( write_only_by_master_rank ) THEN 693 IF ( my_rank == master_rank ) write_data = .TRUE. 694 ! 695 !-- If all PEs can write, check if there are any data to be written 696 ELSEIF ( ALL( value_counts > 0, DIM=1 ) ) THEN 697 write_data = .TRUE. 698 ENDIF 699 700 ELSE 701 return_value = 1 702 CALL internal_message( 'error', routine_name // & 703 ': selected mode "' // TRIM( mode ) // '" must be either "' // & 704 mode_serial // '" or "' // mode_parallel // '"' ) 705 ENDIF 706 707 IF ( write_data ) THEN 592 708 593 709 WRITE( temp_string, * ) variable_id … … 595 711 596 712 ndims = SIZE( bounds_start ) 597 598 ! 599 !-- character output 713 ! 714 !-- Character output 600 715 IF ( PRESENT( values_char_0d ) ) THEN 601 716 nc_stat = NF90_PUT_VAR( file_id, variable_id, (/ values_char_0d /), & … … 723 838 count = value_counts ) 724 839 ! 725 !-- working-precision real output840 !-- Working-precision real output 726 841 ELSEIF ( PRESENT( values_realwp_0d ) ) THEN 727 842 nc_stat = NF90_PUT_VAR( file_id, variable_id, (/ values_realwp_0d /), & … … 757 872 WRITE( temp_string, * ) NF90_STRERROR( nc_stat ) 758 873 759 ALLOCATE( dimension_ids(ndims) )874 IF ( .NOT. ALLOCATED( dimension_ids ) ) ALLOCATE( dimension_ids(ndims) ) 760 875 ALLOCATE( dimension_lengths(ndims) ) 761 876 … … 793 908 #else 794 909 return_value = 1 910 ! 911 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 912 IF ( .FALSE. ) THEN 913 nc_stat = LEN( routine_name ) 914 IF ( write_data ) unlimited_dimension_id = 0 915 IF ( ALLOCATED( dimension_ids ) ) d = 0 916 IF ( ALLOCATED( dimension_lengths ) ) ndims = 0 917 ENDIF 795 918 #endif 796 919 … … 802 925 !> Close netcdf file. 803 926 !--------------------------------------------------------------------------------------------------! 804 SUBROUTINE netcdf4_finalize( file_id, return_value )927 SUBROUTINE netcdf4_finalize( mode, file_id, return_value ) 805 928 806 929 CHARACTER(LEN=*), PARAMETER :: routine_name = 'netcdf4_finalize' !< name of routine 930 931 CHARACTER(LEN=*), INTENT(IN) :: mode !< operation mode (either parallel or serial) 807 932 808 933 INTEGER, INTENT(IN) :: file_id !< file ID … … 812 937 813 938 #if defined( __netcdf4 ) 814 WRITE( temp_string, * ) file_id 815 CALL internal_message( 'debug', routine_name // & 816 ': close file (file_id=' // TRIM( temp_string ) // ')' ) 817 818 nc_stat = NF90_CLOSE( file_id ) 819 IF ( nc_stat == NF90_NOERR ) THEN 820 return_value = 0 821 ELSE 822 return_value = 1 823 CALL internal_message( 'error', routine_name // & 824 ': NetCDF error: ' // NF90_STRERROR( nc_stat ) ) 939 return_value = 0 940 941 IF ( .NOT. ( TRIM( mode ) == mode_serial .AND. my_rank /= master_rank ) ) THEN 942 943 WRITE( temp_string, * ) file_id 944 CALL internal_message( 'debug', routine_name // & 945 ': close file (file_id=' // TRIM( temp_string ) // ')' ) 946 947 nc_stat = NF90_CLOSE( file_id ) 948 IF ( nc_stat == NF90_NOERR ) THEN 949 return_value = 0 950 ELSE 951 return_value = 1 952 CALL internal_message( 'error', routine_name // & 953 ': NetCDF error: ' // NF90_STRERROR( nc_stat ) ) 954 ENDIF 955 825 956 ENDIF 826 957 #else 827 958 return_value = 1 959 ! 960 !-- Dummy commands to prevent "unused-variable" warning if preprocessor is not set 961 IF ( .FALSE. ) THEN 962 nc_stat = 0 963 temp_string = routine_name 964 ENDIF 828 965 #endif 829 966
Note: See TracChangeset
for help on using the changeset viewer.