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) :: outName, outPath, root
415 INTEGER :: my_ind1, my_ind2
419 IF (outpath(1:1) ==
'=')
THEN
420 cpassert(len(outpath) - 1 <= len(filename))
421 filename = outpath(2:)
424 IF (outpath ==
"__STD_OUT__") outpath =
""
425 outname = trim(outpath)
427 my_ind1 = index(outpath,
"/")
428 my_ind2 = len_trim(outpath)
429 IF (my_ind1 /= 0)
THEN
431 DO WHILE (index(outpath(my_ind1 + 1:my_ind2),
"/") /= 0)
432 my_ind1 = index(outpath(my_ind1 + 1:my_ind2),
"/") + my_ind1
434 IF (my_ind1 == my_ind2)
THEN
437 outname = outpath(my_ind1 + 1:my_ind2)
441 IF (.NOT. has_root)
THEN
442 root = trim(logger%iter_info%project_name)
443 ELSE IF (outname ==
"")
THEN
444 root = outpath(1:my_ind1)//trim(logger%iter_info%project_name)
446 root = outpath(1:my_ind1)
449 filename = adjustl(trim(root)//
"_"//trim(openpmd_basename)//trim(extension))
451 END FUNCTION cp_print_key_generate_openpmd_filename
460 FUNCTION cp_advance_iteration_number(logger, openpmd_file)
RESULT(did_advance_iteration)
461 TYPE(cp_logger_type),
POINTER :: logger
462 TYPE(cp_openpmd_per_callsite_value_type) :: openpmd_file
463 LOGICAL :: did_advance_iteration
468 did_advance_iteration = .false.
469 len =
SIZE(logger%iter_info%iteration)
470 IF (len /= openpmd_file%iteration_counter%complex_iteration_depth)
THEN
471 did_advance_iteration = .true.
472 openpmd_file%iteration_counter%complex_iteration_depth = len
473 ALLOCATE (openpmd_file%iteration_counter%complex_iteration(len))
475 did_advance_iteration &
476 = any(openpmd_file%iteration_counter%complex_iteration(1:len) &
477 /= logger%iter_info%iteration(1:len))
480 IF (.NOT. did_advance_iteration)
RETURN
482 openpmd_file%iteration_counter%flat_iteration = openpmd_file%iteration_counter%flat_iteration + 1
483 openpmd_file%iteration_counter%complex_iteration(1:len) &
484 = logger%iter_info%iteration(1:len)
486 END FUNCTION cp_advance_iteration_number
502 FUNCTION cp_openpmd_create_unit_nr_entry(openpmd_file_index, middle_name, logger)
RESULT(res)
503 INTEGER :: openpmd_file_index
504 CHARACTER(len=*),
INTENT(IN) :: middle_name
505 TYPE(cp_logger_type),
POINTER :: logger
506 TYPE(cp_openpmd_per_call_value_type) :: res
508 LOGICAL,
SAVE :: opened_new_iteration = .false.
509 TYPE(openpmd_attributable_type) :: attr
510 TYPE(cp_openpmd_per_callsite_value_type),
POINTER :: opmd
512 opmd => cp_openpmd_per_callsite(openpmd_file_index)%value
514 res%series = opmd%output_series
516 opened_new_iteration = cp_advance_iteration_number(logger, opmd)
518 res%iteration = opmd%output_series%write_iteration(opmd%iteration_counter%flat_iteration)
519 res%name_prefix = trim(middle_name)
521 IF (opened_new_iteration)
THEN
522 attr = res%iteration%as_attributable()
523 CALL attr%set_attribute_vec_int( &
524 "ndim_iteration_index", &
525 opmd%iteration_counter%complex_iteration)
527 END FUNCTION cp_openpmd_create_unit_nr_entry
533 FUNCTION cp_openpmd_get_openpmd_file_entry(openpmd_basename, filename, openpmd_config, logger, use_mpi)
RESULT(file_index)
534 CHARACTER(len=*),
INTENT(IN) :: openpmd_basename, filename, openpmd_config
535 TYPE(cp_logger_type),
POINTER :: logger
537 INTEGER :: file_index
538 CHARACTER(:),
ALLOCATABLE :: merged_config
540 CHARACTER(len=default_string_length),
SAVE :: basename_copied =
' '
541 TYPE(cp_openpmd_per_callsite_value_type) :: emplace_new
544 TYPE(cp_openpmd_per_callsite_value_type) :: series_data
545 TYPE(openpmd_iteration_type) :: iteration
548 basename_copied(1:len_trim(openpmd_basename)) = trim(openpmd_basename)
550 file_index = cp_openpmd_get_index_filedata(basename_copied)
552 CALL timeset(
'openpmd_close_iterations', handle)
553 DO i = 1, cp_num_openpmd_per_callsite
554 IF (i /= file_index)
THEN
555 series_data = cp_openpmd_per_callsite(i)%value
556 iteration = series_data%output_series%get_iteration( &
557 series_data%iteration_counter%flat_iteration)
558 IF (.NOT. iteration%closed())
THEN
559 CALL iteration%close()
563 CALL timestop(handle)
565 IF (file_index /= -1)
RETURN
568 merged_config = openpmd_json_merge(cp_default_backend_config, cp_default_backend_config_non_windows)
570 merged_config = cp_default_backend_config
573 merged_config = openpmd_json_merge(merged_config, openpmd_config, logger%para_env)
574 emplace_new%output_series = openpmd_series_create( &
575 filename, openpmd_access_create, logger%para_env, merged_config)
577 merged_config = openpmd_json_merge(merged_config, openpmd_config)
578 emplace_new%output_series = openpmd_series_create( &
579 filename, openpmd_access_create, config=merged_config)
581 DEALLOCATE (merged_config)
582 file_index = cp_openpmd_add_filedata(basename_copied, emplace_new)
583 END FUNCTION cp_openpmd_get_openpmd_file_entry
585#else ! defined(__OPENPMD)
588 INTEGER,
INTENT(in) :: key
593 cpabort(
"CP2K compiled without the openPMD-api")
605 DO i = 1, cp_num_openpmd_per_callsite
606 DEALLOCATE (cp_openpmd_per_callsite(i)%value%iteration_counter%complex_iteration)
607 CALL cp_openpmd_per_callsite(i)%value%output_series%close()
609 IF (
ALLOCATED(cp_openpmd_per_callsite))
THEN
610 DEALLOCATE (cp_openpmd_per_callsite)
612 cp_num_openpmd_per_callsite = 0
640 middle_name, ignore_should_output, &
642 fout, openpmd_basename)
RESULT(res)
645 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: print_key_path
646 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: middle_name
647 LOGICAL,
INTENT(IN),
OPTIONAL :: ignore_should_output
648 LOGICAL,
INTENT(INOUT),
OPTIONAL :: mpi_io
649 CHARACTER(len=default_path_length),
INTENT(OUT), &
651 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: openpmd_basename
656 CHARACTER(len=default_path_length) :: filename
658 CHARACTER(len=default_string_length) :: openpmd_config, outpath, file_extension
663 INTEGER :: openpmd_file_index, openpmd_call_index
670 IF (
PRESENT(mpi_io))
THEN
671#if defined(__parallel)
672 IF (logger%para_env%num_pe > 1 .AND. mpi_io)
THEN
684 cpassert(
ASSOCIATED(logger))
685 cpassert(basis_section%ref_count > 0)
686 cpassert(logger%ref_count > 0)
688 basis_section, print_key_path, used_print_key=print_key),
cp_p_file)
689 IF (
PRESENT(ignore_should_output)) my_should_output = my_should_output .OR. ignore_should_output
690 IF (.NOT. my_should_output)
RETURN
691 IF (logger%para_env%is_source() .OR. my_mpi_io)
THEN
696 IF (len_trim(openpmd_config) == 0)
THEN
699 openpmd_config =
"@"//trim(openpmd_config)
701 filename = cp_print_key_generate_openpmd_filename(logger, print_key, openpmd_basename, file_extension)
703 IF (
PRESENT(fout))
THEN
707 openpmd_file_index = cp_openpmd_get_openpmd_file_entry( &
708 openpmd_basename, filename, openpmd_config, logger, my_mpi_io)
710 OPEN (newunit=res, status=
'scratch', action=
'write')
711 openpmd_call_index = cp_openpmd_add_unit_nr( &
713 cp_openpmd_create_unit_nr_entry( &
714 openpmd_file_index, middle_name, logger))
721 mark_used(basis_section)
722 mark_used(print_key_path)
723 mark_used(middle_name)
724 mark_used(ignore_should_output)
727 mark_used(openpmd_basename)
729 cpabort(
"CP2K compiled without the openPMD-api")
753 print_key_path, local, ignore_should_output, &
755 INTEGER,
INTENT(INOUT) :: unit_nr
758 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: print_key_path
759 LOGICAL,
INTENT(IN),
OPTIONAL :: local, ignore_should_output, &
764 CHARACTER(len=default_string_length) :: outpath
765 LOGICAL :: my_local, my_mpi_io, &
772 IF (
PRESENT(local)) my_local = local
773 IF (
PRESENT(mpi_io)) my_mpi_io = mpi_io
774 cpassert(
ASSOCIATED(logger))
775 cpassert(basis_section%ref_count > 0)
776 cpassert(logger%ref_count > 0)
778 print_key_path, used_print_key=print_key),
cp_p_file)
779 IF (
PRESENT(ignore_should_output)) my_should_output = my_should_output .OR. ignore_should_output
780 IF (my_should_output .AND. (my_local .OR. &
781 logger%para_env%is_source() .OR. &
784 IF (cp_openpmd_remove_unit_nr(unit_nr))
THEN
790 cpassert(unit_nr == -1)
795 mark_used(basis_section)
796 mark_used(print_key_path)
798 mark_used(ignore_should_output)
800 cpabort(
"CP2K compiled without the openPMD-api")
807 TYPE(cp_openpmd_per_callsite_value_type) :: series_data
808 TYPE(openpmd_iteration_type) :: iteration
811 CALL timeset(
'openpmd_close_iterations', handle)
812 DO i = 1, cp_num_openpmd_per_callsite
813 series_data = cp_openpmd_per_callsite(i)%value
814 iteration = series_data%output_series%get_iteration( &
815 series_data%iteration_counter%flat_iteration)
816 IF (.NOT. iteration%closed())
THEN
817 CALL iteration%close()
820 CALL timestop(handle)
825 CHARACTER(len=default_string_length) :: extension
828 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(19), 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(19), 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...