ncunderflow.f90 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. MODULE declare
  2. ! -*- Mode: f90 -*-
  3. !$Id: ncunderflow.f90 2281 2010-10-15 14:21:13Z smasson $
  4. !-
  5. ! This software is governed by the CeCILL license
  6. ! See IOIPSL/IOIPSL_License_CeCILL.txt
  7. !-
  8. ! f90 -L/usr/local/lib -lnetcdf -align dcommons -g
  9. ! -ladebug -check format -check bounds
  10. ! -check output_conversion -fpe1
  11. ! -I/usr/local/include -free -arch host -tune host
  12. ! -warn declarations -warn argument_checking
  13. ! ncunderflow.f -o ncunderflow
  14. !
  15. ! ifc -FR -cl,ncunderflow.pcl -o ncunderflow ncunderflow.f
  16. ! -L/usr/local/install/netcdf/lib/libnetcdf.a -lPEPCF90
  17. !
  18. IMPLICIT NONE
  19. INTEGER, PARAMETER :: r4 = 4, r8 = 8, i4 = 4, i8 = 8
  20. INTEGER, PARAMETER :: il = KIND(1)
  21. LOGICAL :: ldebug = .FALSE.
  22. INTEGER (kind = il) :: nout = 0, nerr = 0 ! Standard output, standard error
  23. CHARACTER (LEN=4), PARAMETER :: cerror = 'VOID'
  24. END MODULE declare
  25. !!
  26. MODULE mod_nfdiag
  27. CONTAINS
  28. SUBROUTINE nfdiag ( kios, clmess, lcd)
  29. !!
  30. !! Imprime un message d'erreur NetCDF
  31. !!
  32. USE declare
  33. IMPLICIT NONE
  34. INCLUDE 'netcdf.inc'
  35. !!
  36. INTEGER (kind=i4), INTENT (in) :: kios
  37. CHARACTER (len = *), INTENT (in) :: clmess
  38. LOGICAL, INTENT (in), OPTIONAL :: lcd
  39. CHARACTER (len = 80) :: clt
  40. LOGICAL :: ld
  41. !!
  42. IF ( PRESENT ( lcd)) THEN
  43. ld = lcd
  44. ELSE
  45. ld = ldebug
  46. ENDIF
  47. !!
  48. clt = TRIM ( NF_STRERROR ( kios) )
  49. !!
  50. IF ( ld ) THEN
  51. IF ( kios == NF_NOERR ) THEN
  52. WRITE ( unit = nout, fmt = * ) "OK : ", TRIM (clmess)
  53. ELSE
  54. WRITE ( unit = nout, fmt = * ) "ERROR : ", TRIM (clmess), " : ", TRIM ( clt), " : ", kios
  55. IF ( .NOT. ld ) STOP
  56. END IF
  57. ELSE
  58. IF ( kios /= NF_NOERR ) THEN
  59. WRITE ( unit = nout, fmt = * ) "ERROR : ", TRIM (clmess), " : ", TRIM ( clt), " : ", kios
  60. STOP
  61. END IF
  62. ENDIF
  63. !!
  64. RETURN
  65. !!
  66. END SUBROUTINE nfdiag
  67. !!
  68. END MODULE mod_nfdiag
  69. MODULE mod_lec
  70. CONTAINS
  71. !!
  72. SUBROUTINE lec (chaine, cval, c_c)
  73. !!
  74. USE declare
  75. IMPLICIT NONE
  76. !!
  77. CHARACTER (len = *), INTENT ( inout) :: chaine
  78. CHARACTER (len = *), INTENT ( inout) :: cval
  79. CHARACTER (len=*), OPTIONAL :: c_c
  80. INTEGER (kind = il) :: ji, ji1, ji2, ji3, jl, jb
  81. INTEGER (kind = i4) :: index
  82. !!
  83. !! Read character string up to ':' or ',', or in c_c if present
  84. !! Returns the real before the character (xerror if not available)
  85. !! Reduce the string
  86. !!
  87. jl = LEN (chaine) ; jb = LEN_TRIM (chaine)
  88. IF ( ldebug) WRITE ( nout, *) 'Lec : jl, jb ', jl, jb
  89. IF ( jb == 0 ) THEN
  90. cval = cerror
  91. ELSE
  92. ji1 = INDEX (chaine, ':') ; ji2 = INDEX (chaine, ',')
  93. IF ( PRESENT (c_c)) THEN
  94. ji3 = INDEX (chaine, c_c) ; ji = MAX (ji1, ji2, ji3)
  95. ELSE
  96. ji = MAX (ji1, ji2)
  97. ENDIF
  98. IF ( ji == 0 ) THEN
  99. READ ( chaine (1:jb) , fmt = * ) cval
  100. chaine (1:jl-jb) = chaine (jb+1:jl)
  101. ELSE IF ( ji == 1 ) THEN
  102. cval = cerror
  103. chaine (1:jl-1) = chaine (2:jl)
  104. ELSE
  105. cval = chaine (1:ji-1)
  106. chaine (1:jl-ji) = chaine (ji+1:jl )
  107. END IF
  108. END IF
  109. !!
  110. END SUBROUTINE lec
  111. END MODULE mod_lec
  112. PROGRAM ncunderflow
  113. ! Ce programme ouvre un fichier de donnees au format netcdf
  114. ! et met a zero toutes les valeurs trop petites pour etre
  115. ! representees par un reel sur 4 octets au format IEEE
  116. !
  117. ! Revision 2.0 2004/04/05 14:47:50 adm
  118. ! JB+MAF+AC: switch to IOIPSL 2.0 (1)
  119. !
  120. ! Revision 1.1 2003/04/09 15:21:56 adm
  121. ! add ncunderflow in IOIPSL
  122. ! and modify AA_make to take it into account
  123. ! SD + MAF
  124. !
  125. ! Revision 1.1 2001/02/07 14:36:07 jypeter
  126. ! J-Y Peterschmitt / LMCE / 07/02/2001
  127. ! Initial revision
  128. !
  129. USE declare
  130. USE mod_nfdiag
  131. USE mod_lec
  132. IMPLICIT NONE
  133. INCLUDE 'netcdf.inc'
  134. INTEGER (kind=il), EXTERNAL :: iargc
  135. ! Nombre maximal de dimensions : 6
  136. INTEGER (kind=il), PARAMETER :: jpmaxdim = 6, jpmaxvar = 1024
  137. CHARACTER (len = 128) :: clnomprog, clnomfic
  138. CHARACTER (len = 1024) :: clistvar, clecline
  139. CHARACTER (len = 128), DIMENSION(jpmaxdim) :: clnomdim
  140. CHARACTER (len = 128), DIMENSION(jpmaxvar) :: clvarcmd, clvarfic, clvar ! Nom des variables dans le fichier est sur la ligne de commande.
  141. LOGICAL :: lrever = .FALSE. ! Si .true., on traite toutes les variables sauf celle de la ligne de commande
  142. LOGICAL :: lnocoord = .FALSE. ! Si .truee., on exclu les variables coordonnées
  143. LOGICAL :: lverbose = .TRUE.
  144. INTEGER (kind=il) :: incid, ircode, ivarid, ivartype, inbdim, inbatt
  145. INTEGER (kind=il) :: nvarcmd, nvarfic, nvar, nfile, jvarcmd, jvarfic, jvar, jfile, ierr
  146. INTEGER (kind=il) :: ji, jdim3, jdim4, jdim5, jdim6, j1, j2, j3, jarg, ncumul
  147. INTEGER (kind=il), DIMENSION(jpmaxdim) :: idimid, idimsize, istart, icount
  148. REAL (kind=r4), DIMENSION(:,:), ALLOCATABLE :: zdatacorr
  149. REAL (kind=r8), DIMENSION(:,:), ALLOCATABLE :: zdata
  150. REAL (kind=r4) :: reps = TINY (1.0_r4) * 10.0_r4
  151. LOGICAL :: lok
  152. ! Verification du nombre de parametres
  153. IF(iargc() .LT. 2) THEN
  154. CALL usage
  155. STOP
  156. ENDIF
  157. ! Aide
  158. jarg = 1
  159. Lab1: DO WHILE ( jarg <= 3 )
  160. IF (ldebug) WRITE(nout,*) 'lecture ligne commande ', jarg
  161. CALL getarg (jarg,clecline)
  162. IF ( clecline(1:1) /= '-' ) EXIT Lab1
  163. IF ( clecline(1:2) == '-h' .OR. clecline(1:2) == '-?' ) THEN
  164. CALL usage
  165. STOP
  166. ELSE IF ( clecline(1:2) == '-x' ) THEN
  167. lrever = .TRUE.
  168. ELSE IF ( clecline(1:2) == '-d' ) THEN
  169. ldebug = .TRUE.
  170. ELSE IF ( clecline(1:2) == '-V' ) THEN
  171. lverbose = .FALSE.
  172. ELSE IF ( clecline(1:2) == '-v' ) THEN
  173. jarg = jarg + 1
  174. ! Recuperation des noms de variables
  175. IF (ldebug) WRITE(nout,*) 'lecture liste vriables ', jarg
  176. CALL getarg (jarg,clistvar)
  177. clistvar = TRIM(ADJUSTL(clistvar))
  178. jvarcmd = 0 ; nvarcmd = 0
  179. SeekVar: DO WHILE ( .TRUE. )
  180. CALL lec ( clistvar, clvarcmd(jvarcmd+1)(:) )
  181. IF ( TRIM(clvarcmd(jvarcmd+1)(:)) == cerror ) EXIT SeekVar
  182. jvarcmd = jvarcmd + 1
  183. nvarcmd = jvarcmd
  184. IF (ldebug) WRITE(nout,*) 'affecte variable ', jvarcmd, TRIM(clvarcmd(jvarcmd))
  185. END DO SeekVar
  186. ENDIF
  187. jarg = jarg + 1
  188. END DO Lab1
  189. ! Boucle sur les fichiers
  190. FileLoop: DO jfile = jarg, iargc()
  191. ! Recuperation du nom du fichier a traiter
  192. CALL getarg ( jfile, clnomfic)
  193. ! Ouverture du fichier
  194. CALL nfdiag ( NF_OPEN ( TRIM(clnomfic), NF_WRITE, incid ), "Opening " // TRIM(clnomfic) )
  195. WRITE (nout,*) TRIM(clnomfic)
  196. ! Recuparation de la liste des variables du fichier
  197. nvarfic = 0
  198. DO jvarfic = 1, jpmaxvar
  199. j3 = NF_INQ_VAR ( incid, jvarfic, clvarfic(jvarfic)(:), ivartype, inbdim, idimid, inbatt)
  200. IF ( j3 /= NF_NOERR ) EXIT
  201. nvarfic = jvarfic
  202. END DO
  203. ! Liste des variables a traiter
  204. IF ( lrever ) THEN
  205. IF ( nvarcmd == 0) THEN
  206. clvar = clvarfic
  207. nvar = nvarfic
  208. ELSE
  209. jvar = 0
  210. DO jvarfic = 1, nvarfic
  211. lok = .TRUE.
  212. DO jvarcmd = 1, nvarcmd
  213. IF ( TRIM(clvarfic(jvarfic)(:)) == TRIM(clvarcmd(jvarcmd)(:)) ) THEN
  214. lok = .FALSE.
  215. END IF
  216. END DO
  217. IF ( lok) THEN
  218. jvar = jvar + 1
  219. clvar(jvar) = clvarfic(jvarfic)
  220. END IF
  221. END DO
  222. nvar = jvar
  223. END IF
  224. ELSE
  225. clvar = clvarcmd
  226. nvar = nvarcmd
  227. END IF
  228. ncumul = 0
  229. VarLoop: DO jvar = 1, nvar
  230. IF (lverbose) &
  231. & WRITE(nout, FMT='("Correction de ", A, " dans ", A, " : ", $)') TRIM(clvar(jvar)(:)), TRIM(clnomfic)
  232. ! Passage de netcdf en mode 'erreurs non fatales'
  233. ! CALL ncpopt(NCVERBOS)
  234. ! En fait, on reste dans le mode par defaut, dans lequel une erreur
  235. ! netcdf cause un arret du programme. Du coup, il n'est pas
  236. ! necessaire de tester la valeur de la variable ircode
  237. ! ATTENTION! Si jamais on veut arreter le programme a cause d'une
  238. ! erreur ne provenant pas de netcdf, il faut penser a fermer
  239. ! manuellement le fichier avec un appel a ncclos
  240. ! Recuperation de l'identificateur de la variable
  241. CALL nfdiag ( NF_INQ_VARID ( incid, TRIM(clvar(jvar)(:)), ivarid), "Get var id " // TRIM(clvar(jvar)(:)))
  242. ivartype = 0 ; idimid = 0 ; inbdim = 0 ; inbatt = 0
  243. ! Recuperation du nombre de dimensions de la variable
  244. CALL nfdiag ( NF_INQ_VAR ( incid, ivarid, clvar(jvar)(:), ivartype, inbdim, idimid, inbatt), &
  245. & "Get var info " // TRIM(clvar(jvar)(:)))
  246. IF(inbdim .GT. jpmaxdim) THEN
  247. WRITE(nout,*)
  248. WRITE(nout, *) 'La variable ', TRIM(clvar(jvar)(:)), ' a trop de dimensions'
  249. CALL nfdiag ( NF_CLOSE (incid), "Closing file")
  250. STOP
  251. ENDIF
  252. ! Recuperation des dimensions effectives
  253. idimsize(3:jpmaxdim) = 1 ! Au cas ou la variable n'ait que
  254. ! 2 ou 3 dims, on initialise ces valeurs
  255. ! qui serviront dans le controle des boucles
  256. ! et qui auraient une valeur indefinie sinon
  257. DO ji = 1, inbdim
  258. CALL nfdiag ( NF_INQ_DIM ( incid, idimid(ji), clnomdim(ji), idimsize(ji)), "NF_INQ_DIM")
  259. IF (lverbose) WRITE(nout, '(A,A,A,I3,$)') ' ', TRIM(clnomdim(ji)), ' = ', idimsize(ji)
  260. IF ( idimsize(ji) == 0 ) THEN
  261. WRITE(nout, '(A,A,A,A,I3)') TRIM(clvar(jvar)(:)), ', ', TRIM(clnomdim(ji)), ' = ', idimsize(ji)
  262. CYCLE VarLoop
  263. END IF
  264. ENDDO
  265. IF (lverbose) WRITE(nout,*)
  266. idimsize = MAX ( idimsize, 1)
  267. ncumul = ncumul + 1
  268. ! Determination du type de la variable, en fonction du nom de
  269. ! la premiere dimension
  270. !$$$ IF(INDEX(TRIM(clnomdim(1)),'ongitude') .NE. 0) THEN
  271. !$$$ ! var de type map ou 3d
  272. !$$$ write(nout, *) ' --> MAP/3D'
  273. !$$$ ELSE IF(INDEX(TRIM(clnomdim(1)),'atitude') .NE. 0) THEN
  274. !$$$ ! var de type xsec
  275. !$$$ write(nout, *) ' --> XSEC'
  276. !$$$ ELSE
  277. !$$$ WRITE(nout, *)
  278. !$$$ WRITE(nout, *) 'Bizarre, la premiere dimension n''est ni "longitude" ni "latitude"'
  279. !$$$ CALL ncclos(incid, ircode)
  280. !$$$ STOP
  281. !$$$ ENDIF
  282. ! Reservation de memoire pour charger et traiter
  283. ! une grille idimsize(1)*idimsize(2) de la variable
  284. ALLOCATE(zdata(idimsize(1), idimsize(2)), stat=ierr)
  285. IF(ierr .NE. 0) THEN
  286. WRITE(nout, *) 'Erreur d''allocation memoire pour zdata'
  287. CALL nfdiag ( NF_CLOSE (incid), "NF_CLOSE")
  288. STOP
  289. ENDIF
  290. ALLOCATE(zdatacorr(idimsize(1), idimsize(2)), stat=ierr)
  291. IF(ierr .NE. 0) THEN
  292. WRITE(nout, *) 'Erreur d''allocation memoire pour zdatacorr'
  293. CALL nfdiag ( NF_CLOSE (incid), "NF_CLOSE")
  294. STOP
  295. ENDIF
  296. ! Parametrisation de la partie de la variable a charger en memoire
  297. ! (une 'grille' que l'on lira autant de fois qu'il y a de niveaux et
  298. ! de pas de temps)
  299. ! Rappel : seuls les elements 1..inbdim des tableaux sont
  300. ! significatifs et utiles
  301. icount = 0
  302. DO jdim6 = 1, idimsize(6)
  303. DO jdim5 = 1, idimsize(5)
  304. DO jdim4 = 1, idimsize(4)
  305. DO jdim3 = 1, idimsize(3)
  306. istart = (/ 1 , 1 , jdim3, jdim4, jdim5, jdim6 /)
  307. icount = (/ idimsize(1), idimsize(2), 1 , 1 , 1 , 1 /)
  308. ! Chargement d'une 'grille' de donnees, en real*8
  309. CALL nfdiag ( NF_GET_VARA_DOUBLE(incid, ivarid, istart(1:inbdim), icount(1:inbdim), zdata), &
  310. & "NF_GET_VARA_DOUBLE")
  311. ! Mise a zero de toutes les valeurs trop petites pour etre
  312. ! representees par un reel sur 4 octets au format IEEE.
  313. ! Le truc est de faire une operation nulle (addition de 0)
  314. ! sur des donnees qui posent problemes, EN AYANT COMPILE LE PROG
  315. ! AVEC l'OPTION "-fpe1". Dans ce cas, les valeurs trop petites
  316. ! sont remplacees par zero (0.0) et le programme continue,
  317. ! au lieu de planter.
  318. ! Il est possible de faire afficher le nb de valeurs qui ont pose
  319. ! un pb en utilisant en plus l'option "-check underflow"
  320. zdata = zdata + 0.0_r8
  321. zdatacorr = REAL(zdata, KIND=r4)
  322. WHERE ( ABS (zdatacorr) < reps) zdatacorr = 0.0_r4
  323. ! Sauvegarde de la grille corrigee dans le fichier
  324. ! (a la place de la grille initiale), en real*4
  325. CALL nfdiag ( NF_PUT_VARA_REAL(incid, ivarid, istart, icount, zdatacorr), "NF_PUT_VARA_REAL" )
  326. END DO
  327. END DO
  328. END DO
  329. END DO
  330. DEALLOCATE ( zdata)
  331. DEALLOCATE ( zdatacorr)
  332. END DO VarLoop
  333. WRITE (nout,*) 'ncunderflow, nombre de variables corrigees : ', ncumul
  334. ! Fermeture du fichier
  335. CALL nfdiag ( NF_CLOSE (incid), "Closing" )
  336. END DO FileLoop
  337. CONTAINS
  338. SUBROUTINE usage
  339. IMPLICIT NONE
  340. CALL getarg (0, clnomprog)
  341. WRITE(nout, FMT='("Command : ", A)') TRIM(clnomprog)
  342. WRITE(nout, FMT='("Removes underflows in NetCDF files") ')
  343. WRITE(nout, FMT='("Usage : ", A, " [-x] [-V] [-d] -v nomvar[,nomvar] nomfic [nomfic]")' ) TRIM(clnomprog)
  344. WRITE(nout, FMT='("Options : ")' )
  345. WRITE(nout, FMT='(" -V : mode verbose off. Default is verbose on.")' )
  346. WRITE(nout, FMT='(" -d : debug mode on. Default is debug off.")' )
  347. WRITE(nout, FMT='(" -v : gives list of variables to be corrected, separated by a coma.")' )
  348. WRITE(nout, FMT='(" -x : reverses meaning of -v : given variable are not corrected")' )
  349. WRITE(nout, FMT='(" if -x is given, and not -v, all variables are corrected.")' )
  350. STOP
  351. END SUBROUTINE usage
  352. END PROGRAM ncunderflow