program concatnc ! ******************************************************** ! Program to concatenate data from Netcdf "diagfi" files, ! outputs from the martian GCM ! input : diagfi.nc / concat.nc / stats.nc kind of files ! author: Y. Wanherdrick ! + aps(), bps() and phisinit() are now also written ! to output file (E. Millour, september 2006) ! if available (F. Forget, october 2006) ! + handle 1D data (EM, January 2007) ! + ap(), bp() (F. Forget, February 2008) ! + handle the possibility that number of GCM layers (aps, bps ! or sigma) may be different from number of vertical levels ! of data (which is the case for outputs from 'zrecast') ! (EM, April 2010) ! + handle absence of ap() and bp() if aps and bps are available ! (case of stats file) FF, November 2011 ! + read and write controle field, if available. TN, October 2013 ! + possibility to concatenate concat files with a coherent ! time axis in the output, and to redistribute the time axis ! from an offset given by the user. AB, April 2020 ! ******************************************************** implicit none include "netcdf.inc" ! NetCDF definitions character (len=100), dimension(1000) :: file ! file(): input file(s) names(s) character (len=30), dimension(24) :: notconcat ! notconcat(): names of the (24) variables that won't be concatenated character (len=100), dimension(:), allocatable :: var ! var(): name(s) of variable(s) that will be concatenated character (len=100) :: tmpvar,tmpfile,long_name,units ! tmpvar(): used to temporarily store a variable name ! tmpfile(): used to temporarily store a file name ! long_name(): [netcdf] long_name attribute ! units(): [netcdf] units attribute character (len=100) :: filename,vartmp ! filename(): output file name ! vartmp(): temporary variable name (read from netcdf input file) character (len=50) :: altlong_name,altunits,altpositive ! altlong_name(): [netcdf] altitude "long_name" attribute ! altunits(): [netcdf] altitude "units" attribute ! altpositive(): [netcdf] altitude "positive" attribute character (len=4) :: axis ! axis: "sol" or "ls" or "adls" integer :: nid,ierr,miss,validr ! nid: [netcdf] file ID # ! ierr: [netcdf] subroutine returned error code ! miss: [netcdf] subroutine returned error code integer :: i,j,k,inter ! for various loops integer :: varid ! varid: [netcdf] variable ID # integer :: memolatlen=0,memolonlen=0,memoaltlen=0,memoctllen=0 ! memolatlen: # of elements of lat(), read from the first input file ! memolonlen: # of elements of lon(), read from the first input file ! memoaltlen: # of elements of alt(), read from the first input file ! memoctllen: # of elements of ctl(), read from the first input file real, dimension(:), allocatable:: lat,lon,alt,ctl,time ! lat(): array, stores latitude coordinates ! lon(): array, stores longitude coordinates ! alt(): array, stores altitude coordinates ! ctl(): array, stores controle coordinates ! time(): array, stores time coordinates integer :: nbvar,nbfile,nbvarfile,ndim ! nbvar: # of variables to concatenate ! nbfile: # number of input file(s) ! nbvarfile: total # of variables in an input file ! ndim: [netcdf] # (3 or 4) of dimensions (for variables) integer :: latdim,londim,altdim,ctldim,timedim ! latdim: [netcdf] "latitude" dim ID ! londim: [netcdf] "longitude" dim ID ! altdim: [netcdf] "altdim" dim ID ! ctldim: [netcdf] "ctldim" dim ID ! timedim: [netcdf] "timedim" dim ID integer :: gcmlayerdim ! NetCDF dimension ID for # of layers in GCM integer :: latvar,lonvar,altvar,ctlvar,timevar ! latvar: [netcdf] ID of "latitude" variable ! lonvar: [netcdf] ID of "longitude" variable ! altvar: [netcdf] ID of "altitude" variable ! ctlvar: [netcdf] ID of "controle" variable ! timevar: [netcdf] ID of "Time" variable integer :: latlen,lonlen,altlen,ctllen,timelen ! latlen: # of elements of lat() array ! lonlen: # of elements of lon() array ! altlen: # of elements of alt() array ! ctllen: # of elements of ctl() array ! timelen: # of elemnets of time() array integer :: GCM_layers ! number of GCM atmospheric layers (may not be ! same as altlen if file is an output of zrecast) integer :: nout,latdimout,londimout,altdimout,timedimout,timevarout ! nout: [netcdf] output file ID ! latdimout: [netcdf] output latitude (dimension) ID ! londimout: [netcdf] output longitude (dimension) ID ! altdimout: [netcdf] output altitude (dimension) ID ! timedimout: [netcdf] output time (dimension) ID ! timevarout: [netcdf] ID of output "Time" variable integer :: layerdimout ! NetCDF dimension ID for # of layers in GCM integer :: interlayerdimout ! dimension ID for # of interlayers in GCM integer :: reptime,rep,varidout ! reptime: total length of concatenated time() arrays ! rep: # number of elements of a time() array to write to the output file ! varidout: [netcdf] variable ID # (of a variable to write to the output file) integer :: Nnotconcat,var_ok ! Nnotconcat: # of (leading)variables that won't be concatenated ! var_ok: flag (0 or 1) integer, dimension(4) :: corner,edges,dim ! corner: [netcdf] ! edges: [netcdf] ! dim: [netcdf] real, dimension(:,:,:,:), allocatable :: var3d ! var3D(,,,): 4D array to store a field real :: ctlsol ! ctlsol: starting sol value of the file, stored in the variable ctl() real :: previous_last_output_time, output_time ! previous_last_output_time: last time stored in concat.nc after treating a file logical :: firstsol ! firstsol: true if the first file's starting day must be used in the output real :: startsol ! startsol: sol of the firstday as requested by the users (used if firstsol="y") real :: starttimeoffset ! starttimeoffset: offset given by the user for the output time axis (0 if ! firstsol="n") real :: missing !PARAMETER(missing=1E+20) ! missing: [netcdf] to handle "missing" values when reading/writing files real, dimension(2) :: valid_range ! valid_range(2): [netcdf] interval in which a value is considered valid real :: year_day = 669. !============================================================================== ! 1.1. Get input file name(s) !============================================================================== write(*,*) write(*,*) "-- Program written specifically for NetCDF 'diagfi'/'concat' files" write(*,*) " from the martian GCM --" write(*,*) write(*,*) "which files do you want to use?" write(*,*) " when list ok" nbfile=0 read(*,'(a50)') tmpfile do While (len_trim(tmpfile).ne.0) nbfile=nbfile+1 file(nbfile)=tmpfile read(*,'(a50)') tmpfile enddo if(nbfile==0) then write(*,*) "no file... game over" stop endif !============================================================================== ! 1.2. Ask for starting day value (starttimeoffset) !============================================================================== write(*,*) "Starting time in the concat file ?" write(*,*) " If you really wish to change it, write it now (not recommanded!)" write(*,*) " If you do not want to change it, just write 'n' (recommanded)" read(*,*,iostat=ierr) startsol firstsol= (ierr.eq.0) if (firstsol) then ! if nothing or a character that is not a float is read write(*,*) "1st input file's starting day will serve as starting day for the outfile." else ! if the user gave a number write(*,*) "Your input day will serve as starting day for the outfile." endif !============================================================================== ! 1.3. Open the first input file !============================================================================== write(*,*) write(*,*) "opening "//trim(file(1))//"..." ierr = NF_OPEN(file(1),NF_NOWRITE,nid) if (ierr.NE.NF_NOERR) then write(*,*) 'ERROR: Pb opening file '//file(1) stop endif ierr=NF_INQ_NVARS(nid,nbvarfile) ! nbvarfile now set to be the (total) number of variables in file !============================================================================== ! 1.4. Ask for (output) "Time" axis type !============================================================================== write(*,*) write(*,*) "Which time axis should be given in the output? (sol/ls/adls)" write(*,*) " (Warning: to read the result with grads, choose sol)" write(*,*) " To keep sol as the time axis, and just add Ls as a variable, type adls " read(*,*) axis ! loop as long as axis is neither "sol" nor "ls" do while ((axis/="sol").AND.(axis/="ls").AND.(axis/="adls")) read(*,*) axis enddo ! The following variables don't need to be concatenated notconcat(1)='Time' notconcat(2)='controle' notconcat(3)='rlonu' notconcat(4)='latitude' notconcat(5)='longitude' notconcat(6)='altitude' notconcat(7)='rlatv' notconcat(8)='aps' notconcat(9)='bps' notconcat(10)='ap' notconcat(11)='bp' notconcat(12)='cu' notconcat(13)='cv' notconcat(14)='aire' notconcat(15)='phisinit' notconcat(16)='soildepth' ! for XIOS files: notconcat(17)='lat' notconcat(18)='lon' notconcat(19)='time_instant' notconcat(20)='time_instant_bounds' notconcat(21)='time_counter' notconcat(22)='time_counter_bounds' notconcat(23)='area' notconcat(24)='phisfi' !============================================================================== ! 1.5. Get (and check) list of variables to concatenate !============================================================================== write(*,*) Nnotconcat=0 do i=1,nbvarfile ierr=NF_INQ_VARNAME(nid,i,vartmp) ! vartmp now contains the "name" of variable of ID # i var_ok=0 do inter=1,size(notconcat) if (vartmp.eq.notconcat(inter)) then var_ok=1 Nnotconcat=Nnotconcat+1 endif enddo if (var_ok.eq.0) write(*,*) trim(vartmp) enddo ! Nnotconcat: # of variables that won't be concatenated ! nbvarfile: total # of variables in file allocate(var(nbvarfile-Nnotconcat)) write(*,*) write(*,*) "which variables do you want to concatenate?" write(*,*) "all / list of (separated by s)" write(*,*) "(an empty line , i.e: just , implies end of list)" nbvar=0 read(*,'(a100)') tmpvar do while ((tmpvar/=' ').AND.(trim(tmpvar)/='all')) nbvar=nbvar+1 var(nbvar)=tmpvar read(*,'(a100)') tmpvar enddo if (tmpvar=="all") then if (axis=="ls") then nbvar=nbvarfile-Nnotconcat do j=Nnotconcat+1,nbvarfile ierr=nf_inq_varname(nid,j,var(j-Nnotconcat)) enddo endif ! of if (axis=="ls") ! Variables names from the file are catched nbvar=nbvarfile-Nnotconcat j=1 do i=1,nbvarfile ierr=nf_inq_varname(nid,i,vartmp) var_ok=0 do inter=1,size(notconcat) if (vartmp.eq.notconcat(inter)) then var_ok=1 endif enddo if (var_ok.eq.0) then if (j .gt. nbvar) then write(*,*) "PROBLEM HERE !", var stop endif var(j) = vartmp write(*,'(a9,1x,i2,1x,a1,1x,a50)') "variable ",j,":",var(j) j=j+1 endif enddo else if(nbvar==0) then write(*,*) "no variable... game over" stop endif ! of if (tmpvar=="all") !============================================================================== ! 1.6. Get output file name !============================================================================== filename="concat.nc" !============================================================================== ! 2. Concatenate input file(s) into output file !============================================================================== reptime=0 do i=1,nbfile !============================================================================== ! 2.1. Open input file !============================================================================== if (i/=1) then write(*,*) write(*,*) "opening "//trim(file(i))//"..." ierr = NF_OPEN(file(i),NF_NOWRITE,nid) if (ierr.NE.NF_NOERR) then write(*,*) 'ERROR: Pb opening file '//trim(file(i)) write(*,*) NF_STRERROR(ierr) stop endif endif !============================================================================== ! 2.2. Read (and check) dimensions of variables from input file !============================================================================== !============================================================================== ! 2.2.1 Lat, lon, alt, GCM_layers !============================================================================== ierr=NF_INQ_DIMID(nid,"latitude",latdim) ierr=NF_INQ_VARID(nid,"latitude",latvar) if (ierr.NE.NF_NOERR) then !failed to find "latitude"; look for "lat" instead ierr=NF_INQ_DIMID(nid,"lat",latdim) ierr=NF_INQ_VARID(nid,"lat",latvar) endif if (ierr.NE.NF_NOERR) then write(*,*) 'ERROR: Neither nor in file '//trim(file(i)) stop endif ierr=NF_INQ_DIMLEN(nid,latdim,latlen) ! write(*,*) "latlen: ",latlen ierr=NF_INQ_DIMID(nid,"longitude",londim) ierr=NF_INQ_VARID(nid,"longitude",lonvar) if (ierr.NE.NF_NOERR) then ! failed to find "longitude"; look for "lon" instead ierr=NF_INQ_DIMID(nid,"lon",londim) ierr=NF_INQ_VARID(nid,"lon",lonvar) endif if (ierr.NE.NF_NOERR) then write(*,*) 'ERROR: Neither nor in file '//trim(file(i)) stop endif ierr=NF_INQ_DIMLEN(nid,londim,lonlen) ! write(*,*) "lonlen: ",lonlen ierr=NF_INQ_DIMID(nid,"altitude",altdim) ierr=NF_INQ_VARID(nid,"altitude",altvar) if (ierr.NE.NF_NOERR) then write(*,*) 'ERROR: Field is missing in file '//trim(file(i)) stop endif ierr=NF_INQ_DIMLEN(nid,altdim,altlen) ! write(*,*) "altlen: ",altlen ! load size of aps() or sigma() (in case it is not altlen) ! default is that GCM_layers=altlen ! but for outputs of zrecast, it may be a different value ierr=NF_INQ_DIMID(nid,"GCM_layers",gcmlayerdim) if (ierr.ne.NF_NOERR) then ! didn't find a GCM_layers dimension; therefore we have: GCM_layers=altlen else ! load value of GCM_layers ierr=NF_INQ_DIMLEN(nid,gcmlayerdim,GCM_layers) endif ! write(*,*) "GCM_layers=",GCM_layers !============================================================================== ! 2.2.1 Check presence and read "controle" dimension & variable from input file !============================================================================== ctllen=-666 ! dummy initialization ierr=NF_INQ_DIMID(nid,"index",ctldim) if (ierr.NE.NF_NOERR) then ctllen=0 ! no "index", look for "controle_axe" instead ierr=NF_INQ_DIMID(nid,"controle_axe",ctldim) if (ierr.NE.NF_NOERR) then write(*,*) 'Neither nor in file '//trim(file(i)) write(*,*) "The program continues without ..." ctllen=0 else ierr=NF_INQ_DIMLEN(nid,ctldim,ctllen) endif else ierr=NF_INQ_DIMLEN(nid,ctldim,ctllen) endif ! allocate ctl (even if ctllen==0; required to not trigger errors in debug ! mode when ctl is passed as an argument to routines) allocate(ctl(ctllen)) if (ctllen .ne. 0) then ! variable controle available ierr=NF_INQ_VARID(nid,"controle",ctlvar) if (ierr.NE.NF_NOERR) then write(*,*) 'Field is missing in file '//trim(file(i)) write(*,*) "The program continues without ..." ctllen=0 ! seting that implies there is no "controle" later on else ierr = NF_GET_VAR_REAL(nid,ctlvar,ctl) ctlsol = ctl(4) endif endif !============================================================================== ! 2.3 Read "Time" dimension & variable from input file !============================================================================== ierr=NF_INQ_DIMID(nid,"Time",timedim) if (ierr.NE.NF_NOERR) then ! Time not found, look for "time_counter" instead ierr=NF_INQ_DIMID(nid,"time_counter",timedim) if (ierr.NE.NF_NOERR) then write(*,*) 'ERROR: Neither