| [282] | 1 | program extract |
|---|
| 2 | |
|---|
| 3 | ! program to extract (ie: interpolates) pointwise values of an atmospheric |
|---|
| 4 | ! variable from a 'zrecast'ed diagfi file (works if altitude is geometrical |
|---|
| 5 | ! height or a pressure vertical coordinates) |
|---|
| 6 | ! user has to specify: |
|---|
| 7 | ! - name of input file |
|---|
| 8 | ! - date (in sols) offset wrt the input file (e.g. if the input file "begins" |
|---|
| 9 | ! at Ls=0, then the offset is 0; if the input file begins at Ls=30, the |
|---|
| 10 | ! offset date corresponding to the first 3 months is 61+66+66=193 sols, etc.) |
|---|
| 11 | ! - the "extraction mode": |
|---|
| 12 | ! 1: extract individual values; user will specify values of |
|---|
| 13 | ! lon lat alt Ls LT (all on a same line) |
|---|
| 14 | ! on as many lines as there are sought values |
|---|
| 15 | ! 2: extract a profile: user will specify on a first line the values of |
|---|
| 16 | ! lon lat Ls LT (all on a same line) |
|---|
| 17 | ! and then only specify values of altitudes (m or Pa depending on the |
|---|
| 18 | ! coordinate in the input file), one per line, at which values are |
|---|
| 19 | ! sought |
|---|
| [293] | 20 | ! - output values are sent to (ASCII) output file 'infile_var_.dat', where |
|---|
| 21 | ! 'infile' is the input file name (without trailing '.nc') and |
|---|
| 22 | ! 'var' is the sought variable, for extraction mode 1 as |
|---|
| 23 | ! lines of "lon lat alt Ls LT value" and for a profile (extraction mode 2) |
|---|
| [282] | 24 | ! as lines of "alt value" |
|---|
| 25 | ! |
|---|
| 26 | ! NB: If there is no data to do an appropriate interpolation to extract |
|---|
| 27 | ! the sought value, then a "missing_value" (taken from the variable's |
|---|
| 28 | ! attribute in the input file, most likely -9.99E33) is returned. |
|---|
| 29 | ! |
|---|
| 30 | ! EM. Sept. 2011 |
|---|
| 31 | |
|---|
| 32 | use netcdf |
|---|
| 33 | implicit none |
|---|
| 34 | |
|---|
| 35 | ! Input file: |
|---|
| 36 | character(len=256) :: infile |
|---|
| [293] | 37 | character(len=256) :: outfile |
|---|
| [282] | 38 | |
|---|
| [312] | 39 | character (len=256) :: text ! to store some text |
|---|
| [282] | 40 | character (len=64) :: varname ! to store the name of the variable to retreive |
|---|
| 41 | |
|---|
| 42 | ! NetCDF stuff |
|---|
| 43 | integer :: status ! NetCDF return code |
|---|
| 44 | integer :: inid ! NetCDF file IDs |
|---|
| 45 | integer :: varid ! to store the ID of a variable |
|---|
| 46 | integer :: lat_dimid,lon_dimid,alt_dimid,time_dimid |
|---|
| 47 | integer :: datashape(4) |
|---|
| 48 | |
|---|
| 49 | real,dimension(:),allocatable :: longitude ! longitude |
|---|
| 50 | integer lonlen ! # of grid points along longitude |
|---|
| 51 | real,dimension(:),allocatable :: latitude ! latitude |
|---|
| 52 | integer latlen ! # of grid points along latitude |
|---|
| 53 | real,dimension(:),allocatable :: altitude ! can be geometric heights or pressure |
|---|
| 54 | integer altlen ! # of grid point along altitude |
|---|
| 55 | real,dimension(:),allocatable :: time ! time |
|---|
| 56 | integer timelen ! # of points along time |
|---|
| 57 | character :: alttype ! altitude coord. type:'z' (altitude, m) 'p' (pressure, Pa) |
|---|
| 58 | real,dimension(:,:,:,:),allocatable :: field |
|---|
| 59 | real :: missing_value ! value to denote non-existant data |
|---|
| 60 | real :: starttimeoffset ! offset (in sols) wrt Ls=0 of sol 0 in file |
|---|
| 61 | integer :: extract_mode ! 1: point-by-point extraction 2: extract a profile |
|---|
| 62 | |
|---|
| 63 | ! point at which data is sought: |
|---|
| 64 | real :: lon,lat,alt,Ls,LT,value |
|---|
| 65 | real :: sol ! sol GCM date corresponding to sought Ls and LT |
|---|
| 66 | |
|---|
| 67 | integer :: nb |
|---|
| 68 | |
|---|
| 69 | !=============================================================================== |
|---|
| 70 | ! 1.1 Input file |
|---|
| 71 | !=============================================================================== |
|---|
| 72 | |
|---|
| 73 | write(*,*) "" |
|---|
| 74 | write(*,*) " Program valid for diagfi.nc or concatnc.nc files" |
|---|
| 75 | write(*,*) " processed by zrecast " |
|---|
| 76 | write(*,*) " Enter input file name:" |
|---|
| 77 | |
|---|
| 78 | read(*,'(a)') infile |
|---|
| 79 | write(*,*) "" |
|---|
| 80 | |
|---|
| 81 | ! open input file |
|---|
| 82 | status=nf90_open(infile,NF90_NOWRITE,inid) |
|---|
| 83 | if (status.ne.nf90_noerr) then |
|---|
| 84 | write(*,*)"Failed to open datafile ",trim(infile) |
|---|
| 85 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 86 | stop |
|---|
| 87 | endif |
|---|
| 88 | |
|---|
| 89 | write(*,*) " Beginning date of the file?" |
|---|
| 90 | write(*,*) " (i.e. number of sols since Ls=0 that the Time=0.0 in the input" |
|---|
| 91 | write(*,*) " file corresponds to)" |
|---|
| 92 | read(*,*) starttimeoffset |
|---|
| 93 | |
|---|
| 94 | write(*,*) " Extraction mode?" |
|---|
| 95 | write(*,*) " ( 1: pointwise extraction , 2: profile extraction)" |
|---|
| 96 | read(*,*,iostat=status) extract_mode |
|---|
| 97 | if ((status.ne.0).or.(extract_mode.lt.1) & |
|---|
| 98 | .or.(extract_mode.gt.2)) then |
|---|
| 99 | write(*,*) "Error: invalid extraction mode:",extract_mode |
|---|
| 100 | stop |
|---|
| 101 | endif |
|---|
| 102 | |
|---|
| 103 | !=============================================================================== |
|---|
| 104 | ! 1.2 Input variable to extract |
|---|
| 105 | !=============================================================================== |
|---|
| 106 | |
|---|
| 107 | write(*,*) "Enter variable to extract:" |
|---|
| 108 | read(*,*) varname |
|---|
| 109 | ! check that input file contains that variable |
|---|
| 110 | status=nf90_inq_varid(inid,trim(varname),varid) |
|---|
| 111 | if (status.ne.nf90_noerr) then |
|---|
| 112 | write(*,*) "Failed to find variable ",trim(varname)," in ",trim(infile) |
|---|
| 113 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 114 | write(*,*) " Might as well stop here." |
|---|
| 115 | stop |
|---|
| 116 | endif |
|---|
| 117 | |
|---|
| 118 | !=============================================================================== |
|---|
| 119 | ! 1.3 Get grids for dimensions lon,lat,alt,time |
|---|
| 120 | !=============================================================================== |
|---|
| 121 | |
|---|
| 122 | ! latitude |
|---|
| 123 | status=nf90_inq_dimid(inid,"latitude",lat_dimid) |
|---|
| 124 | if (status.ne.nf90_noerr) then |
|---|
| 125 | write(*,*)"Failed to find latitude dimension" |
|---|
| 126 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 127 | stop |
|---|
| 128 | endif |
|---|
| 129 | status=nf90_inquire_dimension(inid,lat_dimid,len=latlen) |
|---|
| 130 | if (status.ne.nf90_noerr) then |
|---|
| 131 | write(*,*)"Failed to find latitude length" |
|---|
| 132 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 133 | endif |
|---|
| 134 | allocate(latitude(latlen)) |
|---|
| 135 | status=nf90_inq_varid(inid,"latitude",varid) |
|---|
| 136 | if (status.ne.nf90_noerr) then |
|---|
| 137 | write(*,*) "Failed to find latitude ID" |
|---|
| 138 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 139 | stop |
|---|
| 140 | endif |
|---|
| 141 | ! read latitude |
|---|
| 142 | status=nf90_get_var(inid,varid,latitude) |
|---|
| 143 | if (status.ne.nf90_noerr) then |
|---|
| 144 | write(*,*) "Failed to load latitude" |
|---|
| 145 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 146 | stop |
|---|
| 147 | endif |
|---|
| 148 | |
|---|
| 149 | !longitude |
|---|
| 150 | status=nf90_inq_dimid(inid,"longitude",lon_dimid) |
|---|
| 151 | if (status.ne.nf90_noerr) then |
|---|
| 152 | write(*,*)"Failed to find longitude dimension" |
|---|
| 153 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 154 | stop |
|---|
| 155 | endif |
|---|
| 156 | status=nf90_inquire_dimension(inid,lon_dimid,len=lonlen) |
|---|
| 157 | if (status.ne.nf90_noerr) then |
|---|
| 158 | write(*,*)"Failed to find longitude length" |
|---|
| 159 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 160 | endif |
|---|
| 161 | allocate(longitude(lonlen)) |
|---|
| 162 | status=nf90_inq_varid(inid,"longitude",varid) |
|---|
| 163 | if (status.ne.nf90_noerr) then |
|---|
| 164 | write(*,*) "Failed to find longitude ID" |
|---|
| 165 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 166 | stop |
|---|
| 167 | endif |
|---|
| 168 | ! read longitude |
|---|
| 169 | status=nf90_get_var(inid,varid,longitude) |
|---|
| 170 | if (status.ne.nf90_noerr) then |
|---|
| 171 | write(*,*) "Failed to load longitude" |
|---|
| 172 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 173 | stop |
|---|
| 174 | endif |
|---|
| 175 | |
|---|
| 176 | !time |
|---|
| 177 | status=nf90_inq_dimid(inid,"Time",time_dimid) |
|---|
| 178 | if (status.ne.nf90_noerr) then |
|---|
| 179 | write(*,*)"Failed to find Time dimension" |
|---|
| 180 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 181 | stop |
|---|
| 182 | endif |
|---|
| 183 | status=nf90_inquire_dimension(inid,time_dimid,len=timelen) |
|---|
| 184 | if (status.ne.nf90_noerr) then |
|---|
| 185 | write(*,*)"Failed to find Time length" |
|---|
| 186 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 187 | endif |
|---|
| 188 | allocate(time(timelen)) |
|---|
| 189 | status=nf90_inq_varid(inid,"Time",varid) |
|---|
| 190 | if (status.ne.nf90_noerr) then |
|---|
| 191 | write(*,*) "Failed to find Time ID" |
|---|
| 192 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 193 | stop |
|---|
| 194 | endif |
|---|
| 195 | ! read Time |
|---|
| 196 | status=nf90_get_var(inid,varid,time) |
|---|
| 197 | if (status.ne.nf90_noerr) then |
|---|
| 198 | write(*,*) "Failed to load Time" |
|---|
| 199 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 200 | stop |
|---|
| 201 | endif |
|---|
| 202 | ! add the offset to time(:) |
|---|
| 203 | time(:)=time(:)+starttimeoffset |
|---|
| 204 | |
|---|
| 205 | !altitude |
|---|
| 206 | status=nf90_inq_dimid(inid,"altitude",alt_dimid) |
|---|
| 207 | if (status.ne.nf90_noerr) then |
|---|
| 208 | write(*,*)"Failed to find altitude dimension" |
|---|
| 209 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 210 | stop |
|---|
| 211 | endif |
|---|
| 212 | status=nf90_inquire_dimension(inid,alt_dimid,len=altlen) |
|---|
| 213 | if (status.ne.nf90_noerr) then |
|---|
| 214 | write(*,*)"Failed to find altitude length" |
|---|
| 215 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 216 | endif |
|---|
| 217 | allocate(altitude(altlen)) |
|---|
| 218 | status=nf90_inq_varid(inid,"altitude",varid) |
|---|
| 219 | if (status.ne.nf90_noerr) then |
|---|
| 220 | write(*,*) "Failed to find altitude ID" |
|---|
| 221 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 222 | stop |
|---|
| 223 | endif |
|---|
| 224 | ! read altitude |
|---|
| 225 | status=nf90_get_var(inid,varid,altitude) |
|---|
| 226 | if (status.ne.nf90_noerr) then |
|---|
| 227 | write(*,*) "Failed to load altitude" |
|---|
| 228 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 229 | stop |
|---|
| 230 | endif |
|---|
| 231 | ! check altitude attribute "units" to find out altitude type |
|---|
| 232 | status=nf90_get_att(inid,varid,"units",text) |
|---|
| 233 | if (status.ne.nf90_noerr) then |
|---|
| 234 | write(*,*) "Failed to load altitude units attribute" |
|---|
| 235 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 236 | stop |
|---|
| 237 | else |
|---|
| 238 | if (trim(text).eq."Pa") then |
|---|
| 239 | alttype="p" ! pressure coordinate |
|---|
| 240 | else if (trim(text).eq."m") then |
|---|
| 241 | alttype="z" ! altitude coordinate |
|---|
| 242 | else |
|---|
| 243 | write(*,*)" I do not understand this unit ",trim(text)," for altitude!" |
|---|
| 244 | stop |
|---|
| 245 | endif |
|---|
| 246 | endif |
|---|
| 247 | |
|---|
| 248 | !=============================================================================== |
|---|
| 249 | ! 1.3 Get input dataset |
|---|
| 250 | !=============================================================================== |
|---|
| 251 | status=nf90_inq_varid(inid,trim(varname),varid) |
|---|
| 252 | if (status.ne.nf90_noerr) then |
|---|
| 253 | write(*,*) "Failed to find variable ",trim(varname)," in ",trim(infile) |
|---|
| 254 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 255 | write(*,*) " Might as well stop here." |
|---|
| 256 | stop |
|---|
| 257 | endif |
|---|
| 258 | |
|---|
| 259 | ! sanity checks on the variable |
|---|
| 260 | status=nf90_inquire_variable(inid,varid,ndims=nb,dimids=datashape) |
|---|
| 261 | if (status.ne.nf90_noerr) then |
|---|
| 262 | write(*,*) "Failed to obtain information on variable ",trim(varname) |
|---|
| 263 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 264 | write(*,*) " Might as well stop here." |
|---|
| 265 | stop |
|---|
| 266 | else |
|---|
| 267 | ! check that it is a 4D variable |
|---|
| 268 | if (nb.ne.4) then |
|---|
| 269 | write(*,*) "Error, expected a 4D (lon-lat-alt-time) variable!" |
|---|
| 270 | stop |
|---|
| 271 | endif |
|---|
| 272 | ! check that its dimensions are indeed lon,lat,alt,time |
|---|
| 273 | if (datashape(1).ne.lon_dimid) then |
|---|
| 274 | write(*,*) "Error, expected first dimension to be longitude!" |
|---|
| 275 | stop |
|---|
| 276 | endif |
|---|
| 277 | if (datashape(2).ne.lat_dimid) then |
|---|
| 278 | write(*,*) "Error, expected second dimension to be latitude!" |
|---|
| 279 | stop |
|---|
| 280 | endif |
|---|
| 281 | if (datashape(3).ne.alt_dimid) then |
|---|
| 282 | write(*,*) "Error, expected third dimension to be altitude!" |
|---|
| 283 | stop |
|---|
| 284 | endif |
|---|
| 285 | if (datashape(4).ne.time_dimid) then |
|---|
| 286 | write(*,*) "Error, expected fourth dimension to be time!" |
|---|
| 287 | stop |
|---|
| 288 | endif |
|---|
| 289 | endif |
|---|
| 290 | |
|---|
| 291 | allocate(field(lonlen,latlen,altlen,timelen)) |
|---|
| 292 | |
|---|
| 293 | ! load dataset |
|---|
| 294 | status=nf90_get_var(inid,varid,field) |
|---|
| 295 | if (status.ne.nf90_noerr) then |
|---|
| 296 | write(*,*) "Failed to load ",trim(varname) |
|---|
| 297 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 298 | stop |
|---|
| 299 | else |
|---|
| 300 | write(*,*) "Loaded ",trim(varname) |
|---|
| 301 | endif |
|---|
| 302 | ! get dataset's missing_value attribute |
|---|
| 303 | status=nf90_get_att(inid,varid,"missing_value",missing_value) |
|---|
| 304 | if (status.ne.nf90_noerr) then |
|---|
| 305 | write(*,*) "Failed to load missing_value attribute" |
|---|
| 306 | write(*,*)trim(nf90_strerror(status)) |
|---|
| 307 | stop |
|---|
| 308 | else |
|---|
| 309 | write(*,'(" with missing_value attribute : ",1pe12.5)'),missing_value |
|---|
| 310 | endif |
|---|
| 311 | |
|---|
| 312 | !=============================================================================== |
|---|
| 313 | ! 2. Process and interpolate |
|---|
| 314 | !=============================================================================== |
|---|
| [293] | 315 | |
|---|
| 316 | !=============================================================================== |
|---|
| 317 | ! 2.1 Create output file |
|---|
| 318 | !=============================================================================== |
|---|
| 319 | |
|---|
| 320 | outfile=trim(infile(1:index(infile,".nc",back=.true.)-1))//"_"//& |
|---|
| 321 | trim(varname)//".dat" |
|---|
| 322 | open(42,file=outfile,form="formatted") |
|---|
| 323 | write(*,*) "Output file is: ",trim(outfile) |
|---|
| 324 | |
|---|
| 325 | !=============================================================================== |
|---|
| 326 | ! 2.2 Extract values |
|---|
| 327 | !=============================================================================== |
|---|
| 328 | |
|---|
| [282] | 329 | if (extract_mode==1) then ! pointwise extraction |
|---|
| 330 | write(*,*) " Enter values of: lon lat alt Ls LT (all on the same line," |
|---|
| 331 | write(*,*) " using as many lines as sought data values)" |
|---|
| 332 | write(*,*) " (enter anything else, e.g. blank line, nonesense,... to quit)" |
|---|
| 333 | else ! extract_mode==2 , profile extraction |
|---|
| 334 | write(*,*) " Enter values of: lon lat Ls LT (all on the same line)" |
|---|
| 335 | read(*,*) lon,lat,Ls,LT |
|---|
| 336 | write(*,*) " Enter values of altitude (one per line)" |
|---|
| 337 | write(*,*) " (enter anything else, e.g. blank line, nonesense,... to quit)" |
|---|
| 338 | endif |
|---|
| 339 | do |
|---|
| 340 | ! 2.1 read coordinates and do some sanity checks |
|---|
| [312] | 341 | text="" !initialize text to empty string |
|---|
| 342 | read(*,'(a)') text ! store input as text (to spot empty input line) |
|---|
| 343 | if (len_trim(adjustl(text)).eq.0) exit |
|---|
| 344 | |
|---|
| [282] | 345 | if (extract_mode==1) then |
|---|
| [312] | 346 | read(text,*,iostat=status) lon,lat,alt,Ls,LT |
|---|
| [282] | 347 | ! Ls in degrees, LT (local true solar time) in hours, i.e. in [0:24] |
|---|
| 348 | else ! extract_mode==2 , read alt only |
|---|
| [312] | 349 | read(text,*,iostat=status) alt |
|---|
| [282] | 350 | endif |
|---|
| 351 | if (status.ne.0) exit |
|---|
| 352 | |
|---|
| 353 | if ((lon.lt.-360.).or.(lon.gt.360.)) then |
|---|
| 354 | write(*,*) "Unexpected value for lon: ",lon |
|---|
| 355 | stop |
|---|
| 356 | endif |
|---|
| 357 | ! we want lon in [-180:180] |
|---|
| 358 | if (lon.lt.-180.) lon=lon+360. |
|---|
| [954] | 359 | if (lon.gt.180.) lon=lon-360. |
|---|
| [282] | 360 | |
|---|
| 361 | if ((lat.lt.-90.).or.(lat.gt.90.)) then |
|---|
| 362 | write(*,*) "Unexpected value for lat: ",lat |
|---|
| 363 | stop |
|---|
| 364 | endif |
|---|
| 365 | |
|---|
| 366 | if ((Ls.lt.0.).or.(Ls.gt.360.)) then |
|---|
| 367 | write(*,*) "Unexpected value for Ls: ",Ls |
|---|
| 368 | stop |
|---|
| 369 | endif |
|---|
| 370 | |
|---|
| 371 | if ((LT.lt.0.).or.(LT.gt.24.)) then |
|---|
| 372 | write(*,*) "Unexpected value for LT: ",LT |
|---|
| 373 | stop |
|---|
| 374 | endif |
|---|
| 375 | |
|---|
| 376 | ! 2.2 compute GCM sol date corresponding to sought Ls and LT |
|---|
| 377 | call ls2sol(Ls,sol) |
|---|
| 378 | !shift 'sol' decimal part to ensure a compatible LT with the desired one |
|---|
| 379 | sol=floor(sol)+(LT-lon/15.)/24. |
|---|
| 380 | ! handle bordeline cases: |
|---|
| 381 | if (sol.gt.669) sol=sol-669 |
|---|
| 382 | if (sol.lt.0) sol=sol+669 |
|---|
| 383 | |
|---|
| 384 | ! write(*,*) " Ls=",Ls," LT=",LT," => sol=",sol |
|---|
| 385 | |
|---|
| 386 | ! 2.3 do the interpolation |
|---|
| 387 | call extraction(lon,lat,alt,sol,& |
|---|
| 388 | lonlen,latlen,altlen,timelen,& |
|---|
| 389 | longitude,latitude,altitude,time,& |
|---|
| 390 | field,missing_value,alttype,varname,value) |
|---|
| 391 | ! 2.4 Write value to output |
|---|
| 392 | if (extract_mode==1) then ! pointwise extraction |
|---|
| [293] | 393 | write(42,'(6(1x,1pe12.5))')lon,lat,alt,Ls,LT,value |
|---|
| [282] | 394 | else ! profile |
|---|
| [293] | 395 | write(42,'(6(1x,1pe12.5))')alt,value |
|---|
| [282] | 396 | endif |
|---|
| 397 | enddo ! of do while |
|---|
| 398 | |
|---|
| [293] | 399 | ! close output file |
|---|
| 400 | close(42) |
|---|
| [282] | 401 | |
|---|
| 402 | end program extract |
|---|
| 403 | |
|---|
| 404 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 405 | subroutine extraction(lon,lat,alt,sol,& |
|---|
| 406 | lonlen,latlen,altlen,timelen,& |
|---|
| 407 | longitude,latitude,altitude,time,& |
|---|
| 408 | field,missing_value,alttype,varname,value) |
|---|
| 409 | |
|---|
| 410 | implicit none |
|---|
| 411 | ! Arguments: |
|---|
| 412 | real,intent(in) :: lon ! sought longitude (deg, in [-180:180]) |
|---|
| 413 | real,intent(in) :: lat ! sought latitude (deg, in [-90:90]) |
|---|
| 414 | real,intent(in) :: alt ! sought altitude (m or Pa) |
|---|
| 415 | real,intent(in) :: sol ! sought date (sols) |
|---|
| 416 | integer,intent(in) :: lonlen |
|---|
| 417 | integer,intent(in) :: latlen |
|---|
| 418 | integer,intent(in) :: altlen |
|---|
| 419 | integer,intent(in) :: timelen |
|---|
| 420 | real,intent(in) :: longitude(lonlen) |
|---|
| 421 | real,intent(in) :: latitude(latlen) |
|---|
| 422 | real,intent(in) :: altitude(altlen) |
|---|
| 423 | real,intent(in) :: time(timelen) |
|---|
| 424 | real,intent(in) :: field(lonlen,latlen,altlen,timelen) |
|---|
| 425 | real,intent(in) :: missing_value ! default value in GCM file for "no data" |
|---|
| 426 | character,intent(in) :: alttype ! altitude coord. type:'z' (altitude, m) |
|---|
| 427 | ! 'p' (pressure, Pa) |
|---|
| 428 | character(len=*),intent(in) :: varname ! variable name (in GCM file) |
|---|
| 429 | real,intent(out) :: value |
|---|
| 430 | |
|---|
| 431 | ! Local variables: |
|---|
| 432 | real,save :: prev_lon=-99 ! previous value of 'lon' routine was called with |
|---|
| 433 | real,save :: prev_lat=-99 ! previous value of 'lat' routine was called with |
|---|
| 434 | real,save :: prev_alt=-9.e20 ! ! previous value of 'alt' |
|---|
| 435 | real,save :: prev_sol=-99 ! previous value of 'sol' routine was called with |
|---|
| 436 | |
|---|
| 437 | ! encompasing indexes: |
|---|
| 438 | integer,save :: ilon_inf=-1,ilon_sup=-1 ! along longitude |
|---|
| 439 | integer,save :: ilat_inf=-1,ilat_sup=-1 ! along latitude |
|---|
| 440 | integer,save :: ialt_inf=-1,ialt_sup=-1 ! along altitude |
|---|
| 441 | integer,save :: itim_inf=-1,itim_sup=-1 ! along time |
|---|
| 442 | |
|---|
| 443 | ! intermediate interpolated values |
|---|
| 444 | real :: t_interp(2,2,2) ! after time interpolation |
|---|
| 445 | real :: zt_interp(2,2) ! after altitude interpolation |
|---|
| 446 | real :: yzt_interp(2) ! after latitude interpolation |
|---|
| 447 | real :: coeff ! interpolation coefficient |
|---|
| 448 | |
|---|
| 449 | integer :: i |
|---|
| 450 | |
|---|
| 451 | ! By default, set value to missing_value |
|---|
| 452 | value=missing_value |
|---|
| 453 | |
|---|
| 454 | ! 1. Find encompassing indexes |
|---|
| 455 | if (lon.ne.prev_lon) then |
|---|
| 456 | do i=1,lonlen-1 |
|---|
| 457 | if (longitude(i).le.lon) then |
|---|
| 458 | ilon_inf=i |
|---|
| 459 | else |
|---|
| 460 | exit |
|---|
| 461 | endif |
|---|
| 462 | enddo |
|---|
| 463 | ilon_sup=ilon_inf+1 |
|---|
| 464 | endif ! of if (lon.ne.prev_lon) |
|---|
| 465 | !write(*,*) 'ilon_inf=',ilon_inf," longitude(ilon_inf)=",longitude(ilon_inf) |
|---|
| 466 | |
|---|
| 467 | if (lat.ne.prev_lat) then |
|---|
| 468 | ! recall that latitudes start from north pole |
|---|
| 469 | do i=1,latlen-1 |
|---|
| 470 | if (latitude(i).ge.lat) then |
|---|
| 471 | ilat_inf=i |
|---|
| 472 | else |
|---|
| 473 | exit |
|---|
| 474 | endif |
|---|
| 475 | enddo |
|---|
| 476 | ilat_sup=ilat_inf+1 |
|---|
| 477 | endif ! of if (lat.ne.prev_lat) |
|---|
| 478 | !write(*,*) 'ilat_inf=',ilat_inf," latitude(ilat_inf)=",latitude(ilat_inf) |
|---|
| 479 | |
|---|
| 480 | if (alt.ne.prev_alt) then |
|---|
| 481 | if (alttype.eq.'p') then ! pressures are ordered from max to min |
|---|
| 482 | !handle special case for alt not in the altitude(1:altlen) interval |
|---|
| 483 | if ((alt.gt.altitude(1)).or.(alt.lt.altitude(altlen))) then |
|---|
| 484 | ialt_inf=-1 |
|---|
| 485 | ialt_sup=-1 |
|---|
| 486 | ! return to main program (with value=missing_value) |
|---|
| 487 | return |
|---|
| 488 | else ! general case |
|---|
| 489 | do i=1,altlen-1 |
|---|
| 490 | if (altitude(i).ge.alt) then |
|---|
| 491 | ialt_inf=i |
|---|
| 492 | else |
|---|
| 493 | exit |
|---|
| 494 | endif |
|---|
| 495 | enddo |
|---|
| 496 | ialt_sup=ialt_inf+1 |
|---|
| 497 | endif ! of if ((alt.gt.altitude(1)).or.(alt.lt.altitude(altlen))) |
|---|
| 498 | else ! altitudes (m) are ordered from min to max |
|---|
| 499 | !handle special case for alt not in the altitude(1:altlen) interval |
|---|
| 500 | if ((alt.lt.altitude(1)).or.(alt.gt.altitude(altlen))) then |
|---|
| 501 | ialt_inf=-1 |
|---|
| 502 | ialt_sup=-1 |
|---|
| 503 | ! return to main program (with value=missing_value) |
|---|
| 504 | return |
|---|
| 505 | else ! general case |
|---|
| 506 | do i=1,altlen-1 |
|---|
| 507 | if (altitude(i).le.alt) then |
|---|
| 508 | ialt_inf=i |
|---|
| 509 | else |
|---|
| 510 | exit |
|---|
| 511 | endif |
|---|
| 512 | enddo |
|---|
| 513 | ialt_sup=ialt_inf+1 |
|---|
| 514 | endif ! of if ((alt.lt.altitude(1)).or.(alt.gt.altitude(altlen))) |
|---|
| 515 | endif ! of if (alttype.eq.'p') |
|---|
| 516 | endif ! of if (alt.ne.prev_alt) |
|---|
| 517 | !write(*,*) 'ialt_inf=',ialt_inf," altitude(ialt_inf)=",altitude(ialt_inf) |
|---|
| 518 | |
|---|
| 519 | if (sol.ne.prev_sol) then |
|---|
| 520 | !handle special case for sol not in the time(1):time(timenlen) interval |
|---|
| 521 | if ((sol.lt.time(1)).or.(sol.gt.time(timelen))) then |
|---|
| 522 | itim_inf=-1 |
|---|
| 523 | itim_sup=-1 |
|---|
| 524 | ! return to main program (with value=missing_value) |
|---|
| 525 | return |
|---|
| 526 | else ! general case |
|---|
| 527 | do i=1,timelen-1 |
|---|
| 528 | if (time(i).le.sol) then |
|---|
| 529 | itim_inf=i |
|---|
| 530 | else |
|---|
| 531 | exit |
|---|
| 532 | endif |
|---|
| 533 | enddo |
|---|
| 534 | itim_sup=itim_inf+1 |
|---|
| 535 | endif ! of if ((sol.lt.time(1)).or.(sol.gt.time(timenlen))) |
|---|
| 536 | endif ! of if (sol.ne.prev_sol) |
|---|
| 537 | !write(*,*) 'itim_inf=',itim_inf," time(itim_inf)=",time(itim_inf) |
|---|
| 538 | !write(*,*) 'itim_sup=',itim_sup," time(itim_sup)=",time(itim_sup) |
|---|
| 539 | |
|---|
| 540 | ! 2. Interpolate |
|---|
| 541 | ! check that there are no "missing_value" in the field() elements we need |
|---|
| 542 | ! otherwise return to main program (with value=missing_value) |
|---|
| 543 | if (field(ilon_inf,ilat_inf,ialt_inf,itim_inf).eq.missing_value) return |
|---|
| 544 | if (field(ilon_inf,ilat_inf,ialt_inf,itim_sup).eq.missing_value) return |
|---|
| 545 | if (field(ilon_inf,ilat_inf,ialt_sup,itim_inf).eq.missing_value) return |
|---|
| 546 | if (field(ilon_inf,ilat_inf,ialt_sup,itim_sup).eq.missing_value) return |
|---|
| 547 | if (field(ilon_inf,ilat_sup,ialt_inf,itim_inf).eq.missing_value) return |
|---|
| 548 | if (field(ilon_inf,ilat_sup,ialt_inf,itim_sup).eq.missing_value) return |
|---|
| 549 | if (field(ilon_inf,ilat_sup,ialt_sup,itim_inf).eq.missing_value) return |
|---|
| 550 | if (field(ilon_inf,ilat_sup,ialt_sup,itim_sup).eq.missing_value) return |
|---|
| 551 | if (field(ilon_sup,ilat_inf,ialt_inf,itim_inf).eq.missing_value) return |
|---|
| 552 | if (field(ilon_sup,ilat_inf,ialt_inf,itim_sup).eq.missing_value) return |
|---|
| 553 | if (field(ilon_sup,ilat_inf,ialt_sup,itim_inf).eq.missing_value) return |
|---|
| 554 | if (field(ilon_sup,ilat_inf,ialt_sup,itim_sup).eq.missing_value) return |
|---|
| 555 | if (field(ilon_sup,ilat_sup,ialt_inf,itim_inf).eq.missing_value) return |
|---|
| 556 | if (field(ilon_sup,ilat_sup,ialt_inf,itim_sup).eq.missing_value) return |
|---|
| 557 | if (field(ilon_sup,ilat_sup,ialt_sup,itim_inf).eq.missing_value) return |
|---|
| 558 | if (field(ilon_sup,ilat_sup,ialt_sup,itim_sup).eq.missing_value) return |
|---|
| 559 | |
|---|
| 560 | ! 2.1 Linear interpolation in time |
|---|
| 561 | coeff=(sol-time(itim_inf))/(time(itim_sup)-time(itim_inf)) |
|---|
| 562 | t_interp(1,1,1)=field(ilon_inf,ilat_inf,ialt_inf,itim_inf)+ & |
|---|
| 563 | coeff*(field(ilon_inf,ilat_inf,ialt_inf,itim_sup)- & |
|---|
| 564 | field(ilon_inf,ilat_inf,ialt_inf,itim_inf)) |
|---|
| 565 | t_interp(1,1,2)=field(ilon_inf,ilat_inf,ialt_sup,itim_inf)+ & |
|---|
| 566 | coeff*(field(ilon_inf,ilat_inf,ialt_sup,itim_sup)- & |
|---|
| 567 | field(ilon_inf,ilat_inf,ialt_sup,itim_inf)) |
|---|
| 568 | t_interp(1,2,1)=field(ilon_inf,ilat_sup,ialt_inf,itim_inf)+ & |
|---|
| 569 | coeff*(field(ilon_inf,ilat_sup,ialt_inf,itim_sup)- & |
|---|
| 570 | field(ilon_inf,ilat_sup,ialt_inf,itim_inf)) |
|---|
| 571 | t_interp(1,2,2)=field(ilon_inf,ilat_sup,ialt_sup,itim_inf)+ & |
|---|
| 572 | coeff*(field(ilon_inf,ilat_sup,ialt_sup,itim_sup)- & |
|---|
| 573 | field(ilon_inf,ilat_sup,ialt_sup,itim_inf)) |
|---|
| 574 | t_interp(2,1,1)=field(ilon_sup,ilat_inf,ialt_inf,itim_inf)+ & |
|---|
| 575 | coeff*(field(ilon_sup,ilat_inf,ialt_inf,itim_sup)- & |
|---|
| 576 | field(ilon_sup,ilat_inf,ialt_inf,itim_inf)) |
|---|
| 577 | t_interp(2,1,2)=field(ilon_sup,ilat_inf,ialt_sup,itim_inf)+ & |
|---|
| 578 | coeff*(field(ilon_sup,ilat_inf,ialt_sup,itim_sup)- & |
|---|
| 579 | field(ilon_sup,ilat_inf,ialt_sup,itim_inf)) |
|---|
| 580 | t_interp(2,2,1)=field(ilon_sup,ilat_sup,ialt_inf,itim_inf)+ & |
|---|
| 581 | coeff*(field(ilon_sup,ilat_sup,ialt_inf,itim_sup)- & |
|---|
| 582 | field(ilon_sup,ilat_sup,ialt_inf,itim_inf)) |
|---|
| 583 | t_interp(2,2,2)=field(ilon_sup,ilat_sup,ialt_sup,itim_inf)+ & |
|---|
| 584 | coeff*(field(ilon_sup,ilat_sup,ialt_sup,itim_sup)- & |
|---|
| 585 | field(ilon_sup,ilat_sup,ialt_sup,itim_inf)) |
|---|
| 586 | |
|---|
| 587 | ! 2.2 Vertical interpolation |
|---|
| 588 | if (((varname=='rho').or.(varname=='pressure')).and.(alttype=='z')) then |
|---|
| 589 | ! do the interpolation on the log of the quantity |
|---|
| 590 | coeff=(alt-altitude(ialt_inf))/(altitude(ialt_sup)-altitude(ialt_inf)) |
|---|
| 591 | zt_interp(1,1)=log(t_interp(1,1,1))+coeff* & |
|---|
| 592 | (log(t_interp(1,1,2))-log(t_interp(1,1,1))) |
|---|
| 593 | zt_interp(1,2)=log(t_interp(1,2,1))+coeff* & |
|---|
| 594 | (log(t_interp(1,2,2))-log(t_interp(1,2,1))) |
|---|
| 595 | zt_interp(2,1)=log(t_interp(2,1,1))+coeff* & |
|---|
| 596 | (log(t_interp(2,1,2))-log(t_interp(2,1,1))) |
|---|
| 597 | zt_interp(2,2)=log(t_interp(2,2,1))+coeff* & |
|---|
| 598 | (log(t_interp(2,2,2))-log(t_interp(2,2,1))) |
|---|
| 599 | zt_interp(1:2,1:2)=exp(zt_interp(1:2,1:2)) |
|---|
| 600 | else ! general case |
|---|
| 601 | coeff=(alt-altitude(ialt_inf))/(altitude(ialt_sup)-altitude(ialt_inf)) |
|---|
| 602 | zt_interp(1,1)=t_interp(1,1,1)+coeff*(t_interp(1,1,2)-t_interp(1,1,1)) |
|---|
| 603 | zt_interp(1,2)=t_interp(1,2,1)+coeff*(t_interp(1,2,2)-t_interp(1,2,1)) |
|---|
| 604 | zt_interp(2,1)=t_interp(2,1,1)+coeff*(t_interp(2,1,2)-t_interp(2,1,1)) |
|---|
| 605 | zt_interp(2,2)=t_interp(2,2,1)+coeff*(t_interp(2,2,2)-t_interp(2,2,1)) |
|---|
| 606 | endif |
|---|
| 607 | |
|---|
| 608 | ! 2.3 Latitudinal interpolation |
|---|
| 609 | coeff=(lat-latitude(ilat_inf))/(latitude(ilat_sup)-latitude(ilat_inf)) |
|---|
| 610 | yzt_interp(1)=zt_interp(1,1)+coeff*(zt_interp(1,2)-zt_interp(1,1)) |
|---|
| 611 | yzt_interp(2)=zt_interp(2,1)+coeff*(zt_interp(2,2)-zt_interp(2,1)) |
|---|
| 612 | |
|---|
| 613 | ! 2.4 longitudinal interpolation |
|---|
| 614 | coeff=(lon-longitude(ilon_inf))/(longitude(ilon_sup)-longitude(ilon_inf)) |
|---|
| 615 | value=yzt_interp(1)+coeff*(yzt_interp(2)-yzt_interp(1)) |
|---|
| 616 | |
|---|
| 617 | end subroutine extraction |
|---|
| [312] | 618 | |
|---|
| [282] | 619 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|---|
| 620 | subroutine ls2sol(ls,sol) |
|---|
| 621 | |
|---|
| 622 | implicit none |
|---|
| 623 | ! Arguments: |
|---|
| 624 | real,intent(in) :: ls |
|---|
| 625 | real,intent(out) :: sol |
|---|
| 626 | |
|---|
| 627 | ! Local: |
|---|
| 628 | double precision xref,zx0,zteta,zz |
|---|
| 629 | !xref: mean anomaly, zteta: true anomaly, zx0: eccentric anomaly |
|---|
| 630 | double precision year_day |
|---|
| 631 | double precision peri_day,timeperi,e_elips |
|---|
| 632 | double precision pi,degrad |
|---|
| 633 | parameter (year_day=668.6d0) ! number of sols in a martian year |
|---|
| 634 | parameter (peri_day=485.35d0) ! date (in sols) of perihelion |
|---|
| 635 | ! timeperi: 2*pi*( 1 - Ls(perihelion)/ 360 ); Ls(perihelion)=250.99 |
|---|
| 636 | parameter (timeperi=1.90258341759902d0) |
|---|
| 637 | parameter (e_elips=0.0934d0) ! eccentricity of orbit |
|---|
| 638 | parameter (pi=3.14159265358979d0) |
|---|
| 639 | parameter (degrad=57.2957795130823d0) |
|---|
| 640 | |
|---|
| 641 | if (abs(ls).lt.1.0e-5) then |
|---|
| 642 | if (ls.ge.0.0) then |
|---|
| 643 | sol = 0.0 |
|---|
| 644 | else |
|---|
| 645 | sol = real(year_day) |
|---|
| 646 | end if |
|---|
| 647 | return |
|---|
| 648 | end if |
|---|
| 649 | |
|---|
| 650 | zteta = ls/degrad + timeperi |
|---|
| 651 | zx0 = 2.0*datan(dtan(0.5*zteta)/dsqrt((1.+e_elips)/(1.-e_elips))) |
|---|
| 652 | xref = zx0-e_elips*dsin(zx0) |
|---|
| 653 | zz = xref/(2.*pi) |
|---|
| 654 | sol = real(zz*year_day + peri_day) |
|---|
| 655 | if (sol.lt.0.0) sol = sol + real(year_day) |
|---|
| 656 | if (sol.ge.year_day) sol = sol - real(year_day) |
|---|
| 657 | |
|---|
| 658 | |
|---|
| 659 | end subroutine ls2sol |
|---|
| [312] | 660 | |
|---|