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
136 real(kind=DEFAULT_PRECISION) :: time
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
317 real(kind=DEFAULT_PRECISION),
intent(in) :: time
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
376 real(kind=DEFAULT_PRECISION),
dimension(:),
intent(in) :: field_values
377 real(kind=DEFAULT_PRECISION),
intent(in) :: time
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
442 real(kind=DEFAULT_PRECISION),
dimension(:),
intent(in) :: field_values
443 real(kind=DEFAULT_PRECISION),
intent(in) :: time
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
587 class(*),
pointer :: generic
590 largest_value_found=0.0
592 if (.not.
c_is_empty(specific_field%values_to_write))
then 597 if (specific_field%collective_write)
then 601 multi_monc_entries=>generic
603 if (
c_size(multi_monc_entries%monc_values) .ne. io_configuration%number_of_moncs) cycle
605 if (value_to_test .le. write_time .and. value_to_test .gt. previous_write_time)
then 606 num_matching=num_matching+1
607 if (largest_value_found .lt. value_to_test) largest_value_found=value_to_test
612 if (num_matching .gt. 0 .and. specific_field%ready_to_write(largest_value_found, specific_field%output_frequency, write_time, &
613 specific_field%latest_timestep_values, timestep))
then 614 if (.not. specific_field%collective_write .or. .not. specific_field%collective_contiguous_optimisation)
then 615 if (specific_field%issue_write)
then 616 call write_variable(io_configuration, specific_field, writer_entry%filename, timestep, write_time)
618 specific_field%previous_write_time=writer_entry%write_time
620 specific_field%pending_to_write=.false.
621 if (
present(field_written)) field_written=.true.
628 specific_field%pending_to_write=.true.
629 if (
present(field_written)) field_written=.false.
641 integer,
intent(in) :: source, data_id
642 character,
dimension(:),
allocatable,
intent(in) :: data_dump
644 integer :: i, timestep
645 real(kind=DEFAULT_PRECISION) :: time
646 logical :: terminated
671 subroutine check_writer_trigger(io_configuration, writer_entry_index, timestep, time, terminated)
673 integer,
intent(in) :: writer_entry_index, timestep
674 real,
intent(in) :: time
675 logical,
intent(in) :: terminated
677 real :: time_difference
679 logical :: issue_write, issue_terminated_write
682 issue_terminated_write=
writer_entries(writer_entry_index)%write_on_terminate .and. terminated
684 time_difference=time-
writer_entries(writer_entry_index)%latest_pending_write_time
685 issue_write=time_difference .ge.
writer_entries(writer_entry_index)%write_time_frequency
687 if (
writer_entries(writer_entry_index)%write_timestep_frequency .gt. 0)
then 688 issue_write=
writer_entries(writer_entry_index)%latest_pending_write_timestep .ne. timestep .and. &
689 mod(timestep,
writer_entries(writer_entry_index)%write_timestep_frequency) == 0
693 issue_terminated_write=issue_terminated_write .and. &
694 writer_entries(writer_entry_index)%latest_pending_write_timestep .ne. timestep
697 if (issue_write .or. issue_terminated_write)
then 699 writer_entries(writer_entry_index)%latest_pending_write_timestep=timestep
707 writer_entries(writer_entry_index)%write_on_terminate .and. terminated)
713 writer_entries(writer_entry_index)%write_on_terminate .and. terminated)
725 subroutine issue_actual_write(io_configuration, writer_entry, timestep, time, terminated_write)
728 integer,
intent(in) :: timestep
729 real,
intent(in) :: time
730 logical,
intent(in) :: terminated_write
732 integer :: i, j, total_outstanding, num_written, total_flds
733 logical :: field_written
734 type(
map_type) :: applicable_time_points
737 do i=1,
size(writer_entry%contents)
738 if (writer_entry%contents(i)%enabled .and. writer_entry%contents(i)%collective_write)
then 739 if (.not. writer_entry%contents(i)%collective_initialised)
then 746 writer_entry%write_time=time
747 writer_entry%write_timestep=timestep
749 call define_netcdf_file(io_configuration, writer_entry, timestep, time, applicable_time_points, terminated_write)
750 call c_free(applicable_time_points)
755 do j=1,
size(writer_entry%contents)
756 if (writer_entry%contents(j)%enabled .and. writer_entry%contents(j)%expected_here)
then 757 total_flds=total_flds+1
759 writer_entry%previous_write_timestep, time, writer_entry%contents(j)%previous_write_time, field_written)
760 if (.not. field_written)
then 761 total_outstanding=total_outstanding+1
763 num_written=num_written+1
767 writer_entry%num_fields_to_write=total_outstanding
774 if (total_outstanding == 0)
then 783 type(
map_type) function extract_applicable_time_points(start_time, end_time)
784 real,
intent(in) :: start_time, end_time
795 if (time_entry .gt. start_time .and. time_entry .le. end_time)
then 807 type(
map_type) function sort_applicable_time_points(unsorted_timepoints)
808 type(
map_type),
intent(inout) :: unsorted_timepoints
810 integer :: i, entries, specific_ts, smallest_ts
811 character(len=STRING_LENGTH) :: smallest_key
812 real(kind=DEFAULT_PRECISION) :: rvalue
816 entries=
c_size(unsorted_timepoints)
823 if (len_trim(smallest_key) == 0 .or. smallest_ts .gt. specific_ts)
then 824 smallest_ts=specific_ts
825 smallest_key=map_entry%key
829 call c_put_real(sort_applicable_time_points, smallest_key, rvalue)
830 call c_remove(unsorted_timepoints, smallest_key)
832 call c_free(unsorted_timepoints)
844 integer,
intent(in) :: timestep
845 real,
intent(in) :: time
847 if (log_get_logging_level() .ge. log_debug)
then 862 real(DEFAULT_PRECISION),
dimension(:) :: values
863 character(len=STRING_LENGTH) :: field_name
868 logical :: terminated, done_chain_run
870 writer_entry=>get_writer_entry_from_netcdf(field_name, timestep, terminated)
872 do i=1,
size(writer_entry%contents)
873 if (writer_entry%contents(i)%enabled .and. writer_entry%contents(i)%collective_write .and. &
874 writer_entry%contents(i)%collective_contiguous_optimisation)
then 875 call check_thread_status(forthread_mutex_lock(writer_entry%contents(i)%values_mutex))
876 call write_variable(io_configuration, writer_entry%contents(i), writer_entry%filename, timestep, writer_entry%write_time)
877 writer_entry%contents(i)%previous_write_time=writer_entry%write_time
878 call check_thread_status(forthread_mutex_unlock(writer_entry%contents(i)%values_mutex))
882 writer_entry%previous_write_time=writer_entry%write_time
883 writer_entry%previous_write_timestep=writer_entry%write_timestep
884 writer_entry%defined_write_time=writer_entry%defined_write_time+writer_entry%write_time_frequency
886 if (writer_entry%contains_io_status_dump)
then 887 if (.not. terminated)
then 888 do while (.not. is_io_server_state_writer_ready(timestep))
896 call close_netcdf_file(io_configuration, field_name, timestep)
898 done_chain_run=.false.
902 if (done_chain_run)
exit 907 if (.not. done_chain_run)
then 911 if (log_get_logging_level() .ge. log_debug)
then 912 call log_log(log_debug,
"No more pending entries to chain to at ts= "//trim(
conv_to_string(timestep)))
925 class(*),
pointer :: generic
927 call check_thread_status(forthread_mutex_lock(writer_entry%pending_writes_mutex))
928 if (.not.
c_is_empty(writer_entry%pending_writes))
then 931 call check_thread_status(forthread_mutex_unlock(writer_entry%pending_writes_mutex))
934 if (log_get_logging_level() .ge. log_debug)
then 938 generic%write_time, generic%terminated_write)
943 call check_thread_status(forthread_mutex_unlock(writer_entry%pending_writes_mutex))
952 integer,
intent(in) :: writer_entry_index, timestep
953 real,
intent(in) :: time
954 logical,
intent(in) :: terminated_write
957 class(*),
pointer :: generic
959 allocate(pending_write)
960 pending_write%write_time=time
961 pending_write%timestep=timestep
962 pending_write%terminated_write=terminated_write
964 generic=>pending_write
965 call check_thread_status(forthread_mutex_lock(
writer_entries(writer_entry_index)%pending_writes_mutex))
967 call check_thread_status(forthread_mutex_unlock(
writer_entries(writer_entry_index)%pending_writes_mutex))
977 character(len=*),
intent(in) :: field_name
978 character(len=*),
intent(in),
optional :: field_namespace
979 integer,
intent(inout) :: writer_index_point, contents_index_point
985 if (contents_index_point .le.
size(
writer_entries(i)%contents))
then 988 if (
present(field_namespace))
then 989 if (
writer_entries(i)%contents(j)%field_namespace .ne. field_namespace) cycle
992 contents_index_point=j
998 contents_index_point=1
1011 integer,
intent(in) :: writer_entry_index
1013 integer :: i, number_contents, group_index, number_q_fields
1016 number_q_fields=
c_get_integer(io_configuration%dimension_sizing,
"qfields")
1018 number_contents=io_configuration%file_writers(writer_entry_index)%number_of_contents
1019 do i=1, number_contents
1020 if (io_configuration%file_writers(writer_entry_index)%contents(i)%facet_type == group_type)
then 1022 io_configuration%file_writers(writer_entry_index)%contents(i)%facet_name)
1023 if (group_index == 0)
call log_log(
log_error,
"Can not find group '"//trim(&
1024 io_configuration%file_writers(writer_entry_index)%contents(i)%facet_name)//
"'")
1027 io_configuration%groups(group_index)%namespace)
1028 else if (io_configuration%file_writers(writer_entry_index)%contents(i)%facet_type == field_type)
then 1031 io_configuration%file_writers(writer_entry_index)%contents(i)%facet_name,
"", number_q_fields)
1044 integer,
intent(in) :: num_q_fields
1045 character(len=STRING_LENGTH),
intent(in) :: namespace
1048 character(len=STRING_LENGTH) :: field_name
1067 character(len=STRING_LENGTH),
intent(in) :: field_name, field_namespace
1068 integer,
intent(in) :: num_q_fields
1074 if (get_diagnostic_field_configuration(io_configuration, field_name, field_namespace, diagnostic_field_configuration))
then 1075 if (diagnostic_field_configuration%field_type == array_field_type)
then 1076 if (diagnostic_field_configuration%dim_size_defns(diagnostic_field_configuration%dimensions) .eq.
"qfields")
then 1082 else if (get_prognostic_field_configuration(io_configuration, field_name, field_namespace, &
1083 prognostic_field_configuration, prognostic_containing_data_defn))
then 1084 if (prognostic_field_configuration%field_type == array_field_type)
then 1085 if (prognostic_field_configuration%dim_size_defns(prognostic_field_configuration%dimensions) .eq.
"qfields")
then 1102 writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
1104 integer,
intent(in) :: writer_entry_index, facet_index, current_field_index
1105 type(
hashset_type),
intent(inout) :: writer_field_names, duplicate_field_names
1106 type(
hashmap_type),
intent(inout) :: diagnostic_generation_frequency
1108 integer :: group_index
1109 character(len=STRING_LENGTH) :: field_name
1114 io_configuration%file_writers(writer_entry_index)%contents(facet_index)%facet_name)
1115 if (group_index == 0)
then 1117 trim(io_configuration%file_writers(writer_entry_index)%contents(facet_index)%facet_name)//
"' in the configuration")
1119 iterator=
c_get_iterator(io_configuration%groups(group_index)%members)
1124 io_configuration%groups(group_index)%namespace, writer_field_names, duplicate_field_names, &
1125 diagnostic_generation_frequency)
1141 my_facet_index, field_name, field_namespace, writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
1143 integer,
intent(in) :: writer_entry_index, io_config_facet_index, my_facet_index
1144 character(len=*),
intent(in) :: field_name, field_namespace
1145 type(
hashset_type),
intent(inout) :: writer_field_names, duplicate_field_names
1146 type(
hashmap_type),
intent(inout) :: diagnostic_generation_frequency
1148 integer :: i, number_q_fields, tot_size
1153 class(*),
pointer :: generic
1155 if (get_diagnostic_field_configuration(io_configuration, field_name, field_namespace, diagnostic_field_configuration))
then 1156 if (diagnostic_field_configuration%field_type == array_field_type)
then 1157 if (diagnostic_field_configuration%dim_size_defns(diagnostic_field_configuration%dimensions) .eq.
"qfields")
then 1158 number_q_fields=
c_get_integer(io_configuration%dimension_sizing,
"qfields")
1159 do i=1, number_q_fields
1161 my_facet_index+i, trim(field_name)//
"_udef"//trim(
conv_to_string(i)), field_namespace, writer_field_names, &
1162 duplicate_field_names,
c_get_integer(diagnostic_generation_frequency, field_name), diagnostic_field_configuration)
1165 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions
1166 tot_size=tot_size*
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%actual_dim_size(i)
1174 my_facet_index+1, field_name, field_namespace, writer_field_names, duplicate_field_names, &
1175 c_get_integer(diagnostic_generation_frequency, field_name), diagnostic_field_configuration)
1177 else if (get_prognostic_field_configuration(io_configuration, field_name, field_namespace, &
1178 prognostic_field_configuration, prognostic_containing_data_defn))
then 1179 if (prognostic_field_configuration%field_type == array_field_type)
then 1180 if (prognostic_field_configuration%dim_size_defns(prognostic_field_configuration%dimensions) .eq.
"qfields")
then 1181 number_q_fields=
c_get_integer(io_configuration%dimension_sizing,
"qfields")
1182 do i=1, number_q_fields
1184 my_facet_index+i, trim(field_name)//
"_udef"//trim(
conv_to_string(i)), field_namespace, writer_field_names, &
1185 duplicate_field_names, prognostic_containing_data_defn%frequency, &
1186 prognostic_field_configuration=prognostic_field_configuration)
1188 if (prognostic_field_configuration%collective)
then 1189 allocate(collective_q_field)
1190 allocate(collective_q_field%dimensions(&
1191 writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions))
1192 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions
1193 if (trim(
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dim_size_defns(i)) ==
"z")
then 1194 collective_q_field%dimensions(i)=1
1195 else if (trim(
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dim_size_defns(i)) &
1197 collective_q_field%dimensions(i)=2
1198 else if (trim(
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dim_size_defns(i)) &
1200 collective_q_field%dimensions(i)=3
1203 generic=>collective_q_field
1207 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%dimensions
1208 tot_size=tot_size*
writer_entries(writer_entry_index)%contents(my_facet_index+number_q_fields)%actual_dim_size(i)
1218 my_facet_index+1, field_name, field_namespace, writer_field_names, duplicate_field_names, &
1219 prognostic_containing_data_defn%frequency, prognostic_field_configuration=prognostic_field_configuration)
1223 "' configured for file write but can not find this as a prognostic or diagnostic definition")
1239 my_facet_index, field_name, field_namespace, writer_field_names, duplicate_field_names, timestep_frequency, &
1240 diagnostic_field_configuration, prognostic_field_configuration)
1242 integer,
intent(in) :: writer_entry_index, io_config_facet_index, my_facet_index, timestep_frequency
1243 character(len=*),
intent(in) :: field_name, field_namespace
1244 type(
hashset_type),
intent(inout) :: writer_field_names, duplicate_field_names
1250 writer_entries(writer_entry_index)%contents(my_facet_index)%field_name=field_name
1251 writer_entries(writer_entry_index)%contents(my_facet_index)%field_namespace=field_namespace
1255 if (.not.
c_contains(writer_field_names, field_name))
then 1261 if (io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type == &
1262 instantaneous_type)
then 1263 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation=>perform_instantaneous_time_manipulation
1264 writer_entries(writer_entry_index)%contents(my_facet_index)%ready_to_write=>is_instantaneous_time_manipulation_ready_to_write
1265 else if (io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type == &
1266 time_averaged_type)
then 1267 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation=>perform_timeaveraged_time_manipulation
1268 writer_entries(writer_entry_index)%contents(my_facet_index)%ready_to_write=>is_time_averaged_time_manipulation_ready_to_write
1269 else if (io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type == &
1271 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation=>perform_none_time_manipulation
1272 writer_entries(writer_entry_index)%contents(my_facet_index)%ready_to_write=>is_none_time_manipulation_ready_to_write
1274 writer_entries(writer_entry_index)%contents(my_facet_index)%time_manipulation_type=&
1275 io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%time_manipulation_type
1276 writer_entries(writer_entry_index)%contents(my_facet_index)%output_frequency=&
1277 io_configuration%file_writers(writer_entry_index)%contents(io_config_facet_index)%output_time_frequency
1278 writer_entries(writer_entry_index)%contents(my_facet_index)%previous_write_time=0.0
1279 writer_entries(writer_entry_index)%contents(my_facet_index)%previous_tracked_write_point=0.0
1280 writer_entries(writer_entry_index)%contents(my_facet_index)%duplicate_field_name=.false.
1281 writer_entries(writer_entry_index)%contents(my_facet_index)%pending_to_write=.false.
1282 writer_entries(writer_entry_index)%contents(my_facet_index)%enabled=.false.
1283 writer_entries(writer_entry_index)%contents(my_facet_index)%expected_here=.true.
1284 writer_entries(writer_entry_index)%contents(my_facet_index)%prognostic_field=.false.
1285 writer_entries(writer_entry_index)%contents(my_facet_index)%diagnostic_field=.false.
1287 if (
present(diagnostic_field_configuration))
then 1288 writer_entries(writer_entry_index)%contents(my_facet_index)%timestep_frequency=timestep_frequency
1289 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=diagnostic_field_configuration%dimensions
1290 writer_entries(writer_entry_index)%contents(my_facet_index)%data_type=diagnostic_field_configuration%data_type
1291 writer_entries(writer_entry_index)%contents(my_facet_index)%field_type=diagnostic_field_configuration%field_type
1292 writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns=diagnostic_field_configuration%dim_size_defns
1293 writer_entries(writer_entry_index)%contents(my_facet_index)%units=diagnostic_field_configuration%units
1294 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_write=diagnostic_field_configuration%collective
1295 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_initialised=.false.
1296 writer_entries(writer_entry_index)%contents(my_facet_index)%issue_write=.true.
1297 writer_entries(writer_entry_index)%contents(my_facet_index)%diagnostic_field=.true.
1298 else if (
present(prognostic_field_configuration))
then 1299 writer_entries(writer_entry_index)%contents(my_facet_index)%timestep_frequency=timestep_frequency
1300 writer_entries(writer_entry_index)%contents(my_facet_index)%data_type=prognostic_field_configuration%data_type
1301 writer_entries(writer_entry_index)%contents(my_facet_index)%field_type=prognostic_field_configuration%field_type
1302 writer_entries(writer_entry_index)%contents(my_facet_index)%units=prognostic_field_configuration%units
1303 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=prognostic_field_configuration%dimensions
1304 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_write=prognostic_field_configuration%collective
1305 writer_entries(writer_entry_index)%contents(my_facet_index)%collective_initialised=.false.
1306 writer_entries(writer_entry_index)%contents(my_facet_index)%prognostic_field=.true.
1307 if (.not. prognostic_field_configuration%collective)
then 1308 writer_entries(writer_entry_index)%contents(my_facet_index)%issue_write=io_configuration%my_io_rank==0
1310 writer_entries(writer_entry_index)%contents(my_facet_index)%issue_write=.true.
1312 if (prognostic_field_configuration%field_type == array_field_type .or. &
1313 prognostic_field_configuration%field_type == map_field_type)
then 1314 if (prognostic_field_configuration%dimensions .gt. 0)
then 1315 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=prognostic_field_configuration%dimensions
1316 writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns=&
1317 prognostic_field_configuration%dim_size_defns
1319 call log_log(
log_error,
"The writing prognostic field '"//trim(field_name)//
"' configuration must have dimensions")
1323 call log_log(
log_error,
"A diagnostic or prognostic configuration for the field '"//trim(field_name)//
"' was not found")
1325 if (
writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions .gt. 0)
then 1326 if (
writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns(&
1327 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions) .eq.
"qfields")
then 1328 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions=&
1329 writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions-1
1331 do i=1,
writer_entries(writer_entry_index)%contents(my_facet_index)%dimensions
1333 io_configuration%dimension_sizing,
writer_entries(writer_entry_index)%contents(my_facet_index)%dim_size_defns(i))
1336 call check_thread_status(forthread_mutex_init(
writer_entries(writer_entry_index)%contents(my_facet_index)%values_mutex, -1))
1345 type(
hashset_type),
intent(inout) :: duplicate_field_names
1349 do i=1,
size(writer_entry%contents)
1350 if (
c_contains(duplicate_field_names, writer_entry%contents(i)%field_name))
then 1351 writer_entry%contents(i)%duplicate_field_name=.true.
1363 character(len=*),
intent(in) :: group_name
1365 integer :: i, entries
1367 entries=io_configuration%number_of_groups
1369 if (io_configuration%groups(i)%name == group_name)
then 1386 if (field_to_write_information%dimensions .eq. 3 .and. &
1390 field_to_write_information%collective_contiguous_optimisation=.true.
1393 field_to_write_information%collective_contiguous_optimisation=.false.
1395 field_to_write_information%collective_initialised=.true.
1407 integer :: start(field_to_write_information%dimensions, io_configuration%number_of_moncs), &
1408 count(field_to_write_information%dimensions, io_configuration%number_of_moncs), &
1409 common_starters(io_configuration%number_of_moncs), num_common, num_current_contents, active_dim, other_dim, &
1410 j, k, i, dim_identifier, number_distinct_writes, start_blocks(io_configuration%number_of_moncs), ierr, &
1411 count_blocks(io_configuration%number_of_moncs), current_contents(io_configuration%number_of_moncs), &
1412 monc_write_start_offset_per_dim(field_to_write_information%dimensions,io_configuration%number_of_moncs)
1413 logical :: processed(io_configuration%number_of_moncs)
1417 class(*),
pointer :: generic
1420 number_distinct_writes=0
1421 do j=1, io_configuration%number_of_moncs
1422 do k=1, field_to_write_information%dimensions
1424 start(k, j)=io_configuration%registered_moncs(j)%local_dim_starts(dim_identifier)
1425 count(k, j)=io_configuration%registered_moncs(j)%local_dim_sizes(dim_identifier)
1429 do j=1, io_configuration%number_of_moncs
1430 if (.not. processed(j))
then 1431 call get_common_starts(y_index, start(y_index, j), start, common_starters, num_common)
1432 if (num_common == 0)
then 1433 call get_common_starts(x_index, start(x_index, j), start, common_starters, num_common)
1434 if (num_common .gt. 0)
then 1442 number_distinct_writes=number_distinct_writes+1
1443 allocate(collective_descriptor)
1444 allocate(collective_descriptor%absolute_start(field_to_write_information%dimensions), &
1445 collective_descriptor%count(field_to_write_information%dimensions))
1446 start_blocks(number_distinct_writes)=start(other_dim, j)
1447 count_blocks(number_distinct_writes)=count(other_dim, j)
1448 num_current_contents=1
1449 current_contents(num_current_contents)=j
1451 if (num_common .gt. 0)
then 1454 if (.not. processed(common_starters(i)) .and. count(active_dim, j) == count(active_dim, i))
then 1455 if (start(other_dim, common_starters(i)) .lt. start_blocks(number_distinct_writes) .and. &
1456 start(other_dim, common_starters(i)) + count(other_dim, common_starters(i)) &
1457 == start_blocks(number_distinct_writes))
then 1458 start_blocks(number_distinct_writes)=start(other_dim, common_starters(i))
1459 count_blocks(number_distinct_writes)=count_blocks(number_distinct_writes)+count(other_dim, common_starters(i))
1460 processed(common_starters(i))=.true.
1461 num_current_contents=num_current_contents+1
1462 current_contents(num_current_contents)=common_starters(i)
1463 else if (start(other_dim, common_starters(i)) .gt. start_blocks(number_distinct_writes) .and. &
1464 start_blocks(number_distinct_writes) + count_blocks(number_distinct_writes) &
1465 == start(other_dim, common_starters(i)))
then 1466 count_blocks(number_distinct_writes)=count_blocks(number_distinct_writes)+count(other_dim, common_starters(i))
1467 processed(common_starters(i))=.true.
1468 num_current_contents=num_current_contents+1
1469 current_contents(num_current_contents)=common_starters(i)
1475 collective_descriptor%absolute_start=start(:,j)
1476 collective_descriptor%count=count(:,j)
1477 collective_descriptor%absolute_start(other_dim)=start_blocks(number_distinct_writes)
1478 collective_descriptor%count(other_dim)=count_blocks(number_distinct_writes)
1479 collective_descriptor%split_dim=other_dim
1480 if (num_current_contents .gt. 0)
then 1481 do k=1, num_current_contents
1482 allocate(specific_monc_collective)
1483 specific_monc_collective%relative_dimension_start=(start(other_dim,current_contents(k))-&
1484 start_blocks(number_distinct_writes)) + 1
1485 specific_monc_collective%counts=count(:, current_contents(k))
1486 specific_monc_collective%monc_location=current_contents(k)
1487 specific_monc_collective%monc_source=io_configuration%registered_moncs(current_contents(k))%source_id
1488 generic=>specific_monc_collective
1489 call c_add_generic(collective_descriptor%specific_monc_info, generic, .false.)
1492 generic=>collective_descriptor
1493 call c_add_generic(field_to_write_information%collective_descriptors, generic, .false.)
1497 call mpi_iallreduce(number_distinct_writes, field_to_write_information%max_num_collective_writes, 1, mpi_int, mpi_max, &
1498 io_configuration%io_communicator, field_to_write_information%max_num_collective_writes_request_handle, ierr)
1509 integer,
intent(in) :: dim, val
1510 integer,
dimension(:,:),
intent(in) :: vals
1511 integer,
dimension(:),
intent(out) :: common_starters
1512 integer,
intent(out) :: num_common
1517 do i=1,
size(vals, 2)
1518 if (vals(dim, i) == val)
then 1519 num_common=num_common+1
1520 common_starters(num_common)=i
1530 character(len=*),
intent(in) :: dim_name
1531 logical,
intent(out),
optional :: is_auto_dimension
1534 logical :: is_modified_size
1536 dash_idx=index(dim_name,
"_")
1538 is_modified_size=dash_idx .ne. -1
1539 if (.not. is_modified_size) dash_idx=len_trim(dim_name)
1541 if (dim_name(:dash_idx) .eq.
"z" .or. dim_name(:dash_idx) .eq.
"zn")
then 1543 else if (dim_name(:dash_idx) .eq.
"y")
then 1545 else if (dim_name(:dash_idx) .eq.
"x")
then 1551 if (
present(is_auto_dimension)) is_auto_dimension=is_modified_size
type(writer_type), dimension(:), allocatable, volatile writer_entries
type(map_type) function sort_applicable_time_points(unsorted_timepoints)
Sorts the time points based upon their timestep, smallest to largest. Note that this is a bubble sort...
Configuration of a specific data definition.
type(writer_type) function, pointer, public get_writer_entry_from_netcdf(field_name, timestep, terminated)
Looks up and retrieves the writer entry that corresponds to this NetCDF file state.
Performs time averaged, time manipulation and only returns a value if the output frequency determines...
type(map_type) function extract_applicable_time_points(start_time, end_time)
Extracts the applicable time points from the overall map that lie within a specific range...
logical, volatile currently_writing
integer function forthread_rwlock_init(rwlock_id, attr_id)
Retrieves the key currently being held at a specific index in the map or "" if the index > map elemen...
Gets a specific generic element out of the list, stack, queue or map with the corresponding key...
subroutine, public finalise_instantaneous_manipulation()
Finalises the instantaneous time manipulation.
logical function, public is_io_server_state_writer_ready(timestep)
Determines whether the IO server state writer is ready (i.e. state is at a specific level for the tim...
Returns whether a collection is empty.
subroutine handle_duplicate_field_names(writer_entry, duplicate_field_names)
Marks duplicate field names in a writer entry as duplicates so that the NetCDF layer can then deal wi...
Puts an integer key-value pair into the map.
type(data_values_type) function, public perform_none_time_manipulation(instant_values, output_frequency, field_name, timestep, time)
Performs no time manipulation and returns data.
integer function forthread_mutex_unlock(mutex_id)
type(data_values_type) function, public perform_instantaneous_time_manipulation(instant_values, output_frequency, field_name, timestep, time)
Performs the instantaneous time manipulation and returns data only if this is to be written to the st...
Overall IO configuration.
subroutine, public inform_writer_federator_fields_present(io_configuration, field_names, diag_field_names_and_roots)
Informs the writer federator that specific fields are present and should be reflected in the diagnost...
Pushes a generic element onto the stack or queue.
integer, parameter, public log_error
Only log ERROR messages.
type(hashset_type), volatile q_field_names
integer, parameter, public array_field_type
subroutine, public provide_ordered_field_to_writer_federator(io_configuration, field_name, field_namespace, field_values, timestep, time, source)
integer function forthread_mutex_destroy(mutex_id)
logical function, public get_diagnostic_field_configuration(io_configuration, field_name, field_namespace, diagnostic_config)
Retrieves the diagnostics field configuration corresponding to a specific field name and returns whet...
Reads the IO server state that was stored in a NetCDF checkpoint file.
subroutine, public close_netcdf_file(io_configuration, field_name, timestep)
Call back for the inter IO reduction which actually does the NetCDF file closing which is a collectiv...
Contains functionality for managing and extracting data from the raw data dumps that the IO server re...
Performs instantaneous time manipulation and only returns a value if the output frequency determines ...
integer function add_field_to_writer_entry(io_configuration, writer_entry_index, io_config_facet_index, my_facet_index, field_name, field_namespace, writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
Adds a field to the writer entry, this will split the Q fields. However at initialisation we don't kn...
subroutine close_diagnostics_file(io_configuration, writer_entry, timestep, time)
Closes the diagnostics file, this is done via a global callback to issue the closes synchronously (co...
logical function, public get_scalar_logical_from_monc(io_configuration, source, data_id, data_dump, key)
Retrieves a single logical element (scalar) from the data dump.
integer function get_dimension_identifier(dim_name, is_auto_dimension)
Translates a dimension name to its numeric corresponding identifier.
subroutine determine_if_outstanding_field_can_be_written(io_configuration, writer_entry, specific_field)
For a specific field wil determine and handle any outstanding fields writes until an outstanding writ...
integer, parameter, public default_precision
MPI communication type which we use for the prognostic and calculation data.
integer, parameter, public z_index
Grid index parameters.
subroutine check_writer_trigger(io_configuration, writer_entry_index, timestep, time, terminated)
Checks a writer trigger and issues a file creation along with field write if the conditions (time or ...
integer, parameter, public io_state_type
integer, parameter, public field_type
subroutine, public issue_actual_write(io_configuration, writer_entry, timestep, time, terminated_write)
Issues the actual file creation, write of available fields and closure if all completed.
logical function, public is_field_used_by_writer_federator(field_name, field_namespace)
Determines whether a field is used by the writer federator or not.
Abstraction layer around MPI, this issues and marshals the lower level communication details...
logical function, public is_field_split_on_q(field_name)
Determines whether a field is split on Q or not.
integer function forthread_rwlock_rdlock(lock_id)
Contains common definitions for the data and datatypes used by MONC.
type(hashmap_type), volatile time_points
subroutine determine_if_field_can_be_written(io_configuration, writer_entry, specific_field, timestep, previous_write_timestep, write_time, previous_write_time, field_written)
Determines if a file can be written to its overarching write representation. If so then a write is is...
Pops a generic element off the stack or queue.
subroutine, public log_master_log(level, message)
Will log just from the master process.
integer, parameter, public log_debug
Log DEBUG, INFO, WARNING and ERROR messages.
A hashmap structure, the same as a map but uses hashing for greatly improved performance when storing...
subroutine, public inform_writer_federator_time_point(io_configuration, source, data_id, data_dump)
integer function forthread_mutex_init(mutex_id, attr_id)
Gets a specific integer element out of the list, stack, queue or map with the corresponding key...
Conversion between common inbuilt FORTRAN data types.
integer, parameter, public double_data_type
subroutine, public store_io_server_state(io_configuration, writer_entries, time_points, file_writer_information, timestep)
Stores the IO server state in the NetCDF file.
subroutine, public initialise_writer_federator(io_configuration, diagnostic_generation_frequency, continuation_run)
Initialises the write federator and configures it based on the user configuration. Also initialises the time manipulations.
Converts data types to strings.
type(hashmap_type), volatile collective_q_field_dims
integer, parameter, public instantaneous_type
integer function forthread_rwlock_wrlock(lock_id)
subroutine, public perform_global_callback(io_configuration, field_name, timestep, completion_procedure)
Performs a global callback.
The NetCDF file type writer which performs actual writing of NetCDF files to the parallel filesystem...
subroutine, public log_log(level, message, str)
Logs a message at the specified level. If the level is above the current level then the message is ig...
subroutine provide_ordered_field_to_writer_federator_real_values(io_configuration, field_name, field_namespace, field_values, timestep, time, source)
Provides fields (either diagnostics or prognostics) to the write federator which will action these as...
logical function, public get_prognostic_field_configuration(io_configuration, field_name, field_namespace, prognostic_config, prognostic_containing_data_defn)
Retrieves the prognostic field configuration corresponding to a specific field name and returns wheth...
Writer types which are shared across writing functionality. Also includes serialisation functionality...
integer, parameter, public string_data_type
This defines some constants and procedures that are useful to the IO server and clients that call it...
logical function, public is_field_present(io_configuration, source, data_id, key)
Map data structure that holds string (length 20 maximum) key value pairs.
This is a thread pool and the single management "main" thread will spawn out free threads in the pool...
Global callback inter IO, which registers the callback with identifiers and then the procedure is act...
subroutine get_common_starts(dim, val, vals, common_starters, num_common)
Retrieves the number of common starting points that match a specific input value. ...
subroutine add_specific_field_to_writer_entry(io_configuration, writer_entry_index, io_config_facet_index, my_facet_index, field_name, field_namespace, writer_field_names, duplicate_field_names, timestep_frequency, diagnostic_field_configuration, prognostic_field_configuration)
Adds a specific field and its information to a writer entry.
Returns the number of elements in the collection.
subroutine write_collective_write_value(result_values, writer_index, contents_index, source, lookup_key)
Writes the collective values, this is held differently to independent values which are written direct...
subroutine, public check_thread_status(ierr)
Checks the error status of any thread operation and reports an error if it failed.
subroutine, public init_instantaneous_manipulation()
Initialises the instantaneous time manipulation.
integer function forthread_mutex_lock(mutex_id)
subroutine initialise_contiguous_data_regions(io_configuration, field_to_write_information)
Will initialise the collective data regions that form contiguous blocks within the data...
subroutine handle_close_diagnostics_globalcallback(io_configuration, values, field_name, timestep)
Call back for the inter IO reduction which actually does the NetCDF file closing which is a collectiv...
integer function get_field_number_of_fields(io_configuration, field_name, field_namespace, num_q_fields)
Retrieves the number of fields that make up this field, if it is a Q field then it will be split into...
logical function check_for_and_issue_chain_write(io_configuration, writer_entry)
Will check whether there are any pending writes and if so will issue a chain write for this...
subroutine, public define_netcdf_file(io_configuration, file_writer_information, timestep, time, time_points, termination_write)
Defines a NetCDF file - which creates it, defines all dimensions and variables. This must be called b...
subroutine, public unlock_mpi()
If we are explicitly managing MPI thread safety (SERIALIZED mode) then unlocks MPI.
Collection data structures.
integer function, public get_monc_location(io_configuration, source)
A helper function to get the location of a MONC's configuration in the IO data structure.
type(hashmap_type), volatile q_field_splits
subroutine register_pending_file_write(writer_entry_index, timestep, time, terminated_write)
Registers a pending file write which will be actioned later on.
subroutine, public check_writer_for_trigger(io_configuration, source, data_id, data_dump)
Checks all writer entries for any trigger fires and issues the underlying file storage.
Performs no time manipulation and returns the value, basically a no-op.
integer, parameter, public log_warn
Log WARNING and ERROR messages.
logical function, public is_time_averaged_time_manipulation_ready_to_write(latest_time, output_frequency, write_time, latest_timestep, write_timestep)
Converts data types to real.
integer, parameter, public string_length
Default length of strings.
subroutine, public lock_mpi()
If we are explicitly managing MPI thread safety (SERIALIZED mode) then locks MPI. ...
logical function, public is_none_time_manipulation_ready_to_write(latest_time, output_frequency, write_time, latest_timestep, write_timestep)
integer function get_group_number_of_fields(io_configuration, group_members, num_q_fields, namespace)
Retrieves the number of fields within a group of fields.
integer, parameter, public time_averaged_type
This federates over the writing of diagnostic and prognostic data to the file system. It also manages the time manipulation of fields and groups.
List data structure which implements a doubly linked list. This list will preserve its order...
subroutine enable_specific_field_by_name(field_name, diagnostics_mode, expected_here)
Enables a specific field by its name, this will locate all the fields with this name and enable them...
Queue (FIFO) data structure.
Adds a generic element to the end of the list.
Functionality to support the different types of grid and abstraction between global grids and local o...
integer, volatile time_points_rwlock
integer function forthread_rwlock_destroy(rwlock_id)
integer function add_group_of_fields_to_writer_entry(io_configuration, writer_entry_index, facet_index, current_field_index, writer_field_names, duplicate_field_names, diagnostic_generation_frequency)
Adds a group of fields to a writer entry, groups are expanded out into individual fields...
logical function, public log_is_master()
Determines whether the process is the master logging process. This might be preferable rather than ca...
subroutine, public finalise_time_averaged_manipulation()
Finalises the reduction action, waiting for all outstanding requests and then freeing data...
subroutine, public reactivate_writer_federator_state(io_configuration, writer_entries, time_points)
Reactivates the writer federator and everything beneath it (i.e. just not the writer field manager...
logical function, public is_instantaneous_time_manipulation_ready_to_write(latest_time, output_frequency, write_time, latest_timestep, write_timestep)
integer, volatile currently_writing_mutex
Frees up all the allocatable, heap, memory associated with a list, stack, queue or map...
subroutine, public provide_q_field_names_to_writer_federator(q_provided_field_names)
Provides the Q field names to the write federator, this is required as on initialisation we don't kno...
integer function forthread_rwlock_unlock(lock_id)
Puts a generic key-value pair into the map.
integer function, public get_scalar_integer_from_monc(io_configuration, source, data_id, data_dump, key)
Retrieves a single integer element (scalar) from the data dump.
real(kind=double_precision) function, public get_scalar_real_from_monc(io_configuration, source, data_id, data_dump, key)
Retreives a scalar real with a corresponding key from the raw data dump.
integer, volatile collective_contiguous_initialisation_mutex
subroutine, public initialise_netcdf_filetype()
Initialises the NetCDF writing functionality.
Hashset structure which will store unique strings. The hashing aspect means that lookup is very fast ...
subroutine, public init_time_averaged_manipulation()
Initialises the reduction action.
integer function get_index_of_group(io_configuration, group_name)
Searches the IO server configuration for a group with a specific name and returns the index to that g...
type(hashset_type), volatile used_field_names
Configuration associated with the representation of a specific data field.
logical function get_next_applicable_writer_entry(field_name, field_namespace, writer_index_point, contents_index_point)
Retrieves the index of the next writer which uses a specific field. If none is found then returns fal...
Converts data types to integers.
Determines whether or not a map contains a specific key.
subroutine, public finalise_writer_federator()
Finalises the write federator and the manipulations.
Gets a specific double precision real element out of the list, stack, queue or map with the correspon...
integer function get_size_of_collective_q(io_configuration, field_name, source)
Retrieves the data size for each Q entry of a collective Q field for the specific source MONC that ha...
Adds a string to the end of the list.
integer function, public log_get_logging_level()
Retrieves the current logging level.
integer, parameter, public map_field_type
Field data type identifiers.
integer, parameter, public y_index
integer function get_total_number_writer_fields(io_configuration, writer_entry_index)
Determines the total number of fields that make up a writer entry, this is all the fields of the grou...
Gets a specific string element out of the list, stack, queue or map with the corresponding key...
Parses the XML configuration file to produce the io configuration description which contains the data...
subroutine, public write_variable(io_configuration, field_to_write_information, filename, timestep, time)
Writes the contents of a variable to the NetCDF file. This also removes the written entries from the ...
Retrieves the double precision real value held at the specific map index or null if index > map eleme...
subroutine, public finalise_netcdf_filetype()
Finalises the NetCDF writing functionality.
The IO server state module which will write out the current state of the IO server to a NetCDF file...
integer, parameter, public group_type
integer, parameter, public x_index
type(data_values_type) function, public perform_timeaveraged_time_manipulation(instant_values, output_frequency, field_name, timestep, time)
Performs the time averaged manipulation and only returns values if these are to be stored (i...
real(kind=double_precision) function, public conv_single_real_to_double(input_real)
Converts from a single to double precision real. This applies some rounding to a certain number of de...
subroutine provide_ordered_single_field_to_writer_federator(io_configuration, field_name, field_namespace, field_values, timestep, time, source)
Provides a single ordered field, i.e. Q fields have been split by this point.
integer, parameter, public none_type
Puts a double precision real key-value pair into the map.
Removes a specific element from the list or map.
subroutine determine_collective_type_and_optimise_if_possible(io_configuration, field_to_write_information)
Determines whether it can optimise a specific collective field. If the field fits into certain limite...