35 use mpi,
only : mpi_int, mpi_max
59 type(
hashmap_type),
intent(inout) :: diagnostic_generation_frequency
60 logical,
intent(in) :: continuation_run
62 integer :: i, j, number_contents, current_field_index
63 type(
hashset_type) :: writer_field_names, duplicate_field_names
76 do i=1, io_configuration%number_of_writers
78 number_contents=io_configuration%file_writers(i)%number_of_contents
80 writer_entries(i)%filename=io_configuration%file_writers(i)%file_name
82 writer_entries(i)%write_on_terminate=io_configuration%file_writers(i)%write_on_terminate
83 writer_entries(i)%include_in_io_state_write=io_configuration%file_writers(i)%include_in_io_state_write
87 writer_entries(i)%write_on_model_time=io_configuration%file_writers(i)%write_on_model_time
90 writer_entries(i)%write_time_frequency=io_configuration%file_writers(i)%write_time_frequency
93 writer_entries(i)%write_timestep_frequency=io_configuration%file_writers(i)%write_timestep_frequency
96 writer_entries(i)%defined_write_time=io_configuration%file_writers(i)%write_time_frequency
100 do j=1, number_contents
101 if (io_configuration%file_writers(i)%contents(j)%facet_type ==
group_type)
then
103 writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
104 else if (io_configuration%file_writers(i)%contents(j)%facet_type ==
field_type)
then
106 i, j, current_field_index, io_configuration%file_writers(i)%contents(j)%facet_name,
"", writer_field_names, &
107 duplicate_field_names, diagnostic_generation_frequency)
108 else if (io_configuration%file_writers(i)%contents(j)%facet_type ==
io_state_type)
then
113 call c_free(writer_field_names)
114 call c_free(duplicate_field_names)
116 if (continuation_run)
then
133 integer,
intent(in) :: source, data_id
134 character,
dimension(:),
allocatable,
intent(in) :: data_dump
138 character(len=STRING_LENGTH) :: timestep_key
163 type(
hashset_type),
intent(inout),
optional :: field_names
164 type(
hashmap_type),
intent(inout),
optional :: diag_field_names_and_roots
167 character(len=STRING_LENGTH) :: specific_name
168 integer :: i, number_q_fields, expected_io
169 logical :: field_found, expected_here, diagnostics_mode
175 if (
present(field_names))
then
176 field_found=
c_contains(field_names, specific_name)
177 diagnostics_mode=.false.
178 else if (
present(diag_field_names_and_roots))
then
179 field_found=
c_contains(diag_field_names_and_roots, specific_name)
180 if (field_found) expected_io=
c_get_integer(diag_field_names_and_roots, specific_name)
181 diagnostics_mode=.true.
185 if (field_found)
then
186 expected_here=expected_io == -1 .or. expected_io == io_configuration%my_io_rank
193 if (
present(field_names))
then
194 field_found=
c_contains(field_names, specific_name)
195 diagnostics_mode=.false.
196 else if (
present(diag_field_names_and_roots))
then
197 field_found=
c_contains(diag_field_names_and_roots, specific_name)
198 if (field_found) expected_io=
c_get_integer(diag_field_names_and_roots, specific_name)
199 diagnostics_mode=.true.
203 if (field_found)
then
204 expected_here=expected_io == -1 .or. expected_io == io_configuration%my_io_rank
205 number_q_fields=
c_get_integer(io_configuration%dimension_sizing,
"qfields")
206 do i=1, number_q_fields
207 if (
c_size(io_configuration%q_field_names) .ge. i)
then
209 diagnostics_mode, expected_here)
212 diagnostics_mode, expected_here)
223 character(len=*),
intent(in) :: field_name, field_namespace
225 integer :: writer_index, contents_index
240 character(len=*),
intent(in) :: field_name
248 character(len=*),
intent(in) :: field_name
249 logical,
intent(in) :: diagnostics_mode
250 logical,
intent(in),
optional :: expected_here
252 logical :: continue_search
253 integer :: writer_index, contents_index
255 continue_search=.true.
258 do while (continue_search)
259 contents_index=contents_index+1
261 contents_index_point=contents_index)
262 if (continue_search)
then
263 if ((
writer_entries(writer_index)%contents(contents_index)%diagnostic_field .and. diagnostics_mode) .or. &
264 (
writer_entries(writer_index)%contents(contents_index)%prognostic_field .and. .not. diagnostics_mode))
then
265 writer_entries(writer_index)%contents(contents_index)%enabled=.true.
266 if (
present(expected_here))
then
267 writer_entries(writer_index)%contents(contents_index)%expected_here=expected_here
278 type(
list_type),
intent(inout) :: q_provided_field_names
281 logical :: continue_search
282 integer :: writer_index, contents_index, i
283 character(len=STRING_LENGTH) :: search_field, field_name, specific_name
291 search_field=trim(specific_name)//
"_udef"//trim(
conv_to_string(i))
292 field_name=trim(specific_name)//
"_"//trim(
c_next_string(q_field_iterator))
293 continue_search=.true.
296 do while (continue_search)
297 contents_index=contents_index+1
299 contents_index_point=contents_index)
300 if (continue_search)
then
301 writer_entries(writer_index)%contents(contents_index)%field_name=field_name
312 timestep, time, source)
314 character(len=*),
intent(in) :: field_name, field_namespace
315 integer,
intent(in) :: timestep, source
319 integer :: writer_index, contents_index
320 logical :: continue_search
323 class(*),
pointer :: generic
327 field_values%values, timestep, time, source)
329 continue_search=.true.
332 allocate(result_values, source=field_values)
333 generic=>result_values
335 do while (continue_search)
336 contents_index=contents_index+1
338 if (continue_search)
then
339 if (.not.
writer_entries(writer_index)%contents(contents_index)%enabled)
then
340 call log_log(
log_warn,
"Received data for previously un-enabled field '"//&
341 writer_entries(writer_index)%contents(contents_index)%field_name//
"'")
343 writer_entries(writer_index)%contents(contents_index)%enabled=.true.
344 writer_entries(writer_index)%contents(contents_index)%latest_timestep_values=timestep
346 call log_log(
log_debug,
"[WRITE FED VALUE STORE] Storing value for field "//trim(field_name)//
" ts="//&
353 if (
writer_entries(writer_index)%contents(contents_index)%pending_to_write)
then
372 timestep, time, source)
374 character(len=*),
intent(in) :: field_name, field_namespace
375 integer,
intent(in) :: timestep, source
380 integer :: individual_size, index
384 timestep, time, source)
388 else if (source .gt. -1)
then
391 call log_log(
log_warn,
"Can not find Q split field in Q field names or collective field names with source, ignoring")
398 trim(field_name)//
"_"//trim(
c_next_string(iterator)), field_namespace, field_values(index:index+individual_size-1), &
399 timestep, time, source)
400 index=index+individual_size
412 character(len=*),
intent(in) :: field_name
413 integer,
intent(in) :: source
415 class(*),
pointer :: generic
416 integer :: i, monc_index
423 do i=1,
size(generic%dimensions)
438 timestep, time, source)
440 character(len=*),
intent(in) :: field_name, field_namespace
441 integer,
intent(in) :: timestep, source
445 integer :: writer_index, contents_index
446 logical :: continue_search
449 class(*),
pointer :: generic
451 continue_search=.true.
455 do while (continue_search)
456 contents_index=contents_index+1
458 if (continue_search)
then
459 if (.not.
writer_entries(writer_index)%contents(contents_index)%enabled)
then
460 call log_log(
log_warn,
"Received data for previously un-enabled field '"//&
461 writer_entries(writer_index)%contents(contents_index)%field_name//
"'")
463 writer_entries(writer_index)%contents(contents_index)%enabled=.true.
465 writer_entries(writer_index)%contents(contents_index)%time_manipulation_type)))
then
466 allocate(result_values)
467 if (
writer_entries(writer_index)%contents(contents_index)%collective_write .and. source .gt. -1)
then
468 result_values=
writer_entries(writer_index)%contents(contents_index)%time_manipulation(field_values, &
469 writer_entries(writer_index)%contents(contents_index)%output_frequency, &
472 result_values=
writer_entries(writer_index)%contents(contents_index)%time_manipulation(field_values, &
473 writer_entries(writer_index)%contents(contents_index)%output_frequency, &
474 field_name, timestep, time)
476 generic=>result_values
478 writer_entries(writer_index)%contents(contents_index)%time_manipulation_type), generic, .false.)
481 writer_entries(writer_index)%contents(contents_index)%time_manipulation_type))
483 if (
allocated(result_values%values))
then
484 writer_entries(writer_index)%contents(contents_index)%latest_timestep_values=timestep
486 call log_log(
log_debug,
"[WRITE FED VALUE STORE] Storing value for field "//trim(field_name)//
" ts="//&
490 if (
writer_entries(writer_index)%contents(contents_index)%collective_write .and. source .gt. -1)
then
497 if (
writer_entries(writer_index)%contents(contents_index)%pending_to_write)
then
505 call c_free(typed_result_values)
516 integer,
intent(in) :: writer_index, contents_index, source
518 character(len=*),
intent(in) :: lookup_key
520 class(*),
pointer :: generic
527 stored_monc_values=>generic
530 allocate(stored_monc_values)
531 generic=>stored_monc_values
534 generic=>result_values
546 logical :: field_write_success, do_close_num_fields
548 if (specific_field%pending_to_write)
then
550 writer_entry%previous_write_timestep, writer_entry%write_time, writer_entry%previous_write_time, field_write_success)
551 if (field_write_success)
then
557 writer_entry%num_fields_to_write=writer_entry%num_fields_to_write-1
558 do_close_num_fields=writer_entry%num_fields_to_write == 0
560 if (do_close_num_fields)
then
561 call close_diagnostics_file(io_configuration, writer_entry, writer_entry%write_timestep, writer_entry%write_time)
574 timestep, previous_write_timestep, write_time, previous_write_time, field_written)
578 integer,
intent(in) :: timestep, previous_write_timestep
579 real,
intent(in) :: write_time, previous_write_time
580 logical,
intent(out),
optional :: field_written
582 real :: value_to_test, largest_value_found
583 integer :: num_matching
584 logical :: entry_beyond_this_write
588 class(*),
pointer :: generic
591 largest_value_found=0.0
592 entry_beyond_this_write=.false.
594 if (.not.
c_is_empty(specific_field%values_to_write))
then
599 if (specific_field%collective_write)
then
603 multi_monc_entries=>generic
605 if (
c_size(multi_monc_entries%monc_values) .ne. io_configuration%number_of_moncs) cycle
607 if (value_to_test .gt. write_time) entry_beyond_this_write=.true.
608 if (value_to_test .le. write_time .and. value_to_test .gt. previous_write_time)
then
609 num_matching=num_matching+1
610 if (largest_value_found .lt. value_to_test) largest_value_found=value_to_test
615 if (num_matching .gt. 0 .and. (specific_field%ready_to_write(largest_value_found, specific_field%output_frequency, write_time, &
616 specific_field%latest_timestep_values, timestep) .or. entry_beyond_this_write))
then
617 if (.not. specific_field%collective_write .or. .not. specific_field%collective_contiguous_optimisation)
then
618 if (specific_field%issue_write)
then
619 call write_variable(io_configuration, specific_field, writer_entry%filename, timestep, write_time)
621 specific_field%previous_write_time=writer_entry%write_time
623 specific_field%pending_to_write=.false.
624 if (
present(field_written)) field_written=.true.
631 specific_field%pending_to_write=.true.
632 if (
present(field_written)) field_written=.false.
644 integer,
intent(in) :: source, data_id
645 character,
dimension(:),
allocatable,
intent(in) :: data_dump
647 integer :: i, timestep
649 logical :: terminated
676 integer,
intent(in) :: writer_entry_index, timestep
677 real,
intent(in) :: time
678 logical,
intent(in) :: terminated
680 real :: time_difference
682 logical :: issue_write, issue_terminated_write
685 issue_terminated_write=
writer_entries(writer_entry_index)%write_on_terminate .and. terminated
687 time_difference=time-
writer_entries(writer_entry_index)%latest_pending_write_time
688 issue_write=time_difference .ge.
writer_entries(writer_entry_index)%write_time_frequency
690 if (
writer_entries(writer_entry_index)%write_timestep_frequency .gt. 0)
then
691 issue_write=
writer_entries(writer_entry_index)%latest_pending_write_timestep .ne. timestep .and. &
692 mod(timestep,
writer_entries(writer_entry_index)%write_timestep_frequency) == 0
696 issue_terminated_write=issue_terminated_write .and. &
697 writer_entries(writer_entry_index)%latest_pending_write_timestep .ne. timestep
700 if (issue_write .or. issue_terminated_write)
then
702 writer_entries(writer_entry_index)%latest_pending_write_timestep=timestep
710 writer_entries(writer_entry_index)%write_on_terminate .and. terminated)
716 writer_entries(writer_entry_index)%write_on_terminate .and. terminated)
731 integer,
intent(in) :: timestep
732 real,
intent(in) :: time
733 logical,
intent(in) :: terminated_write
735 integer :: i, j, total_outstanding, num_written, total_flds
736 logical :: field_written
737 type(
map_type) :: applicable_time_points
740 do i=1,
size(writer_entry%contents)
741 if (writer_entry%contents(i)%enabled .and. writer_entry%contents(i)%collective_write)
then
742 if (.not. writer_entry%contents(i)%collective_initialised)
then
749 writer_entry%write_time=time
750 writer_entry%write_timestep=timestep
752 call define_netcdf_file(io_configuration, writer_entry, timestep, time, applicable_time_points, terminated_write)
753 call c_free(applicable_time_points)
758 do j=1,
size(writer_entry%contents)
759 if (writer_entry%contents(j)%enabled .and. writer_entry%contents(j)%expected_here)
then
760 total_flds=total_flds+1
762 writer_entry%previous_write_timestep, time, writer_entry%contents(j)%previous_write_time, field_written)
763 if (.not. field_written)
then
764 total_outstanding=total_outstanding+1
766 num_written=num_written+1
770 writer_entry%num_fields_to_write=total_outstanding
777 if (total_outstanding == 0)
then
790 logical :: remove_timepoint
797 remove_timepoint=.true.
800 remove_timepoint=.false.
807 if (remove_timepoint)
call c_add_string(removed_entries, map_entry%key)
814 call c_free(removed_entries)
823 real,
intent(in) :: start_time, end_time
834 if (time_entry .gt. start_time .and. time_entry .le. end_time)
then
847 type(map_type),
intent(inout) :: unsorted_timepoints
849 integer :: i, entries, specific_ts, smallest_ts
850 character(len=STRING_LENGTH) :: smallest_key
851 real(kind=default_precision) :: rvalue
852 type(iterator_type) :: iterator
853 type(mapentry_type) :: map_entry
855 entries=c_size(unsorted_timepoints)
858 iterator=c_get_iterator(unsorted_timepoints)
859 do while (c_has_next(iterator))
860 map_entry=c_next_mapentry(iterator)
861 specific_ts=conv_to_integer(map_entry%key)
862 if (len_trim(smallest_key) == 0 .or. smallest_ts .gt. specific_ts)
then
863 smallest_ts=specific_ts
864 smallest_key=map_entry%key
865 rvalue=c_get_real(map_entry)
869 call c_remove(unsorted_timepoints, smallest_key)
871 call c_free(unsorted_timepoints)
881 type(io_configuration_type),
intent(inout) :: io_configuration
882 type(writer_type),
intent(inout) :: writer_entry
883 integer,
intent(in) :: timestep
884 real,
intent(in) :: time
886 if (log_get_logging_level() .ge. log_debug)
then
887 call log_log(log_debug,
"Issue close for NetCDF file at timestep "//trim(conv_to_string(timestep)))
900 type(io_configuration_type),
intent(inout) :: io_configuration
901 real(DEFAULT_PRECISION),
dimension(:) :: values
902 character(len=STRING_LENGTH) :: field_name
905 type(writer_type),
pointer :: writer_entry
907 logical :: terminated, done_chain_run
909 writer_entry=>get_writer_entry_from_netcdf(field_name, timestep, terminated)
911 do i=1,
size(writer_entry%contents)
912 if (writer_entry%contents(i)%enabled .and. writer_entry%contents(i)%collective_write .and. &
913 writer_entry%contents(i)%collective_contiguous_optimisation)
then
914 call check_thread_status(forthread_mutex_lock(writer_entry%contents(i)%values_mutex))
915 call write_variable(io_configuration, writer_entry%contents(i), writer_entry%filename, timestep, writer_entry%write_time)
916 writer_entry%contents(i)%previous_write_time=writer_entry%write_time
917 call check_thread_status(forthread_mutex_unlock(writer_entry%contents(i)%values_mutex))
921 writer_entry%previous_write_time=writer_entry%write_time
922 writer_entry%previous_write_timestep=writer_entry%write_timestep
923 writer_entry%defined_write_time=writer_entry%defined_write_time+writer_entry%write_time_frequency
927 if (writer_entry%contains_io_status_dump)
then
928 if (.not. terminated)
then
929 do while (.not. is_io_server_state_writer_ready(timestep))
937 call close_netcdf_file(io_configuration, field_name, timestep)
939 done_chain_run=.false.
943 if (done_chain_run)
exit
948 if (.not. done_chain_run)
then
952 if (log_get_logging_level() .ge. log_debug)
then
953 call log_log(log_debug,
"No more pending entries to chain to at ts= "//trim(conv_to_string(timestep)))
963 type(io_configuration_type),
intent(inout) :: io_configuration
964 type(writer_type),
intent(inout) :: writer_entry
966 class(*),
pointer :: generic
968 call check_thread_status(forthread_mutex_lock(writer_entry%pending_writes_mutex))
969 if (.not. c_is_empty(writer_entry%pending_writes))
then
971 generic=>c_pop_generic(writer_entry%pending_writes)
972 call check_thread_status(forthread_mutex_unlock(writer_entry%pending_writes_mutex))
974 type is (pending_write_type)
975 if (log_get_logging_level() .ge. log_debug)
then
976 call log_log(log_debug,
"Chain to next pending entry ts= "//trim(conv_to_string(generic%timestep)))
979 generic%write_time, generic%terminated_write)
984 call check_thread_status(forthread_mutex_unlock(writer_entry%pending_writes_mutex))
993 integer,
intent(in) :: writer_entry_index, timestep
994 real,
intent(in) :: time
995 logical,
intent(in) :: terminated_write
997 type(pending_write_type),
pointer :: pending_write
998 class(*),
pointer :: generic
1000 allocate(pending_write)
1001 pending_write%write_time=time
1002 pending_write%timestep=timestep
1003 pending_write%terminated_write=terminated_write
1005 generic=>pending_write
1006 call check_thread_status(forthread_mutex_lock(
writer_entries(writer_entry_index)%pending_writes_mutex))
1007 call c_push_generic(
writer_entries(writer_entry_index)%pending_writes, generic, .false.)
1008 call check_thread_status(forthread_mutex_unlock(
writer_entries(writer_entry_index)%pending_writes_mutex))
1018 character(len=*),
intent(in) :: field_name
1019 character(len=*),
intent(in),
optional :: field_namespace
1020 integer,
intent(inout) :: writer_index_point, contents_index_point
1026 if (contents_index_point .le.
size(
writer_entries(i)%contents))
then
1029 if (
present(field_namespace))
then
1030 if (
writer_entries(i)%contents(j)%field_namespace .ne. field_namespace) cycle
1032 writer_index_point=i
1033 contents_index_point=j
1039 contents_index_point=1
1051 type(io_configuration_type),
intent(inout) :: io_configuration
1052 integer,
intent(in) :: writer_entry_index
1054 integer :: i, number_contents, group_index, number_q_fields
1057 number_q_fields=c_get_integer(io_configuration%dimension_sizing,
"qfields")
1059 number_contents=io_configuration%file_writers(writer_entry_index)%number_of_contents
1060 do i=1, number_contents
1061 if (io_configuration%file_writers(writer_entry_index)%contents(i)%facet_type == group_type)
then
1063 io_configuration%file_writers(writer_entry_index)%contents(i)%facet_name)
1064 if (group_index == 0)
call log_log(log_error,
"Can not find group '"//trim(&
1065 io_configuration%file_writers(writer_entry_index)%contents(i)%facet_name)//
"'")
1068 io_configuration%groups(group_index)%namespace)
1069 else if (io_configuration%file_writers(writer_entry_index)%contents(i)%facet_type == field_type)
then
1072 io_configuration%file_writers(writer_entry_index)%contents(i)%facet_name,
"", number_q_fields)
1083 type(io_configuration_type),
intent(inout) :: io_configuration
1084 type(list_type) :: group_members
1085 integer,
intent(in) :: num_q_fields
1086 character(len=STRING_LENGTH),
intent(in) :: namespace
1088 type(iterator_type) :: iterator
1089 character(len=STRING_LENGTH) :: field_name
1092 iterator=c_get_iterator(group_members)
1093 do while (c_has_next(iterator))
1094 field_name=c_next_string(iterator)
1107 type(io_configuration_type),
intent(inout) :: io_configuration
1108 character(len=STRING_LENGTH),
intent(in) :: field_name, field_namespace
1109 integer,
intent(in) :: num_q_fields
1111 type(io_configuration_field_type) :: prognostic_field_configuration
1112 type(io_configuration_data_definition_type) :: prognostic_containing_data_defn
1113 type(io_configuration_diagnostic_field_type) :: diagnostic_field_configuration
1115 if (get_diagnostic_field_configuration(io_configuration, field_name, field_namespace, diagnostic_field_configuration))
then
1116 if (diagnostic_field_configuration%field_type == array_field_type)
then
1117 if (diagnostic_field_configuration%dim_size_defns(diagnostic_field_configuration%dimensions) .eq.
"qfields")
then
1123 else if (get_prognostic_field_configuration(io_configuration, field_name, field_namespace, &
1124 prognostic_field_configuration, prognostic_containing_data_defn))
then
1125 if (prognostic_field_configuration%field_type == array_field_type)
then
1126 if (prognostic_field_configuration%dim_size_defns(prognostic_field_configuration%dimensions) .eq.
"qfields")
then
1143 writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
1144 type(io_configuration_type),
intent(inout) :: io_configuration
1145 integer,
intent(in) :: writer_entry_index, facet_index, current_field_index
1146 type(hashset_type),
intent(inout) :: writer_field_names, duplicate_field_names
1147 type(hashmap_type),
intent(inout) :: diagnostic_generation_frequency
1149 integer :: group_index
1150 character(len=STRING_LENGTH) :: field_name
1151 type(iterator_type) :: iterator
1155 io_configuration%file_writers(writer_entry_index)%contents(facet_index)%facet_name)
1156 if (group_index == 0)
then
1157 call log_log(log_error,
"Can not find group '"//&
1158 trim(io_configuration%file_writers(writer_entry_index)%contents(facet_index)%facet_name)//
"' in the configuration")
1160 iterator=c_get_iterator(io_configuration%groups(group_index)%members)
1161 do while (c_has_next(iterator))
1162 field_name=c_next_string(iterator)
1165 io_configuration%groups(group_index)%namespace, writer_field_names, duplicate_field_names, &
1166 diagnostic_generation_frequency)
1182 my_facet_index, field_name, field_namespace, writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
1183 type(io_configuration_type),
intent(inout) :: io_configuration
1184 integer,
intent(in) :: writer_entry_index, io_config_facet_index, my_facet_index
1185 character(len=*),
intent(in) :: field_name, field_namespace
1186 type(hashset_type),
intent(inout) :: writer_field_names, duplicate_field_names
1187 type(hashmap_type),
intent(inout) :: diagnostic_generation_frequency
1189 integer :: i, number_q_fields, tot_size
1190 type(io_configuration_field_type) :: prognostic_field_configuration
1191 type(io_configuration_data_definition_type) :: prognostic_containing_data_defn
1192 type(io_configuration_diagnostic_field_type) :: diagnostic_field_configuration
1193 type(collective_q_field_representation_type),
pointer :: collective_q_field
1194 class(*),
pointer :: generic
1196 if (get_diagnostic_field_configuration(io_configuration, field_name, field_namespace, diagnostic_field_configuration))
then
1197 if (diagnostic_field_configuration%field_type == array_field_type)
then
1198 if (diagnostic_field_configuration%dim_size_defns(diagnostic_field_configuration%dimensions) .eq.
"qfields")
then
1199 number_q_fields=c_get_integer(io_configuration%dimension_sizing,
"qfields")
1200 do i=1, number_q_fields
1202 my_facet_index+i, trim(field_name)//
"_udef"//trim(conv_to_string(i)), field_namespace, writer_field_names, &
1203 duplicate_field_names, c_get_integer(diagnostic_generation_frequency, field_name), diagnostic_field_configuration)
1206 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions
1207 tot_size=tot_size*
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%actual_dim_size(i)
1215 my_facet_index+1, field_name, field_namespace, writer_field_names, duplicate_field_names, &
1216 c_get_integer(diagnostic_generation_frequency, field_name), diagnostic_field_configuration)
1218 else if (get_prognostic_field_configuration(io_configuration, field_name, field_namespace, &
1219 prognostic_field_configuration, prognostic_containing_data_defn))
then
1220 if (prognostic_field_configuration%field_type == array_field_type)
then
1221 if (prognostic_field_configuration%dim_size_defns(prognostic_field_configuration%dimensions) .eq.
"qfields")
then
1222 number_q_fields=c_get_integer(io_configuration%dimension_sizing,
"qfields")
1223 do i=1, number_q_fields
1225 my_facet_index+i, trim(field_name)//
"_udef"//trim(conv_to_string(i)), field_namespace, writer_field_names, &
1226 duplicate_field_names, prognostic_containing_data_defn%frequency, &
1227 prognostic_field_configuration=prognostic_field_configuration)
1229 if (prognostic_field_configuration%collective)
then
1230 allocate(collective_q_field)
1231 allocate(collective_q_field%dimensions(&
1232 writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions))
1233 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions
1234 if (trim(
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dim_size_defns(i)) ==
"z")
then
1235 collective_q_field%dimensions(i)=1
1236 else if (trim(
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dim_size_defns(i)) &
1238 collective_q_field%dimensions(i)=2
1239 else if (trim(
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dim_size_defns(i)) &
1241 collective_q_field%dimensions(i)=3
1244 generic=>collective_q_field
1248 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions
1249 tot_size=tot_size*
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%actual_dim_size(i)
1259 my_facet_index+1, field_name, field_namespace, writer_field_names, duplicate_field_names, &
1260 prognostic_containing_data_defn%frequency, prognostic_field_configuration=prognostic_field_configuration)
1263 call log_log(log_error,
"Field '"//trim(field_name)//&
1264 "' configured for file write but can not find this as a prognostic or diagnostic definition")
1280 my_facet_index, field_name, field_namespace, writer_field_names, duplicate_field_names, timestep_frequency, &
1281 diagnostic_field_configuration, prognostic_field_configuration)
1282 type(io_configuration_type),
intent(inout) :: io_configuration
1283 integer,
intent(in) :: writer_entry_index, io_config_facet_index, my_facet_index, timestep_frequency
1284 character(len=*),
intent(in) :: field_name, field_namespace
1285 type(hashset_type),
intent(inout) :: writer_field_names, duplicate_field_names
1286 type(io_configuration_diagnostic_field_type),
intent(inout),
optional :: diagnostic_field_configuration
1287 type(io_configuration_field_type),
intent(inout),
optional :: prognostic_field_configuration
1291 writer_entries(writer_entry_index)%contents(my_facet_index)%field_name=field_name
1292 writer_entries(writer_entry_index)%contents(my_facet_index)%field_namespace=field_namespace
1296 if (.not. c_contains(writer_field_names, field_name))
then
1297 call c_add_string(writer_field_names,
writer_entries(writer_entry_index)%contents(my_facet_index)%field_name)
1299 call c_add_string(duplicate_field_names,
writer_entries(writer_entry_index)%contents(my_facet_index)%field_name)
1302 if (io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type == &
1303 instantaneous_type)
then
1304 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation=>perform_instantaneous_time_manipulation
1305 writer_entries(writer_entry_index)%contents(my_facet_index)%ready_to_write=>is_instantaneous_time_manipulation_ready_to_write
1306 else if (io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type == &
1307 time_averaged_type)
then
1308 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation=>perform_timeaveraged_time_manipulation
1309 writer_entries(writer_entry_index)%contents(my_facet_index)%ready_to_write=>is_time_averaged_time_manipulation_ready_to_write
1310 else if (io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type == &
1312 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation=>perform_none_time_manipulation
1313 writer_entries(writer_entry_index)%contents(my_facet_index)%ready_to_write=>is_none_time_manipulation_ready_to_write
1315 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation_type=&
1316 io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type
1317 writer_entries(writer_entry_index)%contents(my_facet_index)%output_frequency=&
1318 io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%output_time_frequency
1319 writer_entries(writer_entry_index)%contents(my_facet_index)%previous_write_time=0.0
1320 writer_entries(writer_entry_index)%contents(my_facet_index)%previous_tracked_write_point=0.0
1321 writer_entries(writer_entry_index)%contents(my_facet_index)%duplicate_field_name=.false.
1322 writer_entries(writer_entry_index)%contents(my_facet_index)%pending_to_write=.false.
1323 writer_entries(writer_entry_index)%contents(my_facet_index)%enabled=.false.
1324 writer_entries(writer_entry_index)%contents(my_facet_index)%expected_here=.true.
1325 writer_entries(writer_entry_index)%contents(my_facet_index)%prognostic_field=.false.
1326 writer_entries(writer_entry_index)%contents(my_facet_index)%diagnostic_field=.false.
1328 if (
present(diagnostic_field_configuration))
then
1329 writer_entries(writer_entry_index)%contents(my_facet_index)%timestep_frequency=timestep_frequency
1330 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=diagnostic_field_configuration%dimensions
1331 writer_entries(writer_entry_index)%contents(my_facet_index)%data_type=diagnostic_field_configuration%data_type
1332 writer_entries(writer_entry_index)%contents(my_facet_index)%field_type=diagnostic_field_configuration%field_type
1333 writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns=diagnostic_field_configuration%dim_size_defns
1334 writer_entries(writer_entry_index)%contents(my_facet_index)%units=diagnostic_field_configuration%units
1335 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_write=diagnostic_field_configuration%collective
1336 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_initialised=.false.
1337 writer_entries(writer_entry_index)%contents(my_facet_index)%issue_write=.true.
1338 writer_entries(writer_entry_index)%contents(my_facet_index)%diagnostic_field=.true.
1339 else if (
present(prognostic_field_configuration))
then
1340 writer_entries(writer_entry_index)%contents(my_facet_index)%timestep_frequency=timestep_frequency
1341 writer_entries(writer_entry_index)%contents(my_facet_index)%data_type=prognostic_field_configuration%data_type
1342 writer_entries(writer_entry_index)%contents(my_facet_index)%field_type=prognostic_field_configuration%field_type
1343 writer_entries(writer_entry_index)%contents(my_facet_index)%units=prognostic_field_configuration%units
1344 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=prognostic_field_configuration%dimensions
1345 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_write=prognostic_field_configuration%collective
1346 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_initialised=.false.
1347 writer_entries(writer_entry_index)%contents(my_facet_index)%prognostic_field=.true.
1348 if (.not. prognostic_field_configuration%collective)
then
1349 writer_entries(writer_entry_index)%contents(my_facet_index)%issue_write=io_configuration%my_io_rank==0
1351 writer_entries(writer_entry_index)%contents(my_facet_index)%issue_write=.true.
1353 if (prognostic_field_configuration%field_type == array_field_type .or. &
1354 prognostic_field_configuration%field_type == map_field_type)
then
1355 if (prognostic_field_configuration%dimensions .gt. 0)
then
1356 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=prognostic_field_configuration%dimensions
1357 writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns=&
1358 prognostic_field_configuration%dim_size_defns
1360 call log_log(log_error,
"The writing prognostic field '"//trim(field_name)//
"' configuration must have dimensions")
1364 call log_log(log_error,
"A diagnostic or prognostic configuration for the field '"//trim(field_name)//
"' was not found")
1366 if (
writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions .gt. 0)
then
1367 if (
writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns(&
1368 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions) .eq.
"qfields")
then
1369 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=&
1370 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions-1
1372 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions
1373 writer_entries(writer_entry_index)%contents(my_facet_index)%actual_dim_size(i)=c_get_integer(&
1374 io_configuration%dimension_sizing,
writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns(i))
1377 call check_thread_status(forthread_mutex_init(
writer_entries(writer_entry_index)%contents(my_facet_index)%values_mutex, -1))
1385 type(writer_type),
intent(inout) :: writer_entry
1386 type(hashset_type),
intent(inout) :: duplicate_field_names
1390 do i=1,
size(writer_entry%contents)
1391 if (c_contains(duplicate_field_names, writer_entry%contents(i)%field_name))
then
1392 writer_entry%contents(i)%duplicate_field_name=.true.
1403 type(io_configuration_type),
intent(inout) :: io_configuration
1404 character(len=*),
intent(in) :: group_name
1406 integer :: i, entries
1408 entries=io_configuration%number_of_groups
1410 if (io_configuration%groups(i)%name == group_name)
then
1424 type(io_configuration_type),
intent(inout) :: io_configuration
1425 type(writer_field_type),
intent(inout) :: field_to_write_information
1427 if (field_to_write_information%dimensions .eq. 3 .and. &
1431 field_to_write_information%collective_contiguous_optimisation=.true.
1434 field_to_write_information%collective_contiguous_optimisation=.false.
1436 field_to_write_information%collective_initialised=.true.
1445 type(io_configuration_type),
intent(inout) :: io_configuration
1446 type(writer_field_type),
intent(inout) :: field_to_write_information
1448 integer :: start(field_to_write_information%dimensions, io_configuration%number_of_moncs), &
1449 count(field_to_write_information%dimensions, io_configuration%number_of_moncs), &
1450 common_starters(io_configuration%number_of_moncs), num_common, num_current_contents, active_dim, other_dim, &
1451 j, k, i, dim_identifier, number_distinct_writes, start_blocks(io_configuration%number_of_moncs), ierr, &
1452 count_blocks(io_configuration%number_of_moncs), current_contents(io_configuration%number_of_moncs), &
1453 monc_write_start_offset_per_dim(field_to_write_information%dimensions,io_configuration%number_of_moncs)
1454 logical :: processed(io_configuration%number_of_moncs)
1456 type(write_field_collective_descriptor_type),
pointer :: collective_descriptor
1457 type(write_field_collective_monc_info_type),
pointer :: specific_monc_collective
1458 class(*),
pointer :: generic
1461 number_distinct_writes=0
1462 do j=1, io_configuration%number_of_moncs
1463 do k=1, field_to_write_information%dimensions
1465 start(k, j)=io_configuration%registered_moncs(j)%local_dim_starts(dim_identifier)
1466 count(k, j)=io_configuration%registered_moncs(j)%local_dim_sizes(dim_identifier)
1470 do j=1, io_configuration%number_of_moncs
1471 if (.not. processed(j))
then
1472 call get_common_starts(y_index, start(y_index, j), start, common_starters, num_common)
1473 if (num_common == 0)
then
1474 call get_common_starts(x_index, start(x_index, j), start, common_starters, num_common)
1475 if (num_common .gt. 0)
then
1483 number_distinct_writes=number_distinct_writes+1
1484 allocate(collective_descriptor)
1485 allocate(collective_descriptor%absolute_start(field_to_write_information%dimensions), &
1486 collective_descriptor%count(field_to_write_information%dimensions))
1487 start_blocks(number_distinct_writes)=start(other_dim, j)
1488 count_blocks(number_distinct_writes)=count(other_dim, j)
1489 num_current_contents=1
1490 current_contents(num_current_contents)=j
1492 if (num_common .gt. 0)
then
1495 if (.not. processed(common_starters(i)) .and. count(active_dim, j) == count(active_dim, i))
then
1496 if (start(other_dim, common_starters(i)) .lt. start_blocks(number_distinct_writes) .and. &
1497 start(other_dim, common_starters(i)) + count(other_dim, common_starters(i)) &
1498 == start_blocks(number_distinct_writes))
then
1499 start_blocks(number_distinct_writes)=start(other_dim, common_starters(i))
1500 count_blocks(number_distinct_writes)=count_blocks(number_distinct_writes)+count(other_dim, common_starters(i))
1501 processed(common_starters(i))=.true.
1502 num_current_contents=num_current_contents+1
1503 current_contents(num_current_contents)=common_starters(i)
1504 else if (start(other_dim, common_starters(i)) .gt. start_blocks(number_distinct_writes) .and. &
1505 start_blocks(number_distinct_writes) + count_blocks(number_distinct_writes) &
1506 == start(other_dim, common_starters(i)))
then
1507 count_blocks(number_distinct_writes)=count_blocks(number_distinct_writes)+count(other_dim, common_starters(i))
1508 processed(common_starters(i))=.true.
1509 num_current_contents=num_current_contents+1
1510 current_contents(num_current_contents)=common_starters(i)
1516 collective_descriptor%absolute_start=start(:,j)
1517 collective_descriptor%count=count(:,j)
1518 collective_descriptor%absolute_start(other_dim)=start_blocks(number_distinct_writes)
1519 collective_descriptor%count(other_dim)=count_blocks(number_distinct_writes)
1520 collective_descriptor%split_dim=other_dim
1521 if (num_current_contents .gt. 0)
then
1522 do k=1, num_current_contents
1523 allocate(specific_monc_collective)
1524 specific_monc_collective%relative_dimension_start=(start(other_dim,current_contents(k))-&
1525 start_blocks(number_distinct_writes)) + 1
1526 specific_monc_collective%counts=count(:, current_contents(k))
1527 specific_monc_collective%monc_location=current_contents(k)
1528 specific_monc_collective%monc_source=io_configuration%registered_moncs(current_contents(k))%source_id
1529 generic=>specific_monc_collective
1530 call c_add_generic(collective_descriptor%specific_monc_info, generic, .false.)
1533 generic=>collective_descriptor
1534 call c_add_generic(field_to_write_information%collective_descriptors, generic, .false.)
1538 call mpi_iallreduce(number_distinct_writes, field_to_write_information%max_num_collective_writes, 1, mpi_int, mpi_max, &
1539 io_configuration%io_communicator, field_to_write_information%max_num_collective_writes_request_handle, ierr)
1550 integer,
intent(in) :: dim, val
1551 integer,
dimension(:,:),
intent(in) :: vals
1552 integer,
dimension(:),
intent(out) :: common_starters
1553 integer,
intent(out) :: num_common
1558 do i=1,
size(vals, 2)
1559 if (vals(dim, i) == val)
then
1560 num_common=num_common+1
1561 common_starters(num_common)=i
1571 character(len=*),
intent(in) :: dim_name
1572 logical,
intent(out),
optional :: is_auto_dimension
1575 logical :: is_modified_size
1577 dash_idx=index(dim_name,
"_")
1579 is_modified_size=dash_idx .ne. -1
1580 if (.not. is_modified_size) dash_idx=len_trim(dim_name)
1582 if (dim_name(:dash_idx) .eq.
"z" .or. dim_name(:dash_idx) .eq.
"zn")
then
1584 else if (dim_name(:dash_idx) .eq.
"y")
then
1586 else if (dim_name(:dash_idx) .eq.
"x")
then
1592 if (
present(is_auto_dimension)) is_auto_dimension=is_modified_size