! module hist_module implicit none ! ! History module contains non-user input variables to control ! primary and secondary history i/o, and defines the history ! structure type "history". A global variable "h" is declared ! type(history). ! ! Contained subroutines: ! sub hist_initype: initialize a history structure ! sub hist_print : print a history structure to stdout ! sub hist_init : initialize history control variables ! ! Procedure to add a new variable to the histories: ! 1. Add declarations to the history type below. ! 2. Add initialization of the new history structure component ! in sub hist_initype in this module. ! 3. Add write of new var to stdout in hist_print in this module. ! 4. Give value to the new structure component in sub define_hist ! (in output.f). The value may come from another module ! (e.g., "use input_mod"), or an included header file. ! (Define_hist is called prior to writing each history to disk). ! 5. Add definition of the new variable to the netcdf history file ! in sub nc_define (nchist_mod.F) (long name, units, etc) ! (declare variable id at top of nchist_mod.F, e.g., idv_ut, ! and make nc call according to dimensions and data type). ! (nc_define is called when a new netcdf history file is created) ! 6. Add value to the netcdf variable in nc_wrhist (nchist_mod.F) ! using the history structure component (e.g., h%ut) defined ! in step 4 above. ! 7. Add var to case statement in sub nc_rdhist (nchist_mod.F) ! for reading the variable from the source history. ! Make a short run to write the new variable to a history, which ! can then be used as a source history in subsequent runs. ! ! History parameters: ! integer,parameter :: | iprint = 0 ! print level flag logical :: netcdf ! true if writing netcdf histories ! ! Primary history related variables (not user input): integer :: | nseries, ! number of primary history time series (1-mxseries) | iseries, ! index to primary history time series | nsource, ! number of source files given (0 or 1) | nfiles_prim, ! number of history output files to be written | nstep_hist, ! number of steps between history writes | nstep_save, ! number of steps between history saves | nstep, ! total number of steps this run | ncid, ! netcdf file id (ignored if .not.netcdf) | nhist, ! number of prim histories written to current hist file | nhist_total, ! number of prim histories written during run | ioutfile, ! output(ioutfile) is current open hist file name | modeltime(4) ! current model time (day,hrs,mins,secs) ! ! Secondary history related variables (not user input): ! Primary histories can be written in up to mxseries separate ! time sequences. Secondary histories can be written in up to ! mxseries_sech time sequences. (see params.h) ! integer :: | isechist, ! secondary history flag (global 0 or 1) | nseries_sech, ! number of secondary hist time series (<=mxseries_sech) | iseries_sech, ! index to current sech time series | istep_sech, ! number of steps since beginning of sech series | nfiles_sech, ! number of history files to be written | nstep_sechist, ! number of steps between sec history writes | nstep_secsave, ! number of steps between sec history saves | ncidsech, ! netcdf sech file id (ignored if .not.netcdf) | nsech, ! number of sech histories written to current file | nsech_total, ! number of sech histories written during run | isecout, ! secout(isecout) is current open hist file name | nsecfmag, ! number of sech fields on magnetic grid | nsecfgeo ! number of sech fields on geographic grid ! ! History structure type: ! (grid dimensions and coordinate variables are written ! to history files from global common and parameters, ! so are not included in this structure) ! type history character(len=8) :: | model_version, ! version string (e.g., tgcm23) | model_name ! model name (e.g., time-gcm) character(len=16) :: | type, ! 'primary' or 'secondary' | host, ! host machine (getenv of 'HOST') | system, ! operating system (pre-proc macro) | logname ! user login (getenv of 'LOGNAME') character(len=24) :: | rundate ! local date of run character(len=80) :: | mss_path, ! mss path to file containing this history | mss_source ! mss path to source history file integer :: | ihist, ! ihist = nth history on current file | delhmins, ! delta minutes between histories | modeltime(4), ! model time (day,hour,minute,seconds) | time, ! model time (total minutes, includes day) | iter, ! iteration (# steps from 0,0,0) | year, ! 4-digit year | calday, ! calendar day (1-367) | step ! time step (seconds) real :: | ut, ! ut (decimal hours, from modeltime) | missing_value, ! missing value (usually spval) | p0, ! reference pressure | hpower, ! hemispheric power | ctpoten, ! cross-cap potential | byimf, ! by imf | f107d, ! daily f10.7 cm flux | f107a, ! 81-day average f10.7 cm flux | mag(2,2), ! magnetic pole coordinates | dtide(2), ! diurnal tide (tide2(2) from input) | sdtide(10), ! semi-diurnal tide (tide(10) from input) | colfac ! collision factor logical dynamo ! if true, is dynamo history logical coupled_ccm ! if true, run was coupled with ccm integer :: nflds, ! total number of fields on history | nfgeo, ! number of fields on geographic grid | nfmag ! number of fields on magnetic grid ! nflds = nfgeo+nfmag character(len=16), | pointer :: fnames(:) ! pointer to field names on this history end type history ! ! Global history structure variable: type(history) :: h contains !------------------------------------------------------------------- subroutine hist_initype(h,istep) ! ! Initialize a history structure: ! type(history),intent(out) :: h integer,intent(in) :: istep ! h%type = "unknown" h%ihist = -1 h%delhmins = -1 h%modeltime = (/-1,-1,-1,-1/) h%time = -1 h%iter = -1 h%year = -1 h%calday = -1 h%ut = -1. h%step = -1 h%nflds = -1 h%dynamo = .false. h%coupled_ccm = .false. ! ! If istep==0, h%f107, etc were defined from source history: if (istep > 0) then h%hpower = -1. h%ctpoten = -1. h%f107d = -1. h%f107a = -1. endif h%byimf = -1. h%mag(:,1) = (/-1.,-1./) h%mag(:,2) = (/-1.,-1./) h%dtide = (/-1.,-1./) h%sdtide = (/-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1.,-1./) h%colfac = -1. h%p0 = -1. if (associated(h%fnames)) deallocate(h%fnames) end subroutine hist_initype !------------------------------------------------------------------- subroutine hist_print(h,rdwr) ! ! Print info about a history structure: ! ! Args: type(history),intent(in) :: h character(len=*),intent(in) :: rdwr ! ! Locals: integer :: i ! write(6,"(/,72('-'))") if (h%type(1:3)=='pri') then if (rdwr=='WRITE') then write(6,"('Write TGCM PRIMARY HISTORY:')") else write(6,"('Read TGCM PRIMARY HISTORY (source history):')") endif elseif (h%type(1:3)=='sec') then if (rdwr=='WRITE') then write(6,"('Write TGCM SECONDARY HISTORY:')") else ! don't generally read sech, but you never know.. write(6,"('Read TGCM SECONDARY HISTORY:')") write(6,"('WARNING: Why am I reading a secondary history??')") write(6,"(9x,'The model will not start from secondary ', | 'history.')") endif else write(6,"('>>> print_hist: unknown type (apparently ', | 'not primary or secondary.')") endif ! write(6,"(2x,'rundate = ',a)") trim(h%rundate) write(6,"(2x,'logname = ',a)") trim(h%logname) write(6,"(2x,'host = ',a)") trim(h%host) write(6,"(2x,'system = ',a)") trim(h%system) write(6,"(2x,'model_name = ',a)") trim(h%model_name) write(6,"(2x,'model_version = ',a)") trim(h%model_version) write(6,"(2x,'mss_path = ',a)") trim(h%mss_path) write(6,"(2x,'mss_source = ',a)") trim(h%mss_source) write(6,"(2x,'type = ',a)") trim(h%type) write(6,"(2x,'ihist = ',i3,' (nth history on history file)')") | h%ihist write(6,"(2x,'delhmins= ',i4, | ' (delta minutes between histories)')") h%delhmins write(6,"(2x,'calendar year,day = ',i4,',',i3)") h%year,h%calday if (h%calday==0) then write(6,"(4x,'(model is NOT being advanced in calendar time)')") else write(6,"(4x,'(model IS being advanced in calendar time)')") endif write(6,"(2x,'modeltime = ',i3,',',i2,',',i2,',',i2 | ' (model time day,hour,minute,seconds)')") h%modeltime write(6,"(2x,'time = ',i8, | ' (total model time in minutes)')") h%time write(6,"(2x,'ut = ',f5.2,' (ut hours)')") h%ut write(6,"(2x,'step = ',i4,' (time step in seconds)')") | h%step write(6,"(2x,'iter = ',i8,' (number of steps from 0,0,0)')") | h%iter write(6,"(2x,'mag = ',4f7.2,' (magnetic pole coords)')") | h%mag write(6,"(2x,'dtide = ',e8.1,' ',f5.1, | ' (amp/phase of diurnal tide)')") h%dtide write(6,"(2x,'sdtide = ',5e8.1,' ',5f5.1,/, | 4x,'(amp/phase of semi-diurnal tide)')") h%sdtide write(6,"(2x,'f107d = ',f6.2,' (daily solar flux)')") h%f107d write(6,"(2x,'f107a = ',f6.2,' (average solar flux)')") h%f107a write(6,"(2x,'hpower = ',f5.2,' (Gw)')") h%hpower write(6,"(2x,'ctpoten = ',f5.2,' (Volts)')") h%ctpoten write(6,"(2x,'byimf = ',f5.2)") h%byimf write(6,"(2x,'colfac = ',f5.2)") h%colfac write(6,"(2x,'p0 = ',e8.2)") h%p0 write(6,"(2x,'nflds = ',i3,' (number of model fields)')") | h%nflds ! if (associated(h%fnames)) then write(6,"(' There are ',i3,' fields on this history,', + ' as follows:')") h%nflds do i=1,h%nflds write(6,"(2x,a)",advance="NO") h%fnames(i)(1:8) if (mod(i,8)==0.or.i==h%nflds) write(6,"(' ')") enddo endif ! write(6,"(72('-'),/)") return end subroutine hist_print !------------------------------------------------------------------- subroutine hist_init ! ! Initialize non-input history variables, using validated namelist ! user inputs from the input module: ! (this routine is called from init module after input validation) ! use input_module,only: start,stop,step,source,output,mkhvols, | hist,save,secstart,secstop,sechist,secsave,secout,secflds, | secfmag,mxhist_prim,mxhist_sech include "params.h" ! ! Local: integer :: secs_start(mxseries),secs_stop(mxseries), | secs_step,nh,nsteps,i,secs_hist,nsteps_hist,n character(len=80) :: hvols(mxhvols) ! ! External: integer,external :: mtime_to_mins,numfiles ! ! Number of primary history time series: nseries = (size(start)-count(start==ispval))/3 ! secs_start(:) = 0 do i=1,nseries secs_start(i) = mtime_to_mins(start(:,i))*60 secs_stop(i) = mtime_to_mins(stop(:,i))*60 enddo ! ! Total number of timesteps this run: nstep = (secs_stop(nseries)-secs_start(1))/step ! ! Number of source files given (0 or 1): if (len_trim(source)==0) then nsource = 0 else nsource = 1 endif ! ! Number of primary files to be written (nfiles_prim), and ! total primary histories to be written (nhist_total): nfiles_prim = numfiles('prim',nseries,nsource,nhist_total) ! ! Initialize for beginning of run: iseries = 1 nsech = 0 iseries_sech = 1 ! ! Initialize number of steps between primary history disk writes, ! and number of steps between primary history saves: nstep_hist = mtime_to_mins(hist(:,1))*60/step nstep_save = mtime_to_mins(save(:,1))*60/step ! ! Set secondary history non-input variables: ! ! n = total number of secondary history inputs read: n = size(secstart)-count(secstart==ispval) + | size(secstop) -count(secstop==ispval) + | size(sechist) -count(sechist==ispval) + | size(secsave) -count(secsave==ispval) + | size(secflds) -count(len_trim(secflds)==0) ! ! Number of secondary history time series: nseries_sech = (size(secstart)-count(secstart==ispval))/3 ! ! isechist: secondary histories flag: ! If no secondary history inputs were read, return. isechist = 0 if (n > 0) isechist = 1 if (isechist==0) return ! ! Secondary history init: secs_start(:) = 0 secs_start(:) = 0 do i=1,nseries_sech secs_start(i) = mtime_to_mins(secstart(:,i))*60 secs_stop(i) = mtime_to_mins(secstop(:,i))*60 enddo ! ! Number of fields on magnetic grid to be written to secondary histories: nsecfmag = size(secfmag)-count(len_trim(secfmag)==0) ! ! Number of fields on magnetic grid to be written to secondary histories: nsecfgeo = size(secflds)-count(len_trim(secflds)==0) ! ! Number of steps between secondary history disk writes: nstep_sechist = mtime_to_mins(sechist(:,1))*60/step nstep_secsave = mtime_to_mins(secsave(:,1))*60/step ! ! Number of secondary files to be written (nfiles_sech), and ! total secondary histories to be written (nsech_total): ! nfiles_sech = numfiles('sech',nseries_sech,1,nsech_total) ! end subroutine hist_init !------------------------------------------------------------------- subroutine mkfileinfo(ibeg_iyd,ibeg_day,ibeg_hr,ibeg_min, | iend_iyd,iend_day,iend_hr,iend_min, | idelmin,iendonly,tgcm_version,htype, | fileinfo) implicit none ! ! Build char*80 fileinfo field for mss history files containing info ! for the first and last histories on the file (year-day and model time) ! and the delta minutes between each history. Also include tgcm version ! name and secondary/primary history string. ! This char*80 is returned in fileinfo, and is written to the mss comment ! field by putms when the volume is disposed to mss. The information ! is then available via msls -x. ! ! On input: ! ibeg_iyd,ibeg_day,ibeg_hr,ibeg_min = year-day (i5) and model time ! of 1st history on the file. ! iend_iyd,iend_day,iend_hr,iend_min = year-day (i5) and model time ! of last history on the file. ! idelmin = time in minutes between each history (e.g. if histories ! are hourly, idelmin=60. ! tgcm_version = character name of tgcm_version (e.g., "tgcm22") ! isech = secondary history flag (if > 0, histories are secondary, ! otherwise are primary) ! ! On output: ! character(len=80) fileinfo is defined. ! ! Example output fileinfo: ! 96080 80, 0, 0 to 96084 84, 0, 0 by 720 tgcm22 primary ! ! Args: integer,intent(in) :: ibeg_iyd,ibeg_day,ibeg_hr,ibeg_min, | iend_iyd,iend_day,iend_hr,iend_min, | idelmin,iendonly character(len=80),intent(out) :: fileinfo character(len=*),intent(in) :: tgcm_version,htype ! ! Local: integer :: ibegiyd,ibegday,ibeghr,ibegmin, | iendiyd,iendday,iendhr,iendmin,lenversion c if (iendonly <= 0) then ibegiyd = ibeg_iyd ibegday = ibeg_day ibeghr = ibeg_hr ibegmin = ibeg_min else read(fileinfo,"(i5,1x,i3,1x,i2,1x,i2)",err=100) + ibegiyd,ibegday,ibeghr,ibegmin goto 101 100 write(6,"('>>> WARNING mkfileinfo: iendonly=',i2, + ' error reading beginning time: input fileinfo=',/a)") + fileinfo ibegiyd = -1 ibegday = -1 ibeghr = -1 ibegmin = -1 101 continue endif fileinfo = ' ' iendiyd = iend_iyd iendday = iend_day iendhr = iend_hr iendmin = iend_min lenversion = len_trim(tgcm_version) if (lenversion.gt.29) then write(6,"('>>> WARNING mkfileinfo: length of input string', + ' tgcm_version too long=',i3,' (will truncate to 29 chars)')") + lenversion lenversion = 27 endif c c Commas cannot be used in mss comment field because commas are the c mswrite option separator. c For now, colons are not used because they are the default separator c used by msrawinfo (which is called by msallinfo). c write(fileinfo,"(i5,' ',i3,' ',i2,' ',i2,' to ', + i5,' ',i3,' ',i2,' ',i2,' by ',i4,' ',a,' ',a)") + ibegiyd, ibegday, ibeghr, ibegmin, + iendiyd, iendday, iendhr, iendmin, idelmin, + tgcm_version(1:lenversion), htype ! write(6,"('mkfileinfo: fileinfo = ',/,a)") trim(fileinfo) end subroutine mkfileinfo end module hist_module