34module time_interp_external_mod
35#ifdef use_deprecated_io
36#include <fms_platform.h>
56 use fms_mod,
only : write_version_number
57 use mpp_mod,
only :
mpp_error,fatal,warning,mpp_pe, stdout, stdlog, note
58 use mpp_mod,
only : input_nml_file
69 use time_interp_mod,
only :
time_interp, time_interp_init
70 use axis_utils_mod,
only : get_axis_cart, get_axis_modulo, get_axis_modulo_times
71 use fms_mod,
only : lowercase, open_namelist_file, check_nml_error, close_file
72 use platform_mod,
only: r8_kind
73 use horiz_interp_mod,
only :
horiz_interp, horiz_interp_type
79#include<file_version.h>
81 integer,
parameter,
public :: NO_REGION=0, inside_region=1, outside_region=2
82 integer,
parameter,
private :: modulo_year= 0001
83 integer,
parameter,
private :: LINEAR_TIME_INTERP = 1
84 integer,
parameter,
public :: SUCCESS = 0, err_field_not_found = 1
85 integer,
private :: max_fields = 100, max_files= 40
86 integer,
private :: num_fields = 0, num_files=0
88 integer,
private :: num_io_buffers = 2
89 logical,
private :: module_initialized = .false.
90 logical,
private :: debug_this_module = .false.
92 public init_external_field, time_interp_external, time_interp_external_init, &
93 time_interp_external_exit, get_external_field_size, get_time_axis, get_external_field_missing
94 public set_override_region, reset_src_data_region, get_external_field_axes
96 private find_buf_index,&
102 type,
private :: ext_fieldtype
104 character(len=128) :: name, units
105 integer :: siz(4), ndim
106 type(domain2d) :: domain
107 type(axistype) :: axes(4)
108 type(time_type),
dimension(:),
pointer :: time =>null()
109 type(time_type),
dimension(:),
pointer :: start_time =>null(), end_time =>null()
110 type(fieldtype) :: field
111 type(time_type),
dimension(:),
pointer :: period =>null()
112 logical :: modulo_time
113 real,
dimension(:,:,:,:),
pointer :: data =>null()
114 logical,
dimension(:,:,:,:),
pointer :: mask =>null()
115 integer,
dimension(:),
pointer :: ibuf =>null()
116 real,
dimension(:,:,:,:),
pointer :: src_data =>null()
117 type(validtype) :: valid
119 logical :: domain_present
120 real(DOUBLE_KIND) :: slope, intercept
121 integer :: isc,iec,jsc,jec
122 type(time_type) :: modulo_time_beg, modulo_time_end
123 logical :: have_modulo_times, correct_leap_year_inconsistency
124 integer :: region_type
125 integer :: is_region, ie_region, js_region, je_region
126 integer :: is_src, ie_src, js_src, je_src
128 integer :: numwindows
129 logical,
dimension(:,:),
pointer :: need_compute=>null()
131 end type ext_fieldtype
135 character(len=128) :: filename =
''
151 interface time_interp_external
152 module procedure time_interp_external_0d
153 module procedure time_interp_external_2d
154 module procedure time_interp_external_3d
162 type(ext_fieldtype),
save,
private,
pointer :: field(:) => null()
163 type(filetype),
save,
private,
pointer :: opened_files(:) => null()
165 integer,
private,
parameter :: dk = double_kind
166 real(DOUBLE_KIND),
private,
parameter :: time_interp_missing=-1e99_dk
175 subroutine time_interp_external_init()
177 integer :: ioun, io_status, logunit, ierr
179 namelist /time_interp_external_nml/ num_io_buffers, debug_this_module, &
180 max_fields, max_files
184 if(module_initialized)
return
188 call write_version_number(
"TIME_INTERP_EXTERNAL_MOD", version)
190#ifdef INTERNAL_FILE_NML
191 read (input_nml_file, time_interp_external_nml, iostat=io_status)
192 ierr = check_nml_error(io_status,
'time_interp_external_nml')
194 ioun = open_namelist_file()
195 ierr=1;
do while (ierr /= 0)
196 read (ioun, nml=time_interp_external_nml, iostat=io_status,
end=10)
197 ierr = check_nml_error(io_status,
'time_interp_external_nml')
19910
call close_file (ioun)
202 write(logunit,time_interp_external_nml)
203 call realloc_fields(max_fields)
204 call realloc_files(max_files)
206 module_initialized = .true.
208 call time_interp_init()
212 end subroutine time_interp_external_init
274 function init_external_field(file,fieldname,format,threading,domain,desired_units,&
275 verbose,axis_centers,axis_sizes,override,correct_leap_year_inconsistency,&
276 permit_calendar_conversion,use_comp_domain,ierr, nwindows, ignore_axis_atts )
278 character(len=*),
intent(in) :: file,fieldname
279 integer,
intent(in),
optional :: format, threading
280 logical,
intent(in),
optional :: verbose
281 character(len=*),
intent(in),
optional :: desired_units
282 type(domain2d),
intent(in),
optional :: domain
283 type(axistype),
intent(inout),
optional :: axis_centers(4)
284 integer,
intent(inout),
optional :: axis_sizes(4)
285 logical,
intent(in),
optional :: override, correct_leap_year_inconsistency,&
286 permit_calendar_conversion,use_comp_domain
287 integer,
intent(out),
optional :: ierr
288 integer,
intent(in),
optional :: nwindows
289 logical,
optional :: ignore_axis_atts
292 integer :: init_external_field
294 type(fieldtype),
dimension(:),
allocatable :: flds
295 type(axistype),
dimension(:),
allocatable :: axes, fld_axes
296 type(axistype) :: time_axis
297 type(atttype),
allocatable,
dimension(:) :: global_atts
299 real(DOUBLE_KIND) :: slope, intercept
300 integer :: form, thread, fset, unit,ndim,nvar,natt,ntime,i,j
301 integer :: iscomp,iecomp,jscomp,jecomp,isglobal,ieglobal,jsglobal,jeglobal
302 integer :: isdata,iedata,jsdata,jedata, dxsize, dysize,dxsize_max,dysize_max
303 logical :: verb, transpose_xy,use_comp_domain1
304 real,
dimension(:),
allocatable :: tstamp, tstart, tend, tavg
305 character(len=1) :: cart
306 character(len=1),
dimension(4) :: cart_dir
307 character(len=128) :: units, fld_units
308 character(len=128) :: name, msg, calendar_type, timebeg, timeend
309 integer :: siz(4), siz_in(4), gxsize, gysize,gxsize_max, gysize_max
310 type(time_type) :: tdiff
311 integer :: yr, mon, day, hr, minu, sec
312 integer :: len, nfile, nfields_orig, nbuf, nx,ny
313 integer :: numwindows
314 logical :: ignore_axatts
317 if (.not. module_initialized)
call mpp_error(fatal,
'Must call time_interp_external_init first')
318 if(
present(ierr)) ierr = success
319 ignore_axatts=.false.
320 cart_dir(1)=
'X';cart_dir(2)=
'Y';cart_dir(3)=
'Z';cart_dir(4)=
'T'
321 if(
present(ignore_axis_atts)) ignore_axatts = ignore_axis_atts
322 use_comp_domain1 = .false.
323 if(
PRESENT(use_comp_domain)) use_comp_domain1 = use_comp_domain
325 if (
PRESENT(format)) form =
format
327 if (
PRESENT(threading)) thread = threading
330 if (
PRESENT(verbose)) verb=verbose
331 if (debug_this_module) verb = .true.
333 if(
present(nwindows)) numwindows = nwindows
336 if (
PRESENT(desired_units))
then
337 units = desired_units
338 call mpp_error(fatal,
'==> Unit conversion via time_interp_external &
339 &has been temporarily deprecated. Previous versions of&
340 &this module used udunits_mod to perform unit conversion.&
341 & Udunits_mod is in the process of being replaced since &
342 &there were portability issues associated with this code.&
343 & Please remove the desired_units argument from calls to &
348 if(trim(opened_files(i)%filename) == trim(file))
then
354 call mpp_open(unit,trim(file),mpp_rdonly,form,threading=thread,&
356 num_files = num_files + 1
357 if(num_files > max_files)
then
363 call mpp_error(fatal,
"time_interp_external: num_files is greater than max_files, "// &
364 "increase time_interp_external_nml max_files")
366 opened_files(num_files)%filename = trim(file)
367 opened_files(num_files)%unit = unit
369 unit = opened_files(nfile)%unit
375 write(msg,
'(a15,a,a58)')
'external field ',trim(fieldname),&
376 ' does not have an associated record dimension (REQUIRED) '
377 call mpp_error(fatal,trim(msg))
379 allocate(global_atts(natt))
380 call mpp_get_atts(unit, global_atts)
385 allocate(tstamp(ntime),tstart(ntime),tend(ntime),tavg(ntime))
387 transpose_xy = .false.
388 isdata=1; iedata=1; jsdata=1; jedata=1
392 if (
PRESENT(domain))
then
393 call mpp_get_compute_domain(domain,iscomp,iecomp,jscomp,jecomp)
394 nx = iecomp-iscomp+1; ny = jecomp-jscomp+1
395 call mpp_get_data_domain(domain,isdata,iedata,jsdata,jedata,dxsize,dxsize_max,dysize,dysize_max)
396 call mpp_get_global_domain(domain,isglobal,ieglobal,jsglobal,jeglobal,gxsize,gxsize_max,gysize,gysize_max)
397 elseif(use_comp_domain1)
then
398 call mpp_error(fatal,
"init_external_field:"//&
399 " use_comp_domain=true but domain is not present")
402 init_external_field = -1
403 nfields_orig = num_fields
406 call mpp_get_atts(flds(i),name=name,units=fld_units,ndim=ndim,siz=siz_in)
407 call mpp_get_tavg_info(unit,flds(i),flds,tstamp,tstart,tend,tavg)
408 call mpp_get_atts(flds(i),missing=missing)
410 if (trim(lowercase(name)) /= trim(lowercase(fieldname))) cycle
412 if (verb)
write(outunit,*)
'found field ',trim(fieldname),
' in file !!'
413 num_fields = num_fields + 1
414 if(num_fields > max_fields)
then
420 call mpp_error(fatal,
"time_interp_external: num_fields is greater than max_fields, "// &
421 "increase time_interp_external_nml max_fields")
424 init_external_field = num_fields
425 field(num_fields)%unit = unit
426 field(num_fields)%name = trim(name)
427 field(num_fields)%units = trim(fld_units)
428 field(num_fields)%field = flds(i)
429 field(num_fields)%isc = 1
430 field(num_fields)%iec = 1
431 field(num_fields)%jsc = 1
432 field(num_fields)%jec = 1
433 field(num_fields)%region_type = no_region
434 field(num_fields)%is_region = 0
435 field(num_fields)%ie_region = -1
436 field(num_fields)%js_region = 0
437 field(num_fields)%je_region = -1
438 if (
PRESENT(domain))
then
439 field(num_fields)%domain_present = .true.
440 field(num_fields)%domain = domain
441 field(num_fields)%isc=iscomp;field(num_fields)%iec = iecomp
442 field(num_fields)%jsc=jscomp;field(num_fields)%jec = jecomp
444 field(num_fields)%domain_present = .false.
447 call mpp_get_atts(flds(i),valid=field(num_fields)%valid )
448 allocate(fld_axes(ndim))
449 call mpp_get_atts(flds(i),axes=fld_axes)
450 if (ndim > 4)
call mpp_error(fatal, &
451 'invalid array rank <=4d fields supported')
452 field(num_fields)%siz = 1
453 field(num_fields)%ndim = ndim
454 field(num_fields)%tdim = 4
455 field(num_fields)%missing = missing
456 do j=1,field(num_fields)%ndim
458 call get_axis_cart(fld_axes(j), cart)
459 call mpp_get_atts(fld_axes(j),len=len)
460 if (cart ==
'N' .and. .not. ignore_axatts)
then
461 write(msg,
'(a,"/",a)') trim(file),trim(fieldname)
462 call mpp_error(fatal,
'file/field '//trim(msg)// &
463 ' couldnt recognize axis atts in time_interp_external')
464 else if (cart ==
'N' .and. ignore_axatts)
then
469 if (j.eq.2) transpose_xy = .true.
470 if (.not.
PRESENT(domain) .and. .not.
PRESENT(override))
then
475 field(num_fields)%isc=iscomp;field(num_fields)%iec=iecomp
476 elseif (
PRESENT(override))
then
478 if (
PRESENT(axis_sizes)) axis_sizes(1) = len
480 field(num_fields)%axes(1) = fld_axes(j)
481 if(use_comp_domain1)
then
482 field(num_fields)%siz(1) = nx
484 field(num_fields)%siz(1) = dxsize
486 if (len /= gxsize)
then
487 write(msg,
'(a,"/",a)') trim(file),trim(fieldname)
488 call mpp_error(fatal,
'time_interp_ext, file/field '//trim(msg)//
' x dim doesnt match model')
491 field(num_fields)%axes(2) = fld_axes(j)
492 if (.not.
PRESENT(domain) .and. .not.
PRESENT(override))
then
497 field(num_fields)%jsc=jscomp;field(num_fields)%jec=jecomp
498 elseif (
PRESENT(override))
then
500 if (
PRESENT(axis_sizes)) axis_sizes(2) = len
502 if(use_comp_domain1)
then
503 field(num_fields)%siz(2) = ny
505 field(num_fields)%siz(2) = dysize
507 if (len /= gysize)
then
508 write(msg,
'(a,"/",a)') trim(file),trim(fieldname)
509 call mpp_error(fatal,
'time_interp_ext, file/field '//trim(msg)//
' y dim doesnt match model')
512 field(num_fields)%axes(3) = fld_axes(j)
513 field(num_fields)%siz(3) = siz_in(3)
515 field(num_fields)%axes(4) = fld_axes(j)
516 field(num_fields)%siz(4) = ntime
517 field(num_fields)%tdim = j
520 siz = field(num_fields)%siz
522 if (
PRESENT(axis_centers))
then
523 axis_centers = field(num_fields)%axes
526 if (
PRESENT(axis_sizes) .and. .not.
PRESENT(override))
then
527 axis_sizes = field(num_fields)%siz
531 if (verb)
write(outunit,
'(a,4i6)')
'field x,y,z,t local size= ',siz
532 if (verb)
write(outunit,*)
'field contains data in units = ',trim(field(num_fields)%units)
533 if (transpose_xy)
call mpp_error(fatal,
'axis ordering not supported')
534 if (num_io_buffers .le. 1)
call mpp_error(fatal,
'time_interp_ext:num_io_buffers should be at least 2')
535 nbuf = min(num_io_buffers,siz(4))
537 field(num_fields)%numwindows = numwindows
538 allocate(field(num_fields)%need_compute(nbuf, numwindows))
539 field(num_fields)%need_compute = .true.
541 allocate(field(num_fields)%data(isdata:iedata,jsdata:jedata,siz(3),nbuf),&
542 field(num_fields)%mask(isdata:iedata,jsdata:jedata,siz(3),nbuf) )
543 field(num_fields)%mask = .false.
544 field(num_fields)%data = 0.0
545 slope=1.0;intercept=0.0
551 field(num_fields)%slope = slope
552 field(num_fields)%intercept = intercept
553 allocate(field(num_fields)%ibuf(nbuf))
554 field(num_fields)%ibuf = -1
555 field(num_fields)%nbuf = 0
556 if(
PRESENT(override))
then
557 field(num_fields)%is_src = 1
558 field(num_fields)%ie_src = gxsize
559 field(num_fields)%js_src = 1
560 field(num_fields)%je_src = gysize
561 allocate(field(num_fields)%src_data(gxsize,gysize,siz(3),nbuf))
563 field(num_fields)%is_src = isdata
564 field(num_fields)%ie_src = iedata
565 field(num_fields)%js_src = jsdata
566 field(num_fields)%je_src = jedata
567 allocate(field(num_fields)%src_data(isdata:iedata,jsdata:jedata,siz(3),nbuf))
570 allocate(field(num_fields)%time(ntime))
571 allocate(field(num_fields)%period(ntime))
572 allocate(field(num_fields)%start_time(ntime))
573 allocate(field(num_fields)%end_time(ntime))
575 call mpp_get_atts(time_axis,units=units,calendar=calendar_type)
577 field(num_fields)%time(j) = get_cal_time(tstamp(j),trim(units),trim(calendar_type), &
578 & permit_calendar_conversion)
579 field(num_fields)%start_time(j) = get_cal_time(tstart(j),trim(units),trim(calendar_type), &
580 & permit_calendar_conversion)
581 field(num_fields)%end_time(j) = get_cal_time( tend(j),trim(units),trim(calendar_type), &
582 & permit_calendar_conversion)
585 if (field(num_fields)%modulo_time)
then
586 call set_time_modulo(field(num_fields)%Time)
587 call set_time_modulo(field(num_fields)%start_time)
588 call set_time_modulo(field(num_fields)%end_time)
591 if(
present(correct_leap_year_inconsistency))
then
592 field(num_fields)%correct_leap_year_inconsistency = correct_leap_year_inconsistency
594 field(num_fields)%correct_leap_year_inconsistency = .false.
597 if(get_axis_modulo_times(time_axis, timebeg, timeend))
then
598 if(get_calendar_type() == no_calendar)
then
599 field(num_fields)%modulo_time_beg = set_time(timebeg)
600 field(num_fields)%modulo_time_end = set_time(timeend)
602 field(num_fields)%modulo_time_beg = set_date(timebeg)
603 field(num_fields)%modulo_time_end = set_date(timeend)
605 field(num_fields)%have_modulo_times = .true.
607 field(num_fields)%have_modulo_times = .false.
610 call mpp_error(note,
'time_interp_external_mod: file '//trim(file)//
' has only one time level')
613 field(num_fields)%period(j) = field(num_fields)%end_time(j)-field(num_fields)%start_time(j)
614 if (field(num_fields)%period(j) > set_time(0,0))
then
615 call get_time(field(num_fields)%period(j), sec, day)
616 sec = sec/2+mod(day,2)*43200
618 field(num_fields)%time(j) = field(num_fields)%start_time(j)+&
621 if (j > 1 .and. j < ntime)
then
622 tdiff = field(num_fields)%time(j+1) - field(num_fields)%time(j-1)
623 call get_time(tdiff, sec, day)
624 sec = sec/2+mod(day,2)*43200
626 field(num_fields)%period(j) = set_time(sec,day)
627 sec = sec/2+mod(day,2)*43200
629 field(num_fields)%start_time(j) = field(num_fields)%time(j) - set_time(sec,day)
630 field(num_fields)%end_time(j) = field(num_fields)%time(j) + set_time(sec,day)
631 elseif ( j == 1)
then
632 tdiff = field(num_fields)%time(2) - field(num_fields)%time(1)
633 call get_time(tdiff, sec, day)
634 field(num_fields)%period(j) = set_time(sec,day)
635 sec = sec/2+mod(day,2)*43200
637 field(num_fields)%start_time(j) = field(num_fields)%time(j) - set_time(sec,day)
638 field(num_fields)%end_time(j) = field(num_fields)%time(j) + set_time(sec,day)
640 tdiff = field(num_fields)%time(ntime) - field(num_fields)%time(ntime-1)
641 call get_time(tdiff, sec, day)
642 field(num_fields)%period(j) = set_time(sec,day)
643 sec = sec/2+mod(day,2)*43200
645 field(num_fields)%start_time(j) = field(num_fields)%time(j) - set_time(sec,day)
646 field(num_fields)%end_time(j) = field(num_fields)%time(j) + set_time(sec,day)
653 if (field(num_fields)%time(j) >= field(num_fields)%time(j+1))
then
654 write(msg,
'(A,i20)')
"times not monotonically increasing. Filename: " &
655 //trim(file)//
" field: "//trim(fieldname)//
" timeslice: ", j
656 call mpp_error(fatal, trim(msg))
660 field(num_fields)%modulo_time = get_axis_modulo(time_axis)
663 if (field(num_fields)%modulo_time)
write(outunit,*)
'data are being treated as modulo in time'
665 write(outunit,*)
'time index, ', j
666 call get_date(field(num_fields)%start_time(j),yr,mon,day,hr,minu,sec)
667 write(outunit,
'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
668 'start time: yyyy/mm/dd hh:mm:ss= ',yr,
'/',mon,
'/',day,hr,
':',minu,
':',sec
669 call get_date(field(num_fields)%time(j),yr,mon,day,hr,minu,sec)
670 write(outunit,
'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
671 'mid time: yyyy/mm/dd hh:mm:ss= ',yr,
'/',mon,
'/',day,hr,
':',minu,
':',sec
672 call get_date(field(num_fields)%end_time(j),yr,mon,day,hr,minu,sec)
673 write(outunit,
'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
674 'end time: yyyy/mm/dd hh:mm:ss= ',yr,
'/',mon,
'/',day,hr,
':',minu,
':',sec
680 if (num_fields == nfields_orig)
then
681 if (
present(ierr))
then
682 ierr = err_field_not_found
684 call mpp_error(fatal,
'external field "'//trim(fieldname)//
'" not found in file "'//trim(file)//
'"')
688 deallocate(global_atts)
691 deallocate(tstamp, tstart, tend, tavg)
695 end function init_external_field
701 subroutine time_interp_external_2d(index, time, data_in, interp, verbose,horz_interp, mask_out, &
702 is_in, ie_in, js_in, je_in, window_id)
704 integer,
intent(in) :: index
705 type(time_type),
intent(in) :: time
706 real,
dimension(:,:),
intent(inout) :: data_in
707 integer,
intent(in),
optional :: interp
708 logical,
intent(in),
optional :: verbose
709 type(horiz_interp_type),
intent(in),
optional :: horz_interp
710 logical,
dimension(:,:),
intent(out),
optional :: mask_out
711 integer,
intent(in),
optional :: is_in, ie_in, js_in, je_in
712 integer,
intent(in),
optional :: window_id
714 real ,
dimension(size(data_in,1), size(data_in,2), 1) :: data_out
715 logical,
dimension(size(data_in,1), size(data_in,2), 1) :: mask3d
717 data_out(:,:,1) = data_in(:,:)
718 call time_interp_external_3d(index, time, data_out, interp, verbose, horz_interp, mask3d, &
719 is_in=is_in,ie_in=ie_in,js_in=js_in,je_in=je_in,window_id=window_id)
720 data_in(:,:) = data_out(:,:,1)
721 if (
PRESENT(mask_out)) mask_out(:,:) = mask3d(:,:,1)
724 end subroutine time_interp_external_2d
752 subroutine time_interp_external_3d(index, time, data, interp,verbose,horz_interp, mask_out, is_in, ie_in, &
753 & js_in, je_in, window_id)
755 integer,
intent(in) :: index
756 type(time_type),
intent(in) :: time
757 real,
dimension(:,:,:),
intent(inout) :: data
758 integer,
intent(in),
optional :: interp
759 logical,
intent(in),
optional :: verbose
760 type(horiz_interp_type),
intent(in),
optional :: horz_interp
761 logical,
dimension(:,:,:),
intent(out),
optional :: mask_out
762 integer,
intent(in),
optional :: is_in, ie_in, js_in, je_in
763 integer,
intent(in),
optional :: window_id
765 integer :: nx, ny, nz, interp_method, t1, t2
766 integer :: i1, i2, isc, iec, jsc, jec, mod_time
767 integer :: yy, mm, dd, hh, min, ss
768 character(len=256) :: err_msg, filename
770 integer :: isw, iew, jsw, jew, nxw, nyw
778 character(len=16) :: message1, message2
784 interp_method = linear_time_interp
785 if (
PRESENT(interp)) interp_method = interp
787 if (
PRESENT(verbose)) verb=verbose
788 if (debug_this_module) verb = .true.
790 if (index < 1.or.index > num_fields) &
791 call mpp_error(fatal, &
792 &
'invalid index in call to time_interp_ext -- field was not initialized or failed to initialize')
794 isc=field(index)%isc;iec=field(index)%iec
795 jsc=field(index)%jsc;jec=field(index)%jec
797 if( field(index)%numwindows == 1 )
then
801 if( .not.
present(is_in) .or. .not.
present(ie_in) .or. .not.
present(js_in) .or. .not.
present(je_in) )
then
802 call mpp_error(fatal,
'time_interp_external: is_in, ie_in, js_in and je_in must be present ' // &
803 'when numwindows > 1, field='//trim(field(index)%name))
805 nxw = ie_in - is_in + 1
806 nyw = je_in - js_in + 1
807 isc = isc + is_in - 1
808 iec = isc + ie_in - is_in
809 jsc = jsc + js_in - 1
810 jec = jsc + je_in - js_in
813 isw = (nx-nxw)/2+1; iew = isw+nxw-1
814 jsw = (ny-nyw)/2+1; jew = jsw+nyw-1
816 if (nx < nxw .or. ny < nyw .or. nz < field(index)%siz(3))
then
817 write(message1,
'(i6,2i5)') nx,ny,nz
818 call mpp_error(fatal,
'field '//trim(field(index)%name)//
' Array size mismatch in time_interp_external.'// &
819 ' Array "data" is too small. shape(data)='//message1)
821 if(
PRESENT(mask_out))
then
822 if (
size(mask_out,1) /= nx .or.
size(mask_out,2) /= ny .or.
size(mask_out,3) /= nz)
then
823 write(message1,
'(i6,2i5)') nx,ny,nz
824 write(message2,
'(i6,2i5)')
size(mask_out,1),
size(mask_out,2),
size(mask_out,3)
825 call mpp_error(fatal,
'field '//trim(field(index)%name)//
' array size mismatch in time_interp_external.'// &
826 ' Shape of array "mask_out" does not match that of array "data".'// &
827 ' shape(data)='//message1//
' shape(mask_out)='//message2)
831 if (field(index)%siz(4) == 1)
then
833 call load_record(field(index),1,horz_interp, is_in, ie_in ,js_in, je_in,window_id)
834 i1 = find_buf_index(1,field(index)%ibuf)
835 if( field(index)%region_type == no_region )
then
836 where(field(index)%mask(isc:iec,jsc:jec,:,i1))
837 data(isw:iew,jsw:jew,:) = field(index)%data(isc:iec,jsc:jec,:,i1)
840 data(isw:iew,jsw:jew,:) = field(index)%missing
843 where(field(index)%mask(isc:iec,jsc:jec,:,i1))
844 data(isw:iew,jsw:jew,:) = field(index)%data(isc:iec,jsc:jec,:,i1)
847 if(
PRESENT(mask_out)) &
848 mask_out(isw:iew,jsw:jew,:) = field(index)%mask(isc:iec,jsc:jec,:,i1)
850 if(field(index)%have_modulo_times)
then
851 call time_interp(time,field(index)%modulo_time_beg, field(index)%modulo_time_end, field(index)%time(:), &
852 w2, t1, t2, field(index)%correct_leap_year_inconsistency, err_msg=err_msg)
853 if(err_msg .NE.
'')
then
855 call mpp_error(fatal,
"time_interp_external 1: "//trim(err_msg)//&
856 ",file="//trim(filename)//
",field="//trim(field(index)%name) )
859 if(field(index)%modulo_time)
then
864 call time_interp(time,field(index)%time(:),w2,t1,t2,modtime=mod_time, err_msg=err_msg)
865 if(err_msg .NE.
'')
then
867 call mpp_error(fatal,
"time_interp_external 2: "//trim(err_msg)//&
868 ",file="//trim(filename)//
",field="//trim(field(index)%name) )
873 call get_date(time,yy,mm,dd,hh,min,ss)
874 write(outunit,
'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
875 'target time yyyy/mm/dd hh:mm:ss= ',yy,
'/',mm,
'/',dd,hh,
':',min,
':',ss
876 write(outunit,*)
't1, t2, w1, w2= ', t1, t2, w1, w2
879 call load_record(field(index),t1,horz_interp, is_in, ie_in ,js_in, je_in, window_id)
880 call load_record(field(index),t2,horz_interp, is_in, ie_in ,js_in, je_in, window_id)
881 i1 = find_buf_index(t1,field(index)%ibuf)
882 i2 = find_buf_index(t2,field(index)%ibuf)
884 call mpp_error(fatal,
'time_interp_external : records were not loaded correctly in memory')
887 write(outunit,*)
'ibuf= ',field(index)%ibuf
888 write(outunit,*)
'i1,i2= ',i1, i2
891 if( field(index)%region_type == no_region )
then
892 where(field(index)%mask(isc:iec,jsc:jec,:,i1).and.field(index)%mask(isc:iec,jsc:jec,:,i2))
893 data(isw:iew,jsw:jew,:) = field(index)%data(isc:iec,jsc:jec,:,i1)*w1 + &
894 field(index)%data(isc:iec,jsc:jec,:,i2)*w2
897 data(isw:iew,jsw:jew,:) = field(index)%missing
900 where(field(index)%mask(isc:iec,jsc:jec,:,i1).and.field(index)%mask(isc:iec,jsc:jec,:,i2))
901 data(isw:iew,jsw:jew,:) = field(index)%data(isc:iec,jsc:jec,:,i1)*w1 + &
902 field(index)%data(isc:iec,jsc:jec,:,i2)*w2
905 if(
PRESENT(mask_out)) &
906 mask_out(isw:iew,jsw:jew,:) = &
907 field(index)%mask(isc:iec,jsc:jec,:,i1).and.&
908 field(index)%mask(isc:iec,jsc:jec,:,i2)
911 end subroutine time_interp_external_3d
915 subroutine time_interp_external_0d(index, time, data, verbose)
917 integer,
intent(in) :: index
918 type(time_type),
intent(in) :: time
919 real,
intent(inout) :: data
920 logical,
intent(in),
optional :: verbose
923 integer :: i1, i2, mod_time
924 integer :: yy, mm, dd, hh, min, ss
925 character(len=256) :: err_msg, filename
931 if (
PRESENT(verbose)) verb=verbose
932 if (debug_this_module) verb = .true.
934 if (index < 1.or.index > num_fields) &
935 call mpp_error(fatal, &
936 &
'invalid index in call to time_interp_ext -- field was not initialized or failed to initialize')
938 if (field(index)%siz(4) == 1)
then
940 call load_record_0d(field(index),1)
941 i1 = find_buf_index(1,field(index)%ibuf)
942 data = field(index)%data(1,1,1,i1)
944 if(field(index)%have_modulo_times)
then
945 call time_interp(time,field(index)%modulo_time_beg, field(index)%modulo_time_end, field(index)%time(:), &
946 w2, t1, t2, field(index)%correct_leap_year_inconsistency, err_msg=err_msg)
947 if(err_msg .NE.
'')
then
949 call mpp_error(fatal,
"time_interp_external 3:"//trim(err_msg)//&
950 ",file="//trim(filename)//
",field="//trim(field(index)%name) )
953 if(field(index)%modulo_time)
then
958 call time_interp(time,field(index)%time(:),w2,t1,t2,modtime=mod_time, err_msg=err_msg)
959 if(err_msg .NE.
'')
then
961 call mpp_error(fatal,
"time_interp_external 4:"//trim(err_msg)// &
962 ",file="//trim(filename)//
",field="//trim(field(index)%name) )
967 call get_date(time,yy,mm,dd,hh,min,ss)
968 write(outunit,
'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') &
969 'target time yyyy/mm/dd hh:mm:ss= ',yy,
'/',mm,
'/',dd,hh,
':',min,
':',ss
970 write(outunit,*)
't1, t2, w1, w2= ', t1, t2, w1, w2
972 call load_record_0d(field(index),t1)
973 call load_record_0d(field(index),t2)
974 i1 = find_buf_index(t1,field(index)%ibuf)
975 i2 = find_buf_index(t2,field(index)%ibuf)
978 call mpp_error(fatal,
'time_interp_external : records were not loaded correctly in memory')
979 data = field(index)%data(1,1,1,i1)*w1 + field(index)%data(1,1,1,i2)*w2
981 write(outunit,*)
'ibuf= ',field(index)%ibuf
982 write(outunit,*)
'i1,i2= ',i1, i2
986 end subroutine time_interp_external_0d
988 subroutine set_time_modulo(Time)
990 type(time_type),
intent(inout),
dimension(:) :: Time
993 integer :: yr, mon, dy, hr, minu, sec
995 ntime =
size(time(:))
998 call get_date(time(n), yr, mon, dy, hr, minu, sec)
1000 time(n) = set_date(yr, mon, dy, hr, minu, sec)
1004 end subroutine set_time_modulo
1008subroutine load_record(field, rec, interp, is_in, ie_in, js_in, je_in, window_id_in)
1009 type(ext_fieldtype),
intent(inout) :: field
1010 integer ,
intent(in) :: rec
1011 type(horiz_interp_type),
intent(in),
optional :: interp
1012 integer,
intent(in),
optional :: is_in, ie_in, js_in, je_in
1013 integer,
intent(in),
optional :: window_id_in
1017 integer :: isw,iew,jsw,jew
1018 integer :: is_region, ie_region, js_region, je_region, i, j
1019 integer :: start(4), nread(4)
1020 logical :: need_compute
1021 real :: mask_in(size(field%src_data,1),size(field%src_data,2),size(field%src_data,3))
1022 real,
allocatable :: mask_out(:,:,:)
1023 integer :: window_id
1026 if(
PRESENT(window_id_in) ) window_id = window_id_in
1027 need_compute = .true.
1030 ib = find_buf_index(rec,field%ibuf)
1034 need_compute = .false.
1037 field%nbuf = field%nbuf + 1
1038 if(field%nbuf >
size(field%data,4).or.field%nbuf <= 0) field%nbuf = 1
1040 field%ibuf(ib) = rec
1041 field%need_compute(ib,:) = .true.
1043 if (field%domain_present .and. .not.
PRESENT(interp))
then
1044 if (debug_this_module)
write(outunit,*)
'reading record with domain for field ',trim(field%name)
1045 call mpp_read(field%unit,field%field,field%domain,field%src_data(:,:,:,ib),rec)
1047 if (debug_this_module)
write(outunit,*)
'reading record without domain for field ',trim(field%name)
1048 start = 1; nread = 1
1049 start(1) = field%is_src; nread(1) = field%ie_src - field%is_src + 1
1050 start(2) = field%js_src; nread(2) = field%je_src - field%js_src + 1
1051 start(3) = 1; nread(3) =
size(field%src_data,3)
1052 start(field%tdim) = rec; nread(field%tdim) = 1
1053 call mpp_read(field%unit,field%field,field%src_data(:,:,:,ib),start,nread)
1057 isw=field%isc;iew=field%iec
1058 jsw=field%jsc;jew=field%jec
1060 if( field%numwindows > 1)
then
1061 if( .NOT.
PRESENT(is_in) .OR. .NOT.
PRESENT(ie_in) .OR. .NOT.
PRESENT(js_in) .OR. .NOT.
PRESENT(je_in) )
then
1062 call mpp_error(fatal, &
1063 &
'time_interp_external(load_record): is_in, ie_in, js_in, je_in must be present when numwindows>1')
1065 isw = isw + is_in - 1
1066 iew = isw + ie_in - is_in
1067 jsw = jsw + js_in - 1
1068 jew = jsw + je_in - js_in
1073 need_compute = field%need_compute(ib, window_id)
1074 if(need_compute)
then
1075 if(
PRESENT(interp))
then
1076 is_region = field%is_region; ie_region = field%ie_region
1077 js_region = field%js_region; je_region = field%je_region
1079 where (mpp_is_valid(field%src_data(:,:,:,ib), field%valid)) mask_in = 1.0
1080 if ( field%region_type .NE. no_region )
then
1081 if( any(mask_in == 0.0) )
then
1082 call mpp_error(fatal,
"time_interp_external: mask_in should be all 1 when region_type is not NO_REGION")
1084 if( field%region_type == outside_region)
then
1085 do j = js_region, je_region
1086 do i = is_region, ie_region
1087 mask_in(i,j,:) = 0.0
1091 do j = 1,
size(mask_in,2)
1092 do i = 1,
size(mask_in,1)
1093 if( j<js_region .OR. j>je_region .OR. i<is_region .OR. i>ie_region ) mask_in(i,j,:) = 0.0
1098 allocate(mask_out(isw:iew,jsw:jew,
size(field%src_data,3)))
1099 call horiz_interp(interp,field%src_data(:,:,:,ib),field%data(isw:iew,jsw:jew,:,ib), &
1103 field%mask(isw:iew,jsw:jew,:,ib) = mask_out(isw:iew,jsw:jew,:) > 0
1104 deallocate(mask_out)
1106 if ( field%region_type .NE. no_region )
then
1107 call mpp_error(fatal,
"time_interp_external: region_type should be NO_REGION when interp is not present")
1109 field%data(isw:iew,jsw:jew,:,ib) = field%src_data(isw:iew,jsw:jew,:,ib)
1110 field%mask(isw:iew,jsw:jew,:,ib) = mpp_is_valid(field%data(isw:iew,jsw:jew,:,ib),field%valid)
1113 where(field%mask(isw:iew,jsw:jew,:,ib)) field%data(isw:iew,jsw:jew,:,ib) = &
1114 field%data(isw:iew,jsw:jew,:,ib)*field%slope + field%intercept
1115 field%need_compute(ib, window_id) = .false.
1118end subroutine load_record
1121subroutine load_record_0d(field, rec)
1122 type(ext_fieldtype),
intent(inout) :: field
1123 integer ,
intent(in) :: rec
1126 integer :: start(4), nread(4)
1128 ib = find_buf_index(rec,field%ibuf)
1134 field%nbuf = field%nbuf + 1
1135 if(field%nbuf >
size(field%data,4).or.field%nbuf <= 0) field%nbuf = 1
1137 field%ibuf(ib) = rec
1139 if (debug_this_module)
write(outunit,*)
'reading record without domain for field ',trim(field%name)
1140 start = 1; nread = 1
1141 start(3) = 1; nread(3) =
size(field%src_data,3)
1142 start(field%tdim) = rec; nread(field%tdim) = 1
1143 call mpp_read(field%unit,field%field,field%src_data(:,:,:,ib),start,nread)
1144 if ( field%region_type .NE. no_region )
then
1145 call mpp_error(fatal,
"time_interp_external: region_type should be NO_REGION when field is scalar")
1147 field%data(1,1,:,ib) = field%src_data(1,1,:,ib)
1148 field%mask(1,1,:,ib) = mpp_is_valid(field%data(1,1,:,ib),field%valid)
1150 where(field%mask(1,1,:,ib)) field%data(1,1,:,ib) = &
1151 field%data(1,1,:,ib)*field%slope + field%intercept
1154end subroutine load_record_0d
1157subroutine reset_src_data_region(index, is, ie, js, je)
1158 integer,
intent(in) :: index
1159 integer,
intent(in) :: is, ie, js, je
1162 if( is == field(index)%is_src .AND. ie == field(index)%ie_src .AND. &
1163 js == field(index)%js_src .AND. ie == field(index)%je_src )
return
1165 if( .NOT.
ASSOCIATED(field(index)%src_data) )
call mpp_error(fatal, &
1166 "time_interp_external: field(index)%src_data is not associated")
1167 nk =
size(field(index)%src_data,3)
1168 nbuf =
size(field(index)%src_data,4)
1169 deallocate(field(index)%src_data)
1170 allocate(field(index)%src_data(is:ie,js:je,nk,nbuf))
1171 field(index)%is_src = is
1172 field(index)%ie_src = ie
1173 field(index)%js_src = js
1174 field(index)%je_src = je
1177end subroutine reset_src_data_region
1180subroutine set_override_region(index, region_type, is_region, ie_region, js_region, je_region)
1181 integer,
intent(in) :: index, region_type
1182 integer,
intent(in) :: is_region, ie_region, js_region, je_region
1184 field(index)%region_type = region_type
1185 field(index)%is_region = is_region
1186 field(index)%ie_region = ie_region
1187 field(index)%js_region = js_region
1188 field(index)%je_region = je_region
1192end subroutine set_override_region
1196subroutine realloc_files(n)
1197 integer,
intent(in) :: n
1199 type(filetype),
pointer :: ptr(:)
1202 if (
associated(opened_files))
then
1203 if (n <=
size(opened_files))
return
1208 ptr(i)%filename =
''
1212 if (
associated(opened_files))
then
1213 ptr(1:
size(opened_files)) = opened_files(:)
1214 deallocate(opened_files)
1218end subroutine realloc_files
1222subroutine realloc_fields(n)
1223 integer,
intent(in) :: n
1225 type(ext_fieldtype),
pointer :: ptr(:)
1228 if (
associated(field))
then
1229 if (n <=
size(field))
return
1239 ptr(i)%domain = null_domain2d
1240 ptr(i)%axes(:) = default_axis
1241 if (
ASSOCIATED(ptr(i)%time))
DEALLOCATE(ptr(i)%time, stat=ier)
1242 if (
ASSOCIATED(ptr(i)%start_time))
DEALLOCATE(ptr(i)%start_time, stat=ier)
1243 if (
ASSOCIATED(ptr(i)%end_time))
DEALLOCATE(ptr(i)%end_time, stat=ier)
1244 ptr(i)%field = default_field
1245 if (
ASSOCIATED(ptr(i)%period))
DEALLOCATE(ptr(i)%period, stat=ier)
1246 ptr(i)%modulo_time=.false.
1247 if (
ASSOCIATED(ptr(i)%data))
DEALLOCATE(ptr(i)%data, stat=ier)
1248 if (
ASSOCIATED(ptr(i)%ibuf))
DEALLOCATE(ptr(i)%ibuf, stat=ier)
1249 if (
ASSOCIATED(ptr(i)%src_data))
DEALLOCATE(ptr(i)%src_data, stat=ier)
1251 ptr(i)%domain_present=.false.
1253 ptr(i)%intercept=0.0
1254 ptr(i)%isc=-1;ptr(i)%iec=-1
1255 ptr(i)%jsc=-1;ptr(i)%jec=-1
1257 if (
associated(field))
then
1258 ptr(1:
size(field)) = field(:)
1263end subroutine realloc_fields
1266 function find_buf_index(indx,buf)
1268 integer,
dimension(:) :: buf
1269 integer :: find_buf_index
1278 if (buf(i) == indx)
then
1284 end function find_buf_index
1298 function get_external_field_size(index)
1301 integer :: get_external_field_size(4)
1303 if (index .lt. 1 .or. index .gt. num_fields) &
1304 call mpp_error(fatal,
'invalid index in call to get_external_field_size')
1307 get_external_field_size(1) = field(index)%siz(1)
1308 get_external_field_size(2) = field(index)%siz(2)
1309 get_external_field_size(3) = field(index)%siz(3)
1310 get_external_field_size(4) = field(index)%siz(4)
1312 end function get_external_field_size
1326 function get_external_field_missing(index)
1329 real :: get_external_field_missing
1331 if (index .lt. 1 .or. index .gt. num_fields) &
1332 call mpp_error(fatal,
'invalid index in call to get_external_field_size')
1336 get_external_field_missing = field(index)%missing
1338 end function get_external_field_missing
1353 function get_external_field_axes(index)
1356 type(axistype),
dimension(4) :: get_external_field_axes
1358 if (index .lt. 1 .or. index .gt. num_fields) &
1359 call mpp_error(fatal,
'invalid index in call to get_external_field_size')
1362 get_external_field_axes(1) = field(index)%axes(1)
1363 get_external_field_axes(2) = field(index)%axes(2)
1364 get_external_field_axes(3) = field(index)%axes(3)
1365 get_external_field_axes(4) = field(index)%axes(4)
1367 end function get_external_field_axes
1371subroutine get_time_axis(index, time)
1372 integer ,
intent(in) :: index
1373 type(time_type),
intent(out) :: time(:)
1377 if (index < 1.or.index > num_fields) &
1378 call mpp_error(fatal,
'invalid index in call to get_time_axis')
1380 n = min(
size(time),
size(field(index)%time))
1382 time(1:n) = field(index)%time(1:n)
1392 subroutine time_interp_external_exit()
1399 deallocate(field(i)%time,field(i)%start_time,field(i)%end_time,&
1400 field(i)%period,field(i)%data,field(i)%mask,field(i)%ibuf)
1401 if (
ASSOCIATED(field(i)%src_data))
deallocate(field(i)%src_data)
1403 field(i)%axes(j) = default_axis
1405 field(i)%domain = null_domain2d
1406 field(i)%field = default_field
1409 field(i)%intercept = 0.
1413 deallocate(opened_files)
1417 module_initialized = .false.
1419 end subroutine time_interp_external_exit
1422end module time_interp_external_mod
Added for mixed precision support. Updates force time_manager math to be done with kind=8 reals _wrap...
Subroutine for performing the horizontal interpolation between two grids.
These routines retrieve the axis specifications associated with the compute domains....
These routines retrieve the axis specifications associated with the data domains. The domain is a der...
These routines retrieve the axis specifications associated with the global domains....
The domain2D type contains all the necessary information to define the global, compute and data domai...
character(len=len(mpp_file(1)%name)) function mpp_get_file_name(unit)
return the file name of corresponding unit
subroutine mpp_get_info(unit, ndim, nvar, natt, ntime)
Get some general information about a file.
subroutine mpp_get_times(unit, time_values)
Get file time data.
subroutine mpp_get_fields(unit, variables)
Copy variable information from file (excluding data)
subroutine mpp_get_axes(unit, axes, time_axis)
Copy variable information from file (excluding data)
Get file global metadata.
Returns a weight and dates or indices for interpolating between two dates. The interface fraction_of_...
integer function, public days_in_year(time)
Returns the number of days in the calendar year corresponding to the date represented by time for the...
integer function, public get_calendar_type()
Returns default calendar type for mapping from time to date.
type(time_type) function, public increment_time(time, seconds, days, ticks, err_msg, allow_neg_inc)
Increments a time by seconds and days.
integer function, public days_in_month(time, err_msg)
Given a time, computes the corresponding date given the selected date time mapping algorithm.
subroutine, public get_time(time, seconds, days, ticks, err_msg)
Returns days and seconds ( < 86400 ) corresponding to a time. err_msg should be checked for any error...
subroutine, public get_date(time, year, month, day, hour, minute, second, tick, err_msg)
Gets the date for different calendar types. Given a time_interval, returns the corresponding date und...
Given an input date in year, month, days, etc., creates a time_type that represents this time interva...
Given some number of seconds and days, returns the corresponding time_type.
Type to represent amounts of time. Implemented as seconds and days to allow for larger intervals.