35 integer :: data_type, dimensions, dim_sizes(4)
37 character(len=STRING_LENGTH),
dimension(:),
allocatable :: string_values
43 type(
map_type) :: registered_monc_types, registered_monc_buffer_sizes
44 type(
map_type),
dimension(:),
allocatable :: field_start_locations, field_end_locations, dimensions
45 character(len=STRING_LENGTH),
dimension(:),
allocatable :: definition_names
46 integer :: active_threads, active_mutex, deactivate_condition_variable, local_dim_sizes(3), local_dim_starts(3), &
47 local_dim_ends(3), source_id
52 character(len=STRING_LENGTH) :: name, namespace, dim_size_defns(4), units
54 logical ::
optional, collective
59 character(len=STRING_LENGTH) :: name, namespace
60 logical :: send_on_terminate
61 integer :: number_of_data_fields, frequency
62 type(
map_type) :: compiled_fields, trigger_field_types
67 character(len=STRING_LENGTH) :: name
68 integer :: message_tag
69 procedure(handle_recv_data_from_io_server),
pointer,
nopass :: handling_procedure
73 character(len=STRING_LENGTH) ::
type, namespace
78 character(len=STRING_LENGTH) :: name, dim_size_defns(4), units, namespace
85 character(len=STRING_LENGTH) :: name, namespace
90 integer :: facet_type, time_manipulation_type
91 real :: output_time_frequency
92 character(len=STRING_LENGTH) :: facet_name
96 character(len=STRING_LENGTH) :: file_name, title
97 integer :: number_of_contents, write_timestep_frequency
98 real :: write_time_frequency
99 logical :: write_on_model_time, write_on_terminate, include_in_io_state_write
105 integer :: number_of_data_definitions, number_of_diagnostics, io_communicator, number_of_moncs, &
106 number_of_io_servers, my_io_rank, active_moncs, number_inter_io_communications, number_of_threads, number_of_groups, &
107 number_of_writers, number_of_distinct_data_fields, number_of_global_moncs, general_info_mutex
119 logical :: general_info_set
120 character,
dimension(:),
allocatable :: text_configuration
123 #ifndef DOXYGEN_SHOULD_SKIP_THIS
125 subroutine handle_recv_data_from_io_server(io_configuration, data_buffer, inter_io_index)
128 character,
dimension(:),
intent(inout) :: data_buffer
129 integer,
intent(in) :: inter_io_index
130 end subroutine handle_recv_data_from_io_server
132 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
169 recursive function get_io_xml(filename, funit_num)
result(io_xml)
170 character(len=*),
intent(in) :: filename
171 integer,
intent(in),
optional :: funit_num
172 character,
dimension(:),
allocatable :: io_xml, temp_io_xml
174 character(len=FILE_LINE_LEN) :: temp_line, adjusted_io_line
175 character(len=FILE_STR_STRIDE) :: reading_buffer
176 integer :: ierr, first_quote, last_quote, chosen_unit
178 if (
present(funit_num))
then
179 chosen_unit=funit_num
185 open (unit=chosen_unit, file=filename, status=
'OLD', iostat=ierr)
186 if (ierr .ne. 0)
call log_log(
log_error,
"Error opening file '"//trim(filename)//
"'")
188 read(chosen_unit,
"(A)",iostat=ierr) temp_line
189 adjusted_io_line=adjustl(temp_line)
190 if (ierr == 0 .and. adjusted_io_line(1:1) .ne.
"!" .and. adjusted_io_line(1:2) .ne.
"//")
then
191 if (index(temp_line,
"#include") .ne. 0)
then
192 first_quote=index(temp_line,
"""")
193 last_quote=index(temp_line,
"""", back=.true.)
194 if (first_quote .ne. 0 .and. last_quote .ne. 0)
then
196 temp_io_xml=
get_io_xml(temp_line(first_quote+1:last_quote-1), chosen_unit+1)
198 deallocate(temp_io_xml)
199 reading_buffer=new_line(
"A")
201 call log_log(
log_error,
"Malformed IO XML, include directives must have filename in quotes")
204 if (len_trim(reading_buffer) + len_trim(temp_line) .ge.
file_str_stride)
then
208 reading_buffer=trim(reading_buffer)//trim(temp_line)//new_line(
"A")
220 type(
hashmap_type),
intent(inout) :: provided_options_database
221 character,
dimension(:),
intent(in) :: raw_configuration
255 parsed_configuration%number_inter_io_communications=0
256 parsed_configuration%general_info_set=.false.
258 allocate(parsed_configuration%text_configuration(
size(raw_configuration)), source=raw_configuration)
262 type(
hashmap_type),
intent(inout) :: provided_options_database
297 character(len=*),
intent(in) :: element_name
298 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
299 integer,
intent(in) :: number_of_attributes
301 integer :: namespace_index
304 if (element_name ==
"field")
then
311 if (element_name ==
"diagnostic")
then
317 if (element_name ==
"thread_pool")
then
324 if (element_name ==
"include")
then
327 else if (element_name ==
"file")
then
331 else if (element_name ==
"data-writing")
then
333 else if (element_name ==
"data-definition")
then
336 else if (element_name ==
"data-handling")
then
338 if (namespace_index == 0)
then
344 else if (element_name ==
"group")
then
347 else if (element_name ==
"server-configuration")
then
355 character(len=*),
intent(in) :: element_name
359 if (element_name ==
"data-definition")
then
369 else if (element_name ==
"data-handling")
then
372 else if (element_name ==
"server-configuration")
then
374 else if (element_name ==
"action")
then
376 else if (element_name ==
"diagnostic")
then
379 else if (element_name ==
"data-writing")
then
382 else if (element_name ==
"group")
then
386 else if (element_name ==
"file")
then
393 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
395 integer :: number_index
399 if (number_index /= 0)
then
409 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
411 integer :: name_index, frequency_index, namespace_index, send_on_termination_index
412 character(len=STRING_LENGTH) :: namespace
418 if (name_index /= 0 .and. frequency_index /=0)
then
424 if (namespace_index /= 0)
then
431 if (send_on_termination_index /= 0)
then
473 character(len=*),
intent(in) :: element_name
474 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
477 class(*),
pointer :: generic
480 allocate(misc_member)
484 do i=1,
size(attribute_names)
493 character(len=*),
intent(in) :: element_name
494 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
496 integer :: field_index
498 if (element_name ==
"member")
then
500 if (field_index .gt. 0)
then
507 call log_log(
log_error,
"Unrecognised diagnostics group participant, name is '"//trim(element_name)//
"'")
512 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
514 integer :: field_index
519 if (field_index .gt. 0)
then
522 if (field_index .gt. 0)
then
534 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
536 integer :: field_index, number_of_contents
540 if (number_of_contents .gt. &
545 if (field_index .gt. 0)
then
552 if (field_index .gt. 0)
then
559 if (field_index .gt. 0)
then
568 call log_log(
log_error,
"Inclusion to file writer requires a field or group to include")
576 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
577 integer,
intent(in) :: number_of_contents
579 character(len=STRING_LENGTH) :: time_manip
580 integer :: field_index
583 if (field_index .gt. 0)
then
585 if (time_manip ==
"instantaneous")
then
588 else if (time_manip ==
"averaged")
then
591 else if (time_manip ==
"none")
then
595 call log_log(
log_error,
"Time manipulation '"//trim(time_manip)//
"' option not recognised")
598 call log_log(
log_error,
"Inclusion to file writer requires time manipulation")
602 if (field_index .gt. 0)
then
604 contents(number_of_contents)%output_time_frequency=&
610 call log_log(
log_error,
"Inclusion to file writer requires an output frequency")
615 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
617 integer :: field_index
622 if (field_index .gt. 0)
then
630 if (field_index .gt. 0)
then
636 if (field_index .gt. 0)
then
641 call log_log(
log_error,
"File writer requires either a write time frequency or write timestep frequency")
646 if (field_index .gt. 0)
then
654 if (field_index .gt. 0)
then
662 if (field_index .gt. 0)
then
679 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
681 integer :: field_index, type_field_index, data_field_index
682 character(len=STRING_LENGTH) :: field_type_str, field_data_type_str, size_definitions
690 if (field_index == 0 .or. type_field_index == 0 .or. data_field_index == 0)
then
691 call log_log(
log_error,
"Each diagnostic definition requires a field name, field type and data type")
699 call log_log(
log_error,
"The field type of '"//trim(field_type_str)//
"' is not recognised")
704 call log_log(
log_error,
"The field data type of '"//trim(field_data_type_str)//
"' is not recognised")
707 if (field_index .ne. 0)
then
716 if (field_index .ne. 0)
then
721 call log_log(
log_error,
"A diagnostic of field type array or map requires sizing a definition")
724 if (field_index .ne. 0)
then
738 character(len=*),
intent(in) :: size_definitions
739 character(len=STRING_LENGTH),
intent(out) :: individual_str_defn(4)
741 integer :: comma_index, sizing_index, cp
745 comma_index=index(size_definitions(cp:),
",")
746 do while (comma_index .ne. 0)
747 comma_index=comma_index+cp-1
748 individual_str_defn(sizing_index)= trim(size_definitions(cp:comma_index-1))
750 sizing_index=sizing_index+1
751 comma_index=index(size_definitions(cp:),
",")
752 if (sizing_index .gt. 4)
then
753 call log_log(
log_error,
"Can only have a maximum of four diagnostic field sizing dimensions")
756 if (cp .le. len(size_definitions))
then
757 individual_str_defn(sizing_index)=trim(size_definitions(cp:))
758 sizing_index=sizing_index+1
770 character(len=*),
dimension(:),
intent(in) :: attribute_names, attribute_values
772 character(len=STRING_LENGTH) :: field_type_str, field_data_type_str, sizing_defn_str
773 integer :: name_field_index, type_field_index, data_field_index, field_index, optional_field_index, idx
780 if (name_field_index == 0 .or. type_field_index == 0 .or. data_field_index == 0)
then
781 call log_log(
log_error,
"Each data field definition requires a name, field type and data type")
797 call log_log(
log_error,
"The field type of '"//trim(field_type_str)//
"' is not recognised")
815 if (field_index .ne. 0)
then
826 if (field_index .ne. 0)
then
838 call log_log(
log_error,
"The field data type of '"//trim(field_data_type_str)//
"' is not recognised")
844 call log_log(
log_error,
"A map field type must have a data type of ""string""")
848 if (optional_field_index .ne. 0)
then
862 character(len=*),
intent(in) :: field_type_str
871 character(len=*),
intent(in) :: field_data_type_str
886 character(len=*),
intent(in) :: original_string, to_replace
887 character(len=*),
intent(out) :: new_string
889 integer :: current_index, string_len, occurance
892 string_len=len(original_string)
894 do while (current_index .lt. string_len)
895 occurance=index(original_string(current_index:), to_replace)
896 if (occurance .eq. 0)
then
897 occurance=len(original_string)
899 occurance=occurance+current_index
901 new_string=trim(new_string)//trim(original_string(current_index:occurance-len(to_replace)-1))
902 current_index=current_index+occurance+len(to_replace)-2
907 character(len=*),
intent(in) :: original_string
908 integer,
intent(in) :: field_value_type
911 character(len=STRING_LENGTH) :: lookup_key
931 call log_log(
log_error,
"Can not find IO configuration key '"//trim(lookup_key)//
"' in the options database")
941 character(len=*),
intent(in) :: search_name
942 character(len=*),
dimension(:) :: attribute_names
944 integer :: i, size_of_names
946 size_of_names=
size(attribute_names)
948 if (attribute_names(i) == search_name)
then
964 allocate(temp_descriptions(lbound(io_configuration%inter_io_communications,1):&
966 temp_descriptions(lbound(io_configuration%inter_io_communications,1):&
967 ubound(io_configuration%inter_io_communications,1)) = io_configuration%inter_io_communications
968 call move_alloc(from=temp_descriptions,to=io_configuration%inter_io_communications)
1023 allocate(temp_data_definitions(lbound(
building_config%data_definitions, 1):&
1027 call move_alloc(from=temp_data_definitions,to=
building_config%data_definitions)
1037 allocate(temp_registered_moncs(lbound(io_configuration%registered_moncs, 1):&
1039 temp_registered_moncs(lbound(io_configuration%registered_moncs, 1):&
1040 ubound(io_configuration%registered_moncs, 1)) = io_configuration%registered_moncs
1041 call move_alloc(from=temp_registered_moncs,to=io_configuration%registered_moncs)
1050 character(len=*),
intent(in) :: key
1054 do i=1,io_configuration%number_of_data_definitions
1055 if (io_configuration%data_definitions(i)%name .eq. key)
then
1070 integer,
intent(in) :: source
1073 class(*),
pointer :: generic
1077 if (
associated(generic))
then
1079 monc_defn=io_configuration%registered_moncs(location)
1097 do i=1, io_configuration%number_of_data_definitions
1100 io_configuration%data_definitions(i)%send_on_terminate
1102 io_configuration%data_definitions(i)%number_of_data_fields
1114 integer :: i, j, field_index
1118 do i=1, io_configuration%number_of_data_definitions
1119 do j=1, io_configuration%data_definitions(i)%number_of_data_fields
1122 io_configuration%data_definitions(i)%fields(j)%name
1124 io_configuration%data_definitions(i)%fields(j)%field_type
1126 io_configuration%data_definitions(i)%fields(j)%data_type
1128 io_configuration%data_definitions(i)%fields(j)%optional
1129 field_index=field_index+1
1143 do i=1, io_configuration%number_of_data_definitions
1157 character(len=*),
intent(in) :: field_name
1158 integer,
intent(in) :: source, data_id
1160 integer :: monc_location
1172 character(len=*),
intent(in) :: field_name
1175 class(*),
pointer :: generic
1178 if (
associated(generic))
then
1179 select type(generic)
1193 type(
map_type),
intent(inout) :: collection
1194 character(len=*),
intent(in) :: field_name
1197 class(*),
pointer :: generic
1200 if (
associated(generic))
then
1201 select type(generic)
1217 class(*),
pointer :: generic
1220 if (
associated(generic))
then
1221 select type(generic)
1235 integer,
intent(in) :: source
1247 character(len=*),
intent(in) :: field_name, field_namespace
1252 do i=1,
size(io_configuration%diagnostics)
1253 if (io_configuration%diagnostics(i)%name == field_name .and. &
1254 io_configuration%diagnostics(i)%namespace == field_namespace)
then
1255 diagnostic_config=io_configuration%diagnostics(i)
1269 prognostic_config, prognostic_containing_data_defn)
1271 character(len=*),
intent(in) :: field_name, field_namespace
1276 do i=1, io_configuration%number_of_data_definitions
1277 do j=1, io_configuration%data_definitions(i)%number_of_data_fields
1278 if (io_configuration%data_definitions(i)%fields(j)%name == field_name .and. &
1279 io_configuration%data_definitions(i)%fields(j)%namespace == field_namespace)
then
1280 prognostic_config=io_configuration%data_definitions(i)%fields(j)
1281 if (
present(prognostic_containing_data_defn))
then
1282 prognostic_containing_data_defn=io_configuration%data_definitions(i)
1297 character,
dimension(:),
allocatable,
intent(inout) :: io_xml
1298 character(len=*),
intent(in) :: reading_buffer
1300 character,
dimension(:),
allocatable :: temp_io_xml
1303 if (.not.
allocated(io_xml))
then
1304 allocate(io_xml(len_trim(reading_buffer)))
1305 do i=1, len_trim(reading_buffer)
1306 io_xml(i)=reading_buffer(i:i)
1309 allocate(temp_io_xml(
size(io_xml)+len_trim(reading_buffer)))
1310 temp_io_xml(:
size(io_xml)) = io_xml
1311 do i=1, len_trim(reading_buffer)
1312 temp_io_xml(
size(io_xml)+i) = reading_buffer(i:i)
1314 call move_alloc(from=temp_io_xml,to=io_xml)
1322 character,
dimension(:),
allocatable,
intent(inout) :: io_xml, other_xml_array
1324 character,
dimension(:),
allocatable :: temp_io_xml
1326 if (.not.
allocated(other_xml_array))
return
1328 if (.not.
allocated(io_xml))
then
1329 allocate(io_xml(
size(other_xml_array)), source=other_xml_array)
1331 allocate(temp_io_xml(
size(io_xml)+
size(other_xml_array)))
1332 temp_io_xml(:
size(io_xml)) = io_xml
1333 temp_io_xml(
size(io_xml)+1:) = other_xml_array
1334 call move_alloc(from=temp_io_xml,to=io_xml)