source: trunk/LMDZ.COMMON/libf/evolution/writediagpem.F90 @ 3321

Last change on this file since 3321 was 3214, checked in by jbclement, 10 months ago

PEM:

  • It is now possible to set the number of initial PCM calls independently of the number of "inter-PEM" PCM calls. It is useful to get a stable situation for the start of the simulation.
  • Correction of a bug: 'reshape_XIOS_output' treated the first two PCM runs instead of the last two. The numbering has been adapted in "launch_pem.sh" to get it right.
  • PEM outputs ("diagpem.nc" and "diagsoil_pem.nc") has been improved: 'Time' now evolves according to 'dt_pem' (usually year by year) and 'ecritpem' is a full variable of "time_evol_mod.F90".

JBC

File size: 34.3 KB
Line 
1MODULE writediagpem_mod
2
3implicit none
4
5!=======================================================================
6contains
7!=======================================================================
8
9SUBROUTINE writediagpem(ngrid,nom,titre,unite,dim,px)
10
11!  Ecriture de variables diagnostiques au choix dans la physique
12!  dans un fichier NetCDF nomme  'diagpem'. Ces variables peuvent etre
13!  3d (ex : temperature), 2d (ex : temperature de surface), ou
14!  0d (pour un scalaire qui ne depend que du temps : ex : la longitude
15!  solaire)
16!  (ou encore 1d, dans le cas de testphys1d, pour sortir une colonne)
17!  La periode d'ecriture est donnee par
18!  "ecritpem " regle dans le fichier de controle de run :  run.def
19!
20!    writediagpem peut etre appele de n'importe quelle subroutine
21!    de la physique, plusieurs fois. L'initialisation et la creation du
22!    fichier se fait au tout premier appel.
23!
24! WARNING : les variables dynamique (u,v,t,q,ps)
25!  sauvees par writediagpem avec une
26! date donnee sont legerement differentes que dans le fichier histoire car
27! on ne leur a pas encore ajoute de la dissipation et de la physique !!!
28! IL est  RECOMMANDE d'ajouter les tendance physique a ces variables
29! avant l'ecriture dans diagpem (cf. physiq.F)
30!
31! Modifs: Aug.2010 Ehouarn: enforce outputs to be real*4
32!         Oct 2011 Francois: enable having a 'diagpem.def' file to select
33!                            at runtime, which variables to put in file
34!         Oct 2023 JBC: conversion into Fortran 90 with module for the PEM
35!
36!  parametres (input) :
37!  ----------
38!      ngrid : nombres de point ou est calcule la physique
39!                (ngrid = 2+(jjm-1)*iim - 1/jjm)
40!                (= nlon ou klon dans la physique terrestre)
41!      unit : unite logique du fichier de sortie (toujours la meme)
42!      nom  : nom de la variable a sortir (chaine de caracteres)
43!      titre: titre de la variable (chaine de caracteres)
44!      unite : unite de la variable (chaine de caracteres)
45!      px : variable a sortir (real 0, 1, 2, ou 3d)
46!      dim : dimension de px : 0, 1, 2, ou 3 dimensions
47!
48!=================================================================
49use surfdat_h,          only: phisfi
50use geometry_mod,       only: cell_area
51use mod_phys_lmdz_para, only: is_parallel, is_mpi_root, is_master, gather
52use mod_grid_phy_lmdz,  only: klon_glo, Grid1Dto2D_glo, nbp_lon, nbp_lat, nbp_lev, grid_type, unstructured
53use time_evol_mod,      only: ecritpem, dt_pem
54
55implicit none
56
57! Commons
58include "netcdf.inc"
59
60! Arguments on input:
61integer,                        intent(in) :: ngrid
62character(len=*),               intent(in) :: nom, titre, unite
63integer,                        intent(in) :: dim
64real, dimension(ngrid,nbp_lev), intent(in) :: px
65
66! Local variables:
67real*4, dimension(nbp_lon + 1,nbp_lat,nbp_lev) :: dx3    ! to store a 3D data set
68real*4, dimension(nbp_lon + 1,nbp_lat)         :: dx2    ! to store a 2D (surface) data set
69real*4, dimension(nbp_lev)                     :: dx1    ! to store a 1D (column) data set
70real*4                                         :: dx0
71real*4, dimension(1,nbp_lev)                   :: dx3_1d ! to store a profile with 1D model
72real*4                                         :: dx2_1d ! to store a surface value with 1D model
73real*4, save                                   :: date
74
75!$OMP THREADPRIVATE(date)
76real, dimension((nbp_lon + 1),nbp_lat) :: phis
77real, dimension((nbp_lon + 1),nbp_lat) :: area
78integer                                :: irythme, ierr, ierr2, i, j, l, ig0
79integer,                          save :: zitau = 0
80character(27),                    save :: firstnom='1234567890'
81!$OMP THREADPRIVATE(zitau,firstnom)
82
83! Ajouts
84integer,           save :: ntime = 0
85!$OMP THREADPRIVATE(ntime)
86integer                 :: idim, varid
87integer                 :: nid
88character(*), parameter :: fichnom = "diagpem.nc"
89integer, dimension(4)   :: id
90integer, dimension(4)   :: edges, corner
91
92! Added to use diagpem.def to select output variable
93logical,                                  save :: diagpem_def
94logical                                        :: getout
95integer,                                  save :: n_nom_def
96integer                                        :: n
97integer, parameter                             :: n_nom_def_max = 199
98character(120), dimension(n_nom_def_max), save :: nom_def
99logical,                                  save :: firstcall = .true.
100!$OMP THREADPRIVATE(firstcall) !diagpem_def,n_nom_def,nom_def read in diagpem.def
101
102#ifdef CPP_PARA
103! Added to work in parallel mode
104    real, dimension(klon_glo,nbp_lev)        :: dx3_glop
105    real, dimension(nbp_lon,nbp_lat,nbp_lev) :: dx3_glo  ! to store a global 3D data set
106    real, dimension(klon_glo)                :: dx2_glop
107    real, dimension(nbp_lon,nbp_lat)         :: dx2_glo  ! to store a global 2D (surface) data set
108    real, dimension(ngrid)                   :: px2
109!    real, dimension(nbp_lev)                :: dx1_glo   ! to store a 1D (column) data set
110!    real :: dx0_glo
111    real, dimension(klon_glo) :: phisfi_glo ! surface geopotential on global physics grid
112    real, dimension(klon_glo) :: areafi_glo ! mesh area on global physics grid
113#else
114    real, dimension(ngrid) :: phisfi_glo ! surface geopotential on global physics grid
115    real, dimension(ngrid) :: areafi_glo ! mesh area on global physics grid
116#endif
117
118if (grid_type == unstructured) return
119
120!***************************************************************
121!Sortie des variables au rythme voulu
122irythme = int(ecritpem) ! output rate set by ecritpem
123
124!***************************************************************
125! At very first call, check if there is a "diagpem.def" to use and read it
126! ------------------------------------------------------------------------
127IF (firstcall) THEN
128    firstcall=.false.
129
130!$OMP MASTER
131    ! Open diagpem.def definition file if there is one:
132        open(99,file="diagpem.def",status='old',form='formatted',iostat=ierr2)
133
134        if (ierr2 == 0) then
135            diagpem_def=.true.
136            write(*,*) "*******************"
137            write(*,*) "Reading diagpem.def"
138            write(*,*) "*******************"
139            do n=1,n_nom_def_max
140                read(99,fmt='(a)',end=88) nom_def(n)
141                write(*,*) 'Output in diagpem: ', trim(nom_def(n))
142            enddo
143 88         continue
144            if (n.ge.n_nom_def_max) then
145                write(*,*)"n_nom_def_max too small in writediagpem.F:",n
146                call abort_physic("writediagpem","n_nom_def_max too small",1)
147            end if
148            n_nom_def=n-1
149            close(99)
150        else
151            diagpem_def=.false.
152        endif
153!$OMP END MASTER
154!$OMP BARRIER
155ENDIF ! of IF (firstcall)
156
157! Get out of write_diagpem if there is diagpem.def AND variable not listed
158!  -----------------------------------------------------------------------
159if (diagpem_def) then
160    getout=.true.
161    do n=1,n_nom_def
162        if (trim(nom_def(n)).eq.nom) getout=.false.
163    enddo
164    if (getout) return
165endif
166
167! Initialisation of 'firstnom' and create/open the "diagpem.nc" NetCDF file
168! -------------------------------------------------------------------------
169! (at very first call to the subroutine, in accordance with diagpem.def)
170if (firstnom.eq.'1234567890') then ! .true. for the very first valid
171    ! call to this subroutine; now set 'firstnom'
172    firstnom = nom
173    ! just to be sure, check that firstnom is large enough to hold nom
174    if (len_trim(firstnom).lt.len_trim(nom)) then
175        write(*,*) "writediagpem: Error !!!"
176        write(*,*) "   firstnom string not long enough!!"
177        write(*,*) "   increase its size to at least ",len_trim(nom)
178        call abort_physic("writediagpem","firstnom too short",1)
179    endif
180
181    zitau = -1 ! initialize zitau
182
183#ifdef CPP_PARA
184        ! Gather phisfi() geopotential on physics grid
185        call Gather(phisfi,phisfi_glo)
186        ! Gather cell_area() mesh area on physics grid
187        call Gather(cell_area,areafi_glo)
188#else
189        phisfi_glo(:)=phisfi(:)
190        areafi_glo(:)=cell_area(:)
191#endif
192
193    !! parallel: we cannot use the usual writediagpem method
194    !! call iophys_ini
195    if (is_master) then
196        ! only the master is required to do this
197        ! Create the NetCDF file
198        ierr = NF_CREATE(fichnom,NF_CLOBBER,nid)
199        ! Define the 'Time' dimension
200        ierr = nf_def_dim(nid,"Time",NF_UNLIMITED,idim)
201        ! Define the 'Time' variable
202    !#ifdef NC_DOUBLE
203    !    ierr = NF_DEF_VAR (nid, "Time", NF_DOUBLE, 1, idim,varid)
204    !#else
205        ierr = NF_DEF_VAR (nid, "Time", NF_FLOAT, 1, idim,varid)
206    !#endif
207        ! Add a long_name attribute
208        ierr = NF_PUT_ATT_TEXT (nid, varid, "long_name",4,"Time")
209        ! Add a units attribute
210        ierr = NF_PUT_ATT_TEXT(nid, varid,'units',29,"days since 0000-00-0 00:00:00")
211        ! Switch out of NetCDF Define mode
212        ierr = NF_ENDDEF(nid)
213
214        ! Build phis() and area()
215        IF (klon_glo>1) THEN
216            do i=1,nbp_lon+1 ! poles
217            phis(i,1)=phisfi_glo(1)
218            phis(i,nbp_lat)=phisfi_glo(klon_glo)
219            ! for area, divide at the poles by nbp_lon
220            area(i,1)=areafi_glo(1)/nbp_lon
221            area(i,nbp_lat)=areafi_glo(klon_glo)/nbp_lon
222            enddo
223            do j=2,nbp_lat-1
224            ig0= 1+(j-2)*nbp_lon
225            do i=1,nbp_lon
226                phis(i,j)=phisfi_glo(ig0+i)
227                area(i,j)=areafi_glo(ig0+i)
228            enddo
229            ! handle redundant point in longitude
230            phis(nbp_lon+1,j)=phis(1,j)
231            area(nbp_lon+1,j)=area(1,j)
232            enddo
233        ENDIF
234
235        ! write "header" of file (longitudes, latitudes, geopotential, ...)
236        IF (klon_glo>1) THEN ! general 3D case
237            call iniwrite(nid,0,phis,area,nbp_lon+1,nbp_lat)
238        ELSE ! 1D model
239            call iniwrite(nid,0,phisfi_glo(1),areafi_glo(1),1,1)
240        ENDIF
241
242    endif ! of if (is_master)
243
244    else
245
246    if (is_master) then
247        ! only the master is required to do this
248        ! Open the NetCDF file
249        ierr = NF_OPEN(fichnom,NF_WRITE,nid)
250    endif ! of if (is_master)
251
252endif ! if (firstnom.eq.'1234567890')
253
254! Increment time index 'zitau' if it is the "fist call" (at given time level)
255! to writediagpem
256!------------------------------------------------------------------------
257if (nom == firstnom) zitau = zitau + dt_pem
258
259!--------------------------------------------------------
260! Write the variables to output file if it's time to do so
261!--------------------------------------------------------
262if (MOD(zitau+1,irythme) == 0.) then
263! Compute/write/extend 'Time' coordinate (date given in days)
264! (done every "first call" (at given time level) to writediagpem)
265! Note: date is incremented as 1 step ahead of physics time
266!--------------------------------------------------------
267    if (is_master) then
268        ! only the master is required to do this
269        if (nom.eq.firstnom) then
270        ! We have identified a "first call" (at given date)
271            ntime=ntime+1 ! increment # of stored time steps
272            ! compute corresponding date (in days and fractions thereof)
273            date = float(zitau + 1)
274            ! Get NetCDF ID of 'Time' variable
275            ierr= NF_INQ_VARID(nid,"Time",varid)
276            ! Write (append) the new date to the 'Time' array
277!#ifdef NC_DOUBLE
278!    ierr= NF_PUT_VARA_DOUBLE(nid,varid,[ntime],[1],[date])
279!#else
280            ierr= NF_PUT_VARA_REAL(nid,varid,[ntime],[1],[date])
281!#endif
282            if (ierr.ne.NF_NOERR) then
283                write(*,*) "***** PUT_VAR matter in writediagpem_nc"
284                write(*,*) "***** with time"
285                write(*,*) 'ierr=', ierr,": ",NF_STRERROR(ierr)
286!                call abort
287            endif
288
289            write(6,*)'WRITEDIAGPEM: date= ', date
290        endif ! of if (nom.eq.firstnom)
291    endif ! of if (is_master)
292
293!Case of a 3D variable
294!---------------------
295    if (dim == 3) then
296#ifdef CPP_PARA
297        ! Gather field on a "global" (without redundant longitude) array
298        call Gather(px,dx3_glop)
299!$OMP MASTER
300        if (is_mpi_root) then
301            call Grid1Dto2D_glo(dx3_glop,dx3_glo)
302            ! copy dx3_glo() to dx3(:) and add redundant longitude
303            dx3(1:nbp_lon,:,:)=dx3_glo(1:nbp_lon,:,:)
304            dx3(nbp_lon+1,:,:)=dx3(1,:,:)
305        endif
306!$OMP END MASTER
307!$OMP BARRIER
308#else
309!         Passage variable physique -->  variable dynamique
310!         recast (copy) variable from physics grid to dynamics grid
311        IF (klon_glo>1) THEN ! General case
312            DO l=1,nbp_lev
313                DO i=1,nbp_lon+1
314                    dx3(i,1,l)=px(1,l)
315                    dx3(i,nbp_lat,l)=px(ngrid,l)
316                ENDDO
317                DO j=2,nbp_lat-1
318                    ig0= 1+(j-2)*nbp_lon
319                    DO i=1,nbp_lon
320                        dx3(i,j,l)=px(ig0+i,l)
321                    ENDDO
322                    dx3(nbp_lon+1,j,l)=dx3(1,j,l)
323                ENDDO
324            ENDDO
325        ELSE ! 1D model case
326            dx3_1d(1,1:nbp_lev)=px(1,1:nbp_lev)
327        ENDIF
328#endif
329!       Ecriture du champs
330        if (is_master) then
331! only the master writes to output
332! name of the variable
333            ierr= NF_INQ_VARID(nid,nom,varid)
334            if (ierr /= NF_NOERR) then
335! corresponding dimensions
336                ierr = NF_INQ_DIMID(nid,"longitude",id(1))
337                ierr = NF_INQ_DIMID(nid,"latitude",id(2))
338                ierr = NF_INQ_DIMID(nid,"altitude",id(3))
339                ierr = NF_INQ_DIMID(nid,"Time",id(4))
340
341! Create the variable if it doesn't exist yet
342                write (*,*) "==========================="
343                write (*,*) "DIAGPEM: creating variable ",trim(nom)
344                call def_var(nid,nom,titre,unite,4,id,varid,ierr)
345
346            else
347                if (ntime==0) then
348                    write(*,*) "DIAGPEM Error: failed creating variable ",trim(nom)
349                    write(*,*) "it seems it already exists!"
350                    call abort_physic("writediagpem",trim(nom)//" already exists",1)
351                endif
352            endif
353
354            corner(1)=1
355            corner(2)=1
356            corner(3)=1
357            corner(4)=ntime
358
359            IF (klon_glo==1) THEN
360                edges(1)=1
361            ELSE
362                edges(1)=nbp_lon+1
363            ENDIF
364            edges(2)=nbp_lat
365            edges(3)=nbp_lev
366            edges(4)=1
367!#ifdef NC_DOUBLE
368!            ierr= NF_PUT_VARA_DOUBLE(nid,varid,corner,edges,dx3)
369!#else
370!            write(*,*)"test:  nid=",nid," varid=",varid
371!            write(*,*)"       corner()=",corner
372!            write(*,*)"       edges()=",edges
373!            write(*,*)"       dx3()=",dx3
374            IF (klon_glo>1) THEN ! General case
375                ierr= NF_PUT_VARA_REAL(nid,varid,corner,edges,dx3)
376            ELSE
377                ierr= NF_PUT_VARA_REAL(nid,varid,corner,edges,dx3_1d)
378            ENDIF
379!#endif
380
381            if (ierr.ne.NF_NOERR) then
382                write(*,*) "***** PUT_VAR problem in writediagpem"
383                write(*,*) "***** with dx3: ",trim(nom)
384                write(*,*) 'ierr=', ierr,": ",NF_STRERROR(ierr)
385                call abort_physic("writediagpem","failed writing "//trim(nom),1)
386            endif
387
388        endif !of if (is_master)
389
390!Case of a 2D variable
391!---------------------
392    else if (dim == 2) then
393
394#ifdef CPP_PARA
395        ! Gather field on a "global" (without redundant longitude) array
396        px2(:)=px(:,1)
397        call Gather(px2,dx2_glop)
398!$OMP MASTER
399        if (is_mpi_root) then
400            call Grid1Dto2D_glo(dx2_glop,dx2_glo)
401            ! copy dx2_glo() to dx2(:) and add redundant longitude
402            dx2(1:nbp_lon,:)=dx2_glo(1:nbp_lon,:)
403            dx2(nbp_lon+1,:)=dx2(1,:)
404        endif
405!$OMP END MASTER
406!$OMP BARRIER
407#else
408!         Passage variable physique -->  physique dynamique
409!         recast (copy) variable from physics grid to dynamics grid
410        IF (klon_glo>1) THEN ! General case
411            DO i=1,nbp_lon+1
412                dx2(i,1)=px(1,1)
413                dx2(i,nbp_lat)=px(ngrid,1)
414            ENDDO
415            DO j=2,nbp_lat-1
416                ig0= 1+(j-2)*nbp_lon
417                DO i=1,nbp_lon
418                    dx2(i,j)=px(ig0+i,1)
419                ENDDO
420                dx2(nbp_lon+1,j)=dx2(1,j)
421            ENDDO
422        ELSE ! 1D model case
423            dx2_1d=px(1,1)
424        ENDIF
425#endif
426
427        if (is_master) then
428        ! only the master writes to output
429!            write (*,*) 'In  writediagpem, on sauve:  ' , nom
430!            write (*,*) 'In  writediagpem. Estimated date = ' ,date
431            ierr= NF_INQ_VARID(nid,nom,varid)
432            if (ierr /= NF_NOERR) then
433! corresponding dimensions
434                ierr= NF_INQ_DIMID(nid,"longitude",id(1))
435                ierr= NF_INQ_DIMID(nid,"latitude",id(2))
436                ierr= NF_INQ_DIMID(nid,"Time",id(3))
437
438! Create the variable if it doesn't exist yet
439                write (*,*) "==========================="
440                write (*,*) "DIAGPEM: creating variable ",trim(nom)
441
442                call def_var(nid,nom,titre,unite,3,id,varid,ierr)
443
444            else
445                if (ntime==0) then
446                    write(*,*) "DIAGPEM Error: failed creating variable ",trim(nom)
447                    write(*,*) "it seems it already exists!"
448                    call abort_physic("writediagpem",trim(nom)//" already exists",1)
449                endif
450            endif
451
452            corner(1)=1
453            corner(2)=1
454            corner(3)=ntime
455            IF (klon_glo==1) THEN
456                edges(1)=1
457            ELSE
458                edges(1)=nbp_lon+1
459            ENDIF
460            edges(2)=nbp_lat
461            edges(3)=1
462
463
464!#ifdef NC_DOUBLE
465!           ierr = NF_PUT_VARA_DOUBLE (nid,varid,corner,edges,dx2)
466!#else
467            IF (klon_glo>1) THEN ! General case
468                ierr = NF_PUT_VARA_REAL(nid,varid,corner,edges,dx2)
469            ELSE
470                ierr = NF_PUT_VARA_REAL(nid,varid,corner,edges,[dx2_1d])
471            ENDIF
472!#endif
473
474            if (ierr.ne.NF_NOERR) then
475                write(*,*) "***** PUT_VAR matter in writediagpem"
476                write(*,*) "***** with dx2: ",trim(nom)
477                write(*,*) 'ierr=', ierr,": ",NF_STRERROR(ierr)
478                call abort_physic("writediagpem","failed writing "//trim(nom),1)
479            endif
480
481        endif !of if (is_master)
482
483!Case of a 1D variable (ie: a column)
484!---------------------------------------------------
485    else if (dim.eq.1) then
486        if (is_parallel) then
487            write(*,*) "writediagpem error: dim=1 not implemented ","in parallel mode. Problem for ",trim(nom)
488                call abort_physic("writediagpem","failed writing "//trim(nom),1)
489        endif
490!       Passage variable physique -->  physique dynamique
491!       recast (copy) variable from physics grid to dynamics grid
492        do l=1,nbp_lev
493            dx1(l)=px(1,l)
494        enddo
495
496        ierr= NF_INQ_VARID(nid,nom,varid)
497        if (ierr /= NF_NOERR) then
498! corresponding dimensions
499            ierr= NF_INQ_DIMID(nid,"altitude",id(1))
500            ierr= NF_INQ_DIMID(nid,"Time",id(2))
501
502! Create the variable if it doesn't exist yet
503
504            write (*,*) "==========================="
505            write (*,*) "DIAGPEM: creating variable ",trim(nom)
506
507            call def_var(nid,nom,titre,unite,2,id,varid,ierr)
508
509        else
510            if (ntime==0) then
511                write(*,*) "DIAGPEM Error: failed creating variable ",trim(nom)
512                write(*,*) "it seems it already exists!"
513                call abort_physic("writediagpem",trim(nom)//" already exists",1)
514            endif
515        endif
516
517        corner(1)=1
518        corner(2)=ntime
519        edges(1)=nbp_lev
520        edges(2)=1
521!#ifdef NC_DOUBLE
522!           ierr= NF_PUT_VARA_DOUBLE(nid,varid,corner,edges,dx1)
523!#else
524        ierr= NF_PUT_VARA_REAL(nid,varid,corner,edges,dx1)
525!#endif
526
527        if (ierr /= NF_NOERR) then
528            write(*,*) "***** PUT_VAR problem in writediagpem"
529            write(*,*) "***** with dx1: ",trim(nom)
530            write(*,*) 'ierr=', ierr,": ",NF_STRERROR(ierr)
531            call abort_physic("writediagpem","failed writing "//trim(nom),1)
532        endif
533
534!Case of a 0D variable (ie: a time-dependent scalar)
535!---------------------------------------------------
536    else if (dim == 0) then
537
538        dx0 = px (1,1)
539
540        if (is_master) then
541            ! only the master writes to output
542            ierr= NF_INQ_VARID(nid,nom,varid)
543            if (ierr /= NF_NOERR) then
544! corresponding dimensions
545                ierr= NF_INQ_DIMID(nid,"Time",id(1))
546
547! Create the variable if it doesn't exist yet
548                write (*,*) "==========================="
549                write (*,*) "DIAGPEM: creating variable ",trim(nom)
550                call def_var(nid,nom,titre,unite,1,id,varid,ierr)
551
552            else
553                if (ntime==0) then
554                    write(*,*) "DIAGPEM Error: failed creating variable ",trim(nom)
555                    write(*,*) "it seems it already exists!"
556                    call abort_physic("writediagpem",trim(nom)//" already exists",1)
557                endif
558            endif
559
560            corner(1)=ntime
561            edges(1)=1
562
563!#ifdef NC_DOUBLE
564!            ierr = NF_PUT_VARA_DOUBLE (nid,varid,[corner(1)],[edges(1)],[dx0])
565!#else
566            ierr= NF_PUT_VARA_REAL(nid,varid,[corner(1)],[edges(1)],[dx0])
567!#endif
568            if (ierr.ne.NF_NOERR) then
569                write(*,*) "***** PUT_VAR matter in writediagpem"
570                write(*,*) "***** with dx0: ",trim(nom)
571                write(*,*) 'ierr=', ierr,": ",NF_STRERROR(ierr)
572                call abort_physic("writediagpem","failed writing "//trim(nom),1)
573            endif
574        endif !of if (is_master)
575    endif ! of if (dim.eq.3) elseif(dim.eq.2)...
576endif ! of if ( MOD(zitau+1,irythme) .eq.0.)
577
578if (is_master) ierr= NF_CLOSE(nid)
579
580END SUBROUTINE writediagpem
581
582!=================================================================
583
584SUBROUTINE writediagsoilpem(ngrid,name,title,units,dimpx,px)
585
586! Write variable 'name' to NetCDF file 'diagsoil.nc'.
587! The variable may be 3D (lon,lat,depth) subterranean field,
588! a 2D (lon,lat) surface field, or a simple scalar (0D variable).
589!
590! Calls to 'writediagsoilpem' can originate from anywhere in the program;
591! An initialisation of variable 'name' is done if it is the first time
592! that this routine is called with given 'name'; otherwise data is appended
593! (yielding the sought time series of the variable)
594
595! Modifs: Aug.2010 Ehouarn: enforce outputs to be real*4
596
597use comsoil_h_PEM,      only: nsoilmx_PEM, inertiedat_PEM
598use geometry_mod,       only: cell_area
599use mod_phys_lmdz_para, only: is_mpi_root, is_master, gather
600use mod_grid_phy_lmdz,  only: klon_glo, Grid1Dto2D_glo, nbp_lon, nbp_lat
601use mod_grid_phy_lmdz,  only: grid_type, unstructured
602use time_evol_mod,      only: ecritpem, dt_pem
603
604implicit none
605
606include"netcdf.inc"
607
608! Arguments:
609integer,intent(in) :: ngrid ! number of (horizontal) points of physics grid
610! i.e. ngrid = 2+(jjm-1)*iim - 1/jjm
611character(len=*),intent(in) :: name ! 'name' of the variable
612character(len=*),intent(in) :: title ! 'long_name' attribute of the variable
613character(len=*),intent(in) :: units ! 'units' attribute of the variable
614integer,intent(in) :: dimpx ! dimension of the variable (3,2 or 0)
615real,dimension(ngrid,nsoilmx_PEM),intent(in) :: px ! variable
616
617! Local variables:
618real*4,dimension(nbp_lon+1,nbp_lat,nsoilmx_PEM) :: data3 ! to store 3D data
619real*4,dimension(nbp_lon+1,nbp_lat) :: data2 ! to store 2D data
620real*4 :: data0 ! to store 0D data
621real*4 :: data3_1d(1,nsoilmx_PEM) ! to store a profile in 1D model
622real*4 :: data2_1d ! to store surface value with 1D model
623integer :: i,j,l ! for loops
624integer :: ig0
625
626real*4,save :: date ! time counter (in elapsed days)
627
628real :: inertia((nbp_lon+1),nbp_lat,nsoilmx_PEM)
629real :: area((nbp_lon+1),nbp_lat)
630
631real :: inertiafi_glo(klon_glo,nsoilmx_PEM)
632real :: areafi_glo(klon_glo)
633
634integer,save :: isample ! sample rate at which data is to be written to output
635integer,save :: ntime=0 ! counter to internally store time steps
636character(len=20),save :: firstname="1234567890"
637integer,save :: zitau=0
638!$OMP THREADPRIVATE(date,isample,ntime,firstname,zitau)
639
640character(len=30) :: filename="diagsoilpem.nc"
641
642! NetCDF stuff:
643integer :: nid ! NetCDF output file ID
644integer :: varid ! NetCDF ID of a variable
645integer :: ierr ! NetCDF routines return code
646integer,dimension(4) :: id ! NetCDF IDs of the dimensions of the variable
647integer,dimension(4) :: edges,corners
648
649#ifdef CPP_PARA
650! Added to work in parallel mode
651real dx3_glop(klon_glo,nsoilmx_PEM)
652real dx3_glo(nbp_lon,nbp_lat,nsoilmx_PEM) ! to store a global 3D data set
653real dx2_glop(klon_glo)
654real dx2_glo(nbp_lon,nbp_lat)     ! to store a global 2D (surface) data set
655real px2(ngrid)
656#endif
657
658! 0. Do we ouput a diagsoil.nc file? If not just bail out now.
659
660! additional check: one can only output diagsoil.nc files
661! in lon-lat case (or 1D)
662if (grid_type==unstructured) then
663  write(*,*) "writediagsoil: Error !!!"
664  write(*,*) "diagsoil.nc outputs not possible on unstructured grids!!"
665  call abort_physic("writediagsoil","impossible on unstructured grid",1)
666endif
667
668! 1. Initialization step
669if (firstname.eq."1234567890") then
670  ! Store 'name' as 'firstname'
671  firstname=name
672  ! From now on, if 'name'.eq.'firstname', then it is a new time cycle
673
674  ! just to be sure, check that firstnom is large enough to hold nom
675  if (len_trim(firstname).lt.len_trim(name)) then
676    write(*,*) "writediagsoil: Error !!!"
677    write(*,*) "   firstname string not long enough!!"
678    write(*,*) "   increase its size to at least ",len_trim(name)
679    call abort_physic("writediagsoil","firstname too short",1)
680  endif
681 
682  ! Set output sample rate
683  isample = int(ecritpem) ! same as for diagpem outputs
684 
685  ! Create output NetCDF file
686  if (is_master) then
687   ierr=NF_CREATE(filename,NF_CLOBBER,nid)
688   if (ierr.ne.NF_NOERR) then
689    write(*,*)'writediagsoil: Error, failed creating file '//trim(filename)
690    call abort_physic("writediagsoil","failed creating"//trim(filename),1)
691   endif
692  endif
693
694#ifdef CPP_PARA
695   ! Gather inertiedat() soil thermal inertia on physics grid
696   call Gather(inertiedat_PEM,inertiafi_glo)
697   ! Gather cell_area() mesh area on physics grid
698   call Gather(cell_area,areafi_glo)
699#else
700         inertiafi_glo(:,:)=inertiedat_PEM(:,:)
701         areafi_glo(:)=cell_area(:)
702#endif
703
704  if (is_master) then
705   ! build inertia() and area()
706   if (klon_glo>1) then
707    do i=1,nbp_lon+1 ! poles
708     inertia(i,1,1:nsoilmx_PEM)=inertiafi_glo(1,1:nsoilmx_PEM)
709     inertia(i,nbp_lat,1:nsoilmx_PEM)=inertiafi_glo(klon_glo,1:nsoilmx_PEM)
710     ! for area, divide at the poles by nbp_lon
711     area(i,1)=areafi_glo(1)/nbp_lon
712     area(i,nbp_lat)=areafi_glo(klon_glo)/nbp_lon
713    enddo
714    do j=2,nbp_lat-1
715     ig0= 1+(j-2)*nbp_lon
716     do i=1,nbp_lon
717        inertia(i,j,1:nsoilmx_PEM)=inertiafi_glo(ig0+i,1:nsoilmx_PEM)
718        area(i,j)=areafi_glo(ig0+i)
719     enddo
720     ! handle redundant point in longitude
721     inertia(nbp_lon+1,j,1:nsoilmx_PEM)=inertia(1,j,1:nsoilmx_PEM)
722     area(nbp_lon+1,j)=area(1,j)
723    enddo
724   endif
725   
726   ! write "header" of file (longitudes, latitudes, geopotential, ...)
727   if (klon_glo>1) then ! general 3D case
728     call iniwritesoil(nid,ngrid,inertia,area,nbp_lon+1,nbp_lat)
729   else ! 1D model
730     call iniwritesoil(nid,ngrid,inertiafi_glo(1,:),areafi_glo(1),1,1)
731   endif
732
733  endif ! of if (is_master)
734 
735  ! set zitau to -1 to be compatible with zitau incrementation step below
736  zitau=-1
737 
738else
739  ! If not an initialization call, simply open the NetCDF file
740  if (is_master) then
741   ierr=NF_OPEN(filename,NF_WRITE,nid)
742  endif
743endif ! of if (firstname.eq."1234567890")
744
745! 2. Increment local time counter, if necessary
746if (name.eq.firstname) then
747  ! if we run across 'firstname', then it is a new time step
748  zitau = zitau + dt_pem
749endif
750
751! 3. Write data, if the time index matches the sample rate
752if (mod(zitau+1,isample).eq.0) then
753
754! 3.1 If first call at this date, update 'time' variable
755  if (name.eq.firstname) then
756    ntime=ntime+1
757    date = float(zitau + 1)
758   
759    if (is_master) then
760     ! Get NetCDF ID for "time"
761     ierr=NF_INQ_VARID(nid,"time",varid)
762     ! Add the current value of date to the "time" array
763!#ifdef NC_DOUBLE
764!     ierr=NF_PUT_VARA_DOUBLE(nid,varid,ntime,1,date)
765!#else
766     ierr=NF_PUT_VARA_REAL(nid,varid,[ntime],[1],[date])
767!#endif
768     if (ierr.ne.NF_NOERR) then
769      write(*,*)"writediagsoil: Failed writing date to time variable"
770      call abort_physic("writediagsoil","failed writing time",1)
771     endif
772    endif ! of if (is_master)
773  endif ! of if (name.eq.firstname)
774
775! 3.2 Write the variable to the NetCDF file
776if (dimpx.eq.3) then ! Case of a 3D variable
777  ! A. Recast data along 'dynamics' grid
778#ifdef CPP_PARA
779  ! gather field on a "global" (without redundant longitude) array
780  call Gather(px,dx3_glop)
781!$OMP MASTER
782  if (is_mpi_root) then
783    call Grid1Dto2D_glo(dx3_glop,dx3_glo)
784    ! copy dx3_glo() to dx3(:) and add redundant longitude
785    data3(1:nbp_lon,:,:)=dx3_glo(1:nbp_lon,:,:)
786    data3(nbp_lon+1,:,:)=data3(1,:,:)
787  endif
788!$OMP END MASTER
789!$OMP BARRIER
790#else
791  if (klon_glo>1) then ! General case
792   do l=1,nsoilmx_PEM
793    ! handle the poles
794    do i=1,nbp_lon+1
795      data3(i,1,l)=px(1,l)
796      data3(i,nbp_lat,l)=px(ngrid,l)
797    enddo
798    ! rest of the grid
799    do j=2,nbp_lat-1
800      ig0=1+(j-2)*nbp_lon
801      do i=1,nbp_lon
802        data3(i,j,l)=px(ig0+i,l)
803      enddo
804      data3(nbp_lon+1,j,l)=data3(1,j,l) ! extra (modulo) longitude
805    enddo
806   enddo
807  else ! 1D model case
808   data3_1d(1,1:nsoilmx_PEM)=px(1,1:nsoilmx_PEM)
809  endif
810#endif
811 
812  ! B. Write (append) the variable to the NetCDF file
813  if (is_master) then
814  ! B.1. Get the ID of the variable
815  ierr=NF_INQ_VARID(nid,name,varid)
816  if (ierr.ne.NF_NOERR) then
817    ! If we failed geting the variable's ID, we assume it is because
818    ! the variable doesn't exist yet and must be created.
819    ! Start by obtaining corresponding dimensions IDs
820    ierr=NF_INQ_DIMID(nid,"longitude",id(1))
821    ierr=NF_INQ_DIMID(nid,"latitude",id(2))
822    ierr=NF_INQ_DIMID(nid,"depth",id(3))
823    ierr=NF_INQ_DIMID(nid,"time",id(4))
824    ! Tell the world about it
825    write(*,*) "====================="
826    write(*,*) "writediagsoil: creating variable "//trim(name)
827    call def_var(nid,name,title,units,4,id,varid,ierr)
828  endif ! of if (ierr.ne.NF_NOERR)
829 
830  ! B.2. Prepare things to be able to write/append the variable
831  corners(1)=1
832  corners(2)=1
833  corners(3)=1
834  corners(4)=ntime
835 
836  if (klon_glo==1) then
837    edges(1)=1
838  else
839    edges(1)=nbp_lon+1
840  endif
841  edges(2)=nbp_lat
842  edges(3)=nsoilmx_PEM
843  edges(4)=1
844 
845  ! B.3. Write the slab of data
846!#ifdef NC_DOUBLE
847!  ierr=NF_PUT_VARA_DOUBLE(nid,varid,corners,edges,data3)
848!#else
849  if (klon_glo>1) then
850    ierr=NF_PUT_VARA_REAL(nid,varid,corners,edges,data3)
851  else
852    ierr=NF_PUT_VARA_REAL(nid,varid,corners,edges,data3_1d)
853  endif
854!#endif
855  if (ierr.ne.NF_NOERR) then
856    write(*,*) "writediagsoil: Error: Failed writing "//trim(name)//&
857               " to file "//trim(filename)//" at time",date
858  endif
859  endif ! of if (is_master)
860
861elseif (dimpx.eq.2) then ! Case of a 2D variable
862
863  ! A. Recast data along 'dynamics' grid
864#ifdef CPP_PARA
865  ! gather field on a "global" (without redundant longitude) array
866  px2(:)=px(:,1)
867  call Gather(px2,dx2_glop)
868!$OMP MASTER
869  if (is_mpi_root) then
870    call Grid1Dto2D_glo(dx2_glop,dx2_glo)
871    ! copy dx3_glo() to dx3(:) and add redundant longitude
872    data2(1:nbp_lon,:)=dx2_glo(1:nbp_lon,:)
873    data2(nbp_lon+1,:)=data2(1,:)
874  endif
875!$OMP END MASTER
876!$OMP BARRIER
877#else
878  if (klon_glo>1) then ! general case
879    ! handle the poles
880    do i=1,nbp_lon+1
881      data2(i,1)=px(1,1)
882      data2(i,nbp_lat)=px(ngrid,1)
883    enddo
884    ! rest of the grid
885    do j=2,nbp_lat-1
886      ig0=1+(j-2)*nbp_lon
887      do i=1,nbp_lon
888        data2(i,j)=px(ig0+i,1)
889      enddo
890      data2(nbp_lon+1,j)=data2(1,j) ! extra (modulo) longitude
891    enddo
892  else ! 1D model case
893    data2_1d=px(1,1)
894  endif
895#endif
896
897  ! B. Write (append) the variable to the NetCDF file
898  if (is_master) then
899  ! B.1. Get the ID of the variable
900  ierr=NF_INQ_VARID(nid,name,varid)
901  if (ierr.ne.NF_NOERR) then
902    ! If we failed geting the variable's ID, we assume it is because
903    ! the variable doesn't exist yet and must be created.
904    ! Start by obtaining corresponding dimensions IDs
905    ierr=NF_INQ_DIMID(nid,"longitude",id(1))
906    ierr=NF_INQ_DIMID(nid,"latitude",id(2))
907    ierr=NF_INQ_DIMID(nid,"time",id(3))
908    ! Tell the world about it
909    write(*,*) "====================="
910    write(*,*) "writediagsoil: creating variable "//trim(name)
911    call def_var(nid,name,title,units,3,id,varid,ierr)
912  endif ! of if (ierr.ne.NF_NOERR)
913
914  ! B.2. Prepare things to be able to write/append the variable
915  corners(1)=1
916  corners(2)=1
917  corners(3)=ntime
918 
919  if (klon_glo==1) then
920    edges(1)=1
921  else
922    edges(1)=nbp_lon+1
923  endif
924  edges(2)=nbp_lat
925  edges(3)=1
926 
927  ! B.3. Write the slab of data
928!#ifdef NC_DOUBLE
929!  ierr=NF_PUT_VARA_DOUBLE(nid,varid,corners,edges,data2)
930!#else
931  if (klon_glo>1) then ! General case
932    ierr=NF_PUT_VARA_REAL(nid,varid,corners,edges,data2)
933  else
934    ierr=NF_PUT_VARA_REAL(nid,varid,corners,edges,[data2_1d])
935  endif
936!#endif
937  if (ierr.ne.NF_NOERR) then
938    write(*,*) "writediagsoil: Error: Failed writing "//trim(name)//&
939               " to file "//trim(filename)//" at time",date
940  endif
941  endif ! of if (is_master)
942
943elseif (dimpx.eq.0) then ! Case of a 0D variable
944#ifdef CPP_PARA
945  write(*,*) "writediagsoil: dimps==0 case not implemented in // mode!!"
946  call abort_physic("writediagsoil","dimps==0 not implemented",1)
947#endif
948  ! A. Copy data value
949  data0=px(1,1)
950
951  ! B. Write (append) the variable to the NetCDF file
952  ! B.1. Get the ID of the variable
953  ierr=NF_INQ_VARID(nid,name,varid)
954  if (ierr.ne.NF_NOERR) then
955    ! If we failed geting the variable's ID, we assume it is because
956    ! the variable doesn't exist yet and must be created.
957    ! Start by obtaining corresponding dimensions IDs
958    ierr=NF_INQ_DIMID(nid,"time",id(1))
959    ! Tell the world about it
960    write(*,*) "====================="
961    write(*,*) "writediagsoil: creating variable "//trim(name)
962    call def_var(nid,name,title,units,1,id,varid,ierr)
963  endif ! of if (ierr.ne.NF_NOERR)
964
965  ! B.2. Prepare things to be able to write/append the variable
966  corners(1)=ntime
967 
968  edges(1)=1
969
970  ! B.3. Write the data
971!#ifdef NC_DOUBLE
972!  ierr=NF_PUT_VARA_DOUBLE(nid,varid,corners,edges,data0)
973!#else
974  ierr=NF_PUT_VARA_REAL(nid,varid,corners,edges,[data0])
975!#endif
976  if (ierr.ne.NF_NOERR) then
977    write(*,*) "writediagsoil: Error: Failed writing "//trim(name)//&
978               " to file "//trim(filename)//" at time",date
979  endif
980
981endif ! of if (dimpx.eq.3) elseif (dimpx.eq.2) ...
982endif ! of if (mod(zitau+1,isample).eq.0)
983
984! 4. Close the NetCDF file
985if (is_master) then
986  ierr=NF_CLOSE(nid)
987endif
988
989END SUBROUTINE writediagsoilpem
990
991
992END MODULE writediagpem_mod
993
Note: See TracBrowser for help on using the repository browser.