52 openpmd_access_create, &
53 openpmd_attributable_type, openpmd_iteration_type, openpmd_mesh_type, &
54 openpmd_particle_species_type, &
55 openpmd_record_type, &
56 openpmd_series_create, openpmd_series_type, &
57 openpmd_type_int, openpmd_json_merge, openpmd_get_default_extension
61#include "../base/base_uses.f90"
66 LOGICAL,
PRIVATE,
PARAMETER :: debug_this_module = .true.
67 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_output_handling_openpmd'
76 TYPE(openpmd_series_type) :: series = openpmd_series_type()
77 TYPE(openpmd_iteration_type) :: iteration = openpmd_iteration_type()
80 CHARACTER(len=default_string_length) :: name_prefix =
""
83 TYPE :: cp_openpmd_per_call_type
86 END TYPE cp_openpmd_per_call_type
88 TYPE :: cp_current_iteration_counter_type
89 INTEGER :: flat_iteration = 0
90 INTEGER,
ALLOCATABLE :: complex_iteration(:)
91 INTEGER :: complex_iteration_depth = 0
92 END TYPE cp_current_iteration_counter_type
94 TYPE :: cp_openpmd_per_callsite_value_type
96 TYPE(openpmd_series_type) :: output_series = openpmd_series_type()
100 TYPE(cp_current_iteration_counter_type) :: iteration_counter = cp_current_iteration_counter_type()
101 END TYPE cp_openpmd_per_callsite_value_type
103 TYPE :: cp_openpmd_per_callsite_type
104 CHARACTER(len=default_string_length) :: key =
""
105 TYPE(cp_openpmd_per_callsite_value_type) ::
value = cp_openpmd_per_callsite_value_type()
106 END TYPE cp_openpmd_per_callsite_type
115 TYPE(cp_openpmd_per_call_type),
ALLOCATABLE :: cp_openpmd_per_call(:)
116 INTEGER :: cp_num_openpmd_per_call = 0
117 INTEGER :: cp_capacity_openpmd_per_call = 0
124 TYPE(cp_openpmd_per_callsite_type),
ALLOCATABLE,
TARGET :: cp_openpmd_per_callsite(:)
125 INTEGER :: cp_num_openpmd_per_callsite = 0
126 INTEGER :: cp_capacity_openpmd_per_callsite = 0
140 INTEGER,
PARAMETER :: cp_allocation_size = 100
143 CHARACTER(len=*),
PARAMETER :: cp_default_backend_config = &
144 "[hdf5]"//new_line(
'a')// &
145 "# will be overridden by particle flushes"//new_line(
'a')// &
146 "independent_stores = false"//new_line(
'a')// &
147 "dont_warn_unused_keys = ['independent_stores']"//new_line(
'a')// &
148 ""//new_line(
'a')// &
149 "[adios2]"//new_line(
'a')// &
150 "# discard any attributes written on ranks other than 0"//new_line(
'a')// &
151 "attribute_writing_ranks = 0"//new_line(
'a')// &
152 "[adios2.engine]"//new_line(
'a')// &
153 "# CP2K generally has many small IO operations, "//new_line(
'a')// &
154 "# so stage IO memory to the buffer first and then "//new_line(
'a')// &
155 "# run it all at once, instead of writing to disk directly."//new_line(
'a')// &
156 "# Save memory by specifying 'disk' here instead."//new_line(
'a')// &
157 "# TODO: In future, maybe implement some input variable"//new_line(
'a')// &
158 "# to specify intervals at which to flush to disk."//new_line(
'a')// &
159 "preferred_flush_target = 'buffer'"//new_line(
'a')
161 CHARACTER(len=*),
PARAMETER :: cp_default_backend_config_non_windows = &
162 "# Raise the BufferChunkSize to the maximum (2GB), since large operations"//new_line(
'a')// &
163 "# improve IO performance and the allocation overhead only cuts into"//new_line(
'a')// &
164 "# virtual memory (except on Windows, hence do not do that there)"//new_line(
'a')// &
165 "[adios2.engine.parameters]"//new_line(
'a')// &
166 "BufferChunkSize = 2147381248"//new_line(
'a')
173#else ! defined(__OPENPMD)
194 FUNCTION cp_openpmd_add_unit_nr (key, value)
RESULT(index)
195 INTEGER,
INTENT(in) :: key
196 TYPE(cp_openpmd_per_call_value_type),
INTENT(in) :: value
199 LOGICAL :: check_capacity
203 DO i = 1, cp_num_openpmd_per_call
204 IF (cp_openpmd_per_call(i)%key == key)
THEN
205 cp_openpmd_per_call(i)%value =
value
211 IF (cp_capacity_openpmd_per_call == 0)
THEN
212 ALLOCATE (cp_openpmd_per_call(cp_allocation_size))
213 cp_capacity_openpmd_per_call = cp_allocation_size
217 check_capacity = cp_num_openpmd_per_call < cp_capacity_openpmd_per_call
218 cpassert(check_capacity)
221 cp_num_openpmd_per_call = cp_num_openpmd_per_call+1
222 cp_openpmd_per_call(cp_num_openpmd_per_call)%key = key
223 cp_openpmd_per_call(cp_num_openpmd_per_call)%value =
value
224 index = cp_num_openpmd_per_call
225 END FUNCTION cp_openpmd_add_unit_nr
232 FUNCTION cp_openpmd_get_index_unit_nr (key)
RESULT(index)
233 INTEGER,
INTENT(in) :: key
240 DO i = 1, cp_num_openpmd_per_call
241 IF (cp_openpmd_per_call(i)%key == key)
THEN
246 END FUNCTION cp_openpmd_get_index_unit_nr
249 INTEGER,
INTENT(in) :: key
250 TYPE(cp_openpmd_per_call_value_type) :: value
254 i = cp_openpmd_get_index_unit_nr(key)
257 value = cp_openpmd_per_call(i)%value
265 FUNCTION cp_openpmd_remove_unit_nr (key)
RESULT(was_found)
266 INTEGER,
INTENT(in) :: key
273 DO i = 1, cp_num_openpmd_per_call
274 IF (cp_openpmd_per_call(i)%key == key)
THEN
276 IF (i /= cp_num_openpmd_per_call)
THEN
278 cp_openpmd_per_call(i) = cp_openpmd_per_call(cp_num_openpmd_per_call)
281 cp_num_openpmd_per_call = cp_num_openpmd_per_call-1
282 IF (cp_num_openpmd_per_call == 0)
THEN
283 DEALLOCATE (cp_openpmd_per_call)
284 cp_capacity_openpmd_per_call = 0
289 END FUNCTION cp_openpmd_remove_unit_nr
299 FUNCTION cp_openpmd_add_filedata (key, value)
RESULT(index)
300 CHARACTER(len=default_string_length),
INTENT(in) :: key
301 TYPE(cp_openpmd_per_callsite_value_type),
INTENT(in) :: value
304 LOGICAL :: check_capacity
308 DO i = 1, cp_num_openpmd_per_callsite
309 IF (cp_openpmd_per_callsite(i)%key == key)
THEN
310 cp_openpmd_per_callsite(i)%value =
value
316 IF (cp_capacity_openpmd_per_callsite == 0)
THEN
317 ALLOCATE (cp_openpmd_per_callsite(cp_allocation_size))
318 cp_capacity_openpmd_per_callsite = cp_allocation_size
322 check_capacity = cp_num_openpmd_per_callsite < cp_capacity_openpmd_per_callsite
323 cpassert(check_capacity)
326 cp_num_openpmd_per_callsite = cp_num_openpmd_per_callsite+1
327 cp_openpmd_per_callsite(cp_num_openpmd_per_callsite)%key = key
328 cp_openpmd_per_callsite(cp_num_openpmd_per_callsite)%value =
value
329 index = cp_num_openpmd_per_callsite
330 END FUNCTION cp_openpmd_add_filedata
337 FUNCTION cp_openpmd_get_index_filedata (key)
RESULT(index)
338 CHARACTER(len=default_string_length),
INTENT(in) :: key
345 DO i = 1, cp_num_openpmd_per_callsite
346 IF (cp_openpmd_per_callsite(i)%key == key)
THEN
351 END FUNCTION cp_openpmd_get_index_filedata
353 FUNCTION cp_openpmd_get_value_filedata (key)
RESULT(value)
354 CHARACTER(len=default_string_length),
INTENT(in) :: key
355 TYPE(cp_openpmd_per_callsite_value_type) :: value
359 i = cp_openpmd_get_index_filedata(key)
362 value = cp_openpmd_per_callsite(i)%value
363 END FUNCTION cp_openpmd_get_value_filedata
370 FUNCTION cp_openpmd_remove_filedata (key)
RESULT(was_found)
371 CHARACTER(len=default_string_length),
INTENT(in) :: key
378 DO i = 1, cp_num_openpmd_per_callsite
379 IF (cp_openpmd_per_callsite(i)%key == key)
THEN
381 IF (i /= cp_num_openpmd_per_callsite)
THEN
383 cp_openpmd_per_callsite(i) = cp_openpmd_per_callsite(cp_num_openpmd_per_callsite)
386 cp_num_openpmd_per_callsite = cp_num_openpmd_per_callsite-1
387 IF (cp_num_openpmd_per_callsite == 0)
THEN
388 DEALLOCATE (cp_openpmd_per_callsite)
389 cp_capacity_openpmd_per_callsite = 0
394 END FUNCTION cp_openpmd_remove_filedata
408 FUNCTION cp_print_key_generate_openpmd_filename(logger, print_key, openpmd_basename, extension)
RESULT(filename)
409 TYPE(cp_logger_type),
POINTER :: logger
410 TYPE(section_vals_type),
POINTER :: print_key
411 CHARACTER(len=*),
INTENT(IN) :: openpmd_basename, extension
412 CHARACTER(len=default_path_length) :: filename
414 CHARACTER(len=default_path_length) :: outPath, root
415 CHARACTER(len=default_string_length) :: outName
416 INTEGER :: my_ind1, my_ind2
420 IF (outpath(1:1) ==
'=')
THEN
421 cpassert(len(outpath) - 1 <= len(filename))
422 filename = outpath(2:)
425 IF (outpath ==
"__STD_OUT__") outpath =
""
428 my_ind1 = index(outpath,
"/")
429 my_ind2 = len_trim(outpath)
430 IF (my_ind1 /= 0)
THEN
432 DO WHILE (index(outpath(my_ind1 + 1:my_ind2),
"/") /= 0)
433 my_ind1 = index(outpath(my_ind1 + 1:my_ind2),
"/") + my_ind1
435 IF (my_ind1 == my_ind2)
THEN
438 outname = outpath(my_ind1 + 1:my_ind2)
442 IF (.NOT. has_root)
THEN
443 root = trim(logger%iter_info%project_name)
444 ELSE IF (outname ==
"")
THEN
445 root = outpath(1:my_ind1)//trim(logger%iter_info%project_name)
447 root = outpath(1:my_ind1)
450 filename = adjustl(trim(root)//
"_"//trim(openpmd_basename)//trim(extension))
452 END FUNCTION cp_print_key_generate_openpmd_filename
461 FUNCTION cp_advance_iteration_number(logger, openpmd_file)
RESULT(did_advance_iteration)
462 TYPE(cp_logger_type),
POINTER :: logger
463 TYPE(cp_openpmd_per_callsite_value_type) :: openpmd_file
464 LOGICAL :: did_advance_iteration
469 did_advance_iteration = .false.
470 len =
SIZE(logger%iter_info%iteration)
471 IF (len /= openpmd_file%iteration_counter%complex_iteration_depth)
THEN
472 did_advance_iteration = .true.
473 openpmd_file%iteration_counter%complex_iteration_depth = len
474 ALLOCATE (openpmd_file%iteration_counter%complex_iteration(len))
476 did_advance_iteration &
477 = any(openpmd_file%iteration_counter%complex_iteration(1:len) &
478 /= logger%iter_info%iteration(1:len))
481 IF (.NOT. did_advance_iteration)
RETURN
483 openpmd_file%iteration_counter%flat_iteration = openpmd_file%iteration_counter%flat_iteration + 1
484 openpmd_file%iteration_counter%complex_iteration(1:len) &
485 = logger%iter_info%iteration(1:len)
487 END FUNCTION cp_advance_iteration_number
503 FUNCTION cp_openpmd_create_unit_nr_entry(openpmd_file_index, middle_name, logger)
RESULT(res)
504 INTEGER :: openpmd_file_index
505 CHARACTER(len=*),
INTENT(IN) :: middle_name
506 TYPE(cp_logger_type),
POINTER :: logger
507 TYPE(cp_openpmd_per_call_value_type) :: res
509 LOGICAL,
SAVE :: opened_new_iteration = .false.
510 TYPE(openpmd_attributable_type) :: attr
511 TYPE(cp_openpmd_per_callsite_value_type),
POINTER :: opmd
513 opmd => cp_openpmd_per_callsite(openpmd_file_index)%value
515 res%series = opmd%output_series
517 opened_new_iteration = cp_advance_iteration_number(logger, opmd)
519 res%iteration = opmd%output_series%write_iteration(opmd%iteration_counter%flat_iteration)
520 res%name_prefix = trim(middle_name)
522 IF (opened_new_iteration)
THEN
523 attr = res%iteration%as_attributable()
524 CALL attr%set_attribute_vec_int( &
525 "ndim_iteration_index", &
526 opmd%iteration_counter%complex_iteration)
528 END FUNCTION cp_openpmd_create_unit_nr_entry
534 FUNCTION cp_openpmd_get_openpmd_file_entry(openpmd_basename, filename, openpmd_config, logger, use_mpi)
RESULT(file_index)
535 CHARACTER(len=*),
INTENT(IN) :: openpmd_basename, filename, openpmd_config
536 TYPE(cp_logger_type),
POINTER :: logger
538 INTEGER :: file_index
539 CHARACTER(:),
ALLOCATABLE :: merged_config
541 CHARACTER(len=default_string_length),
SAVE :: basename_copied =
' '
542 TYPE(cp_openpmd_per_callsite_value_type) :: emplace_new
545 TYPE(cp_openpmd_per_callsite_value_type) :: series_data
546 TYPE(openpmd_iteration_type) :: iteration
549 basename_copied(1:len_trim(openpmd_basename)) = trim(openpmd_basename)
551 file_index = cp_openpmd_get_index_filedata(basename_copied)
553 CALL timeset(
'openpmd_close_iterations', handle)
554 DO i = 1, cp_num_openpmd_per_callsite
555 IF (i /= file_index)
THEN
556 series_data = cp_openpmd_per_callsite(i)%value
557 iteration = series_data%output_series%get_iteration( &
558 series_data%iteration_counter%flat_iteration)
559 IF (.NOT. iteration%closed())
THEN
560 CALL iteration%close()
564 CALL timestop(handle)
566 IF (file_index /= -1)
RETURN
569 merged_config = openpmd_json_merge(cp_default_backend_config, cp_default_backend_config_non_windows)
571 merged_config = cp_default_backend_config
574 merged_config = openpmd_json_merge(merged_config, openpmd_config, logger%para_env)
575 emplace_new%output_series = openpmd_series_create( &
576 filename, openpmd_access_create, logger%para_env, merged_config)
578 merged_config = openpmd_json_merge(merged_config, openpmd_config)
579 emplace_new%output_series = openpmd_series_create( &
580 filename, openpmd_access_create, config=merged_config)
582 DEALLOCATE (merged_config)
583 file_index = cp_openpmd_add_filedata(basename_copied, emplace_new)
584 END FUNCTION cp_openpmd_get_openpmd_file_entry
586#else ! defined(__OPENPMD)
589 INTEGER,
INTENT(in) :: key
594 cpabort(
"CP2K compiled without the openPMD-api")
606 DO i = 1, cp_num_openpmd_per_callsite
607 DEALLOCATE (cp_openpmd_per_callsite(i)%value%iteration_counter%complex_iteration)
608 CALL cp_openpmd_per_callsite(i)%value%output_series%close()
610 IF (
ALLOCATED(cp_openpmd_per_callsite))
THEN
611 DEALLOCATE (cp_openpmd_per_callsite)
613 cp_num_openpmd_per_callsite = 0
641 middle_name, ignore_should_output, &
643 fout, openpmd_basename)
RESULT(res)
646 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: print_key_path
647 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: middle_name
648 LOGICAL,
INTENT(IN),
OPTIONAL :: ignore_should_output
649 LOGICAL,
INTENT(INOUT),
OPTIONAL :: mpi_io
650 CHARACTER(len=default_path_length),
INTENT(OUT), &
652 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: openpmd_basename
657 CHARACTER(len=default_path_length) :: filename
659 CHARACTER(len=default_string_length) :: openpmd_config, outpath, file_extension
664 INTEGER :: openpmd_file_index, openpmd_call_index
671 IF (
PRESENT(mpi_io))
THEN
672#if defined(__parallel)
673 IF (logger%para_env%num_pe > 1 .AND. mpi_io)
THEN
685 cpassert(
ASSOCIATED(logger))
686 cpassert(basis_section%ref_count > 0)
687 cpassert(logger%ref_count > 0)
689 basis_section, print_key_path, used_print_key=print_key),
cp_p_file)
690 IF (
PRESENT(ignore_should_output)) my_should_output = my_should_output .OR. ignore_should_output
691 IF (.NOT. my_should_output)
RETURN
692 IF (logger%para_env%is_source() .OR. my_mpi_io)
THEN
697 IF (len_trim(openpmd_config) == 0)
THEN
700 openpmd_config =
"@"//openpmd_config
702 filename = cp_print_key_generate_openpmd_filename(logger, print_key, openpmd_basename, file_extension)
704 IF (
PRESENT(fout))
THEN
708 openpmd_file_index = cp_openpmd_get_openpmd_file_entry( &
709 openpmd_basename, filename, openpmd_config, logger, my_mpi_io)
711 OPEN (newunit=res, status=
'scratch', action=
'write')
712 openpmd_call_index = cp_openpmd_add_unit_nr( &
714 cp_openpmd_create_unit_nr_entry( &
715 openpmd_file_index, middle_name, logger))
722 mark_used(basis_section)
723 mark_used(print_key_path)
724 mark_used(middle_name)
725 mark_used(ignore_should_output)
728 mark_used(openpmd_basename)
730 cpabort(
"CP2K compiled without the openPMD-api")
754 print_key_path, local, ignore_should_output, &
756 INTEGER,
INTENT(INOUT) :: unit_nr
759 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: print_key_path
760 LOGICAL,
INTENT(IN),
OPTIONAL :: local, ignore_should_output, &
765 CHARACTER(len=default_string_length) :: outpath
766 LOGICAL :: my_local, my_mpi_io, &
773 IF (
PRESENT(local)) my_local = local
774 IF (
PRESENT(mpi_io)) my_mpi_io = mpi_io
775 cpassert(
ASSOCIATED(logger))
776 cpassert(basis_section%ref_count > 0)
777 cpassert(logger%ref_count > 0)
779 print_key_path, used_print_key=print_key),
cp_p_file)
780 IF (
PRESENT(ignore_should_output)) my_should_output = my_should_output .OR. ignore_should_output
781 IF (my_should_output .AND. (my_local .OR. &
782 logger%para_env%is_source() .OR. &
785 IF (cp_openpmd_remove_unit_nr(unit_nr))
THEN
791 cpassert(unit_nr == -1)
796 mark_used(basis_section)
797 mark_used(print_key_path)
799 mark_used(ignore_should_output)
801 cpabort(
"CP2K compiled without the openPMD-api")
808 TYPE(cp_openpmd_per_callsite_value_type) :: series_data
809 TYPE(openpmd_iteration_type) :: iteration
812 CALL timeset(
'openpmd_close_iterations', handle)
813 DO i = 1, cp_num_openpmd_per_callsite
814 series_data = cp_openpmd_per_callsite(i)%value
815 iteration = series_data%output_series%get_iteration( &
816 series_data%iteration_counter%flat_iteration)
817 IF (.NOT. iteration%closed())
THEN
818 CALL iteration%close()
821 CALL timestop(handle)
826 CHARACTER(len=default_string_length) :: extension
829 extension = openpmd_get_default_extension()
Utility routines to open and close files. Tracking of preconnections.
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Collection of routines to handle the iteration info.
character(len=default_path_length), dimension(18), parameter, public each_possible_labels
subroutine, public cp_iteration_info_retain(iteration_info)
retains the iteration_info (see doc/ReferenceCounting.html)
subroutine, public cp_iteration_info_release(iteration_info)
releases the iteration_info (see doc/ReferenceCounting.html)
character(len=default_path_length), dimension(18), parameter, public each_desc_labels
various routines to log and control the output. The idea is that decisions about where to log should ...
recursive integer function, public cp_logger_get_default_unit_nr(logger, local, skip_not_ionode)
asks the default unit number of the given logger. try to use cp_logger_get_unit_nr
integer function, public cp_logger_get_unit_nr(logger, local)
returns the unit nr for the requested kind of log.
subroutine, public cp_logger_generate_filename(logger, res, root, postfix, local)
generates a unique filename (ie adding eventual suffixes and process ids)
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
subroutine, public cp_openpmd_close_iterations()
character(len=default_string_length) function, public cp_openpmd_get_default_extension()
subroutine, public cp_openpmd_output_finalize()
Close all outputs.
type(cp_openpmd_per_call_value_type) function, public cp_openpmd_get_value_unit_nr(key)
integer function, public cp_openpmd_print_key_unit_nr(logger, basis_section, print_key_path, middle_name, ignore_should_output, mpi_io, fout, openpmd_basename)
...
subroutine, public cp_openpmd_print_key_finished_output(unit_nr, logger, basis_section, print_key_path, local, ignore_should_output, mpi_io)
should be called after you finish working with a unit obtained with cp_openpmd_print_key_unit_nr,...
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer, parameter, public cp_p_file
integer function, public cp_print_key_should_output(iteration_info, basis_section, print_key_path, used_print_key, first_time)
returns what should be done with the given property if btest(res,cp_p_store) then the property should...
Defines the basic variable types.
integer, parameter, public default_string_length
integer, parameter, public default_path_length
Machine interface based on Fortran 2003 and POSIX.
subroutine, public m_mov(source, target)
...
Utility routines for the memory handling.
Interface to the message passing library MPI.
subroutine, public mp_file_delete(filepath, info)
Deletes a file. Auxiliary routine to emulate 'replace' action for mp_file_open. Only the master proce...
subroutine, public mp_file_get_amode(mpi_io, replace, amode, form, action, status, position)
(parallel) Utility routine to determine MPI file access mode based on variables
Utilities for string manipulations.
subroutine, public compress(string, full)
Eliminate multiple space characters in a string. If full is .TRUE., then all spaces are eliminated.
contains the information about the current state of the program to be able to decide if output is nec...
type of a logger, at the moment it contains just a print level starting at which level it should be l...