source: IOIPSL/trunk/src/histcom.f90 @ 879

Last change on this file since 879 was 879, checked in by bellier, 14 years ago

bugfix for variables with REAL8 external type

  • Property svn:keywords set to Id
File size: 79.4 KB
Line 
1MODULE histcom
2!-
3!$Id$
4!-
5! This software is governed by the CeCILL license
6! See IOIPSL/IOIPSL_License_CeCILL.txt
7!-
8  USE netcdf
9!-
10  USE stringop, ONLY : nocomma,cmpblank,findpos,find_str,strlowercase
11  USE mathelp,  ONLY : mathop,moycum,buildop
12  USE fliocom,  ONLY : flio_dom_file,flio_dom_att
13  USE calendar
14  USE errioipsl, ONLY : ipslerr,ipsldbg
15!-
16  IMPLICIT NONE
17!-
18  PRIVATE
19  PUBLIC :: histbeg,histdef,histhori,histvert,histend, &
20 &          histwrite,histclo,histsync,ioconf_modname
21!---------------------------------------------------------------------
22!- Some confusing vocabulary in this code !
23!- =========================================
24!-
25!- A REGULAR grid is a grid which is i,j indexes
26!- and thus it is stored in a 2D matrix.
27!- This is opposed to a IRREGULAR grid which is only in a vector
28!- and where we do not know which neighbors we have.
29!- As a consequence we need the bounds for each grid-cell.
30!-
31!- A RECTILINEAR grid is a special case of a regular grid
32!- in which all longitudes for i constant are equal
33!- and all latitudes for j constant.
34!- In other words we do not need the full 2D matrix
35!- to describe the grid, just two vectors.
36!---------------------------------------------------------------------
37!-
38  INTERFACE histbeg
39    MODULE PROCEDURE histbeg_totreg,histbeg_regular,histbeg_irregular
40  END INTERFACE
41!-
42  INTERFACE histhori
43    MODULE PROCEDURE histhori_regular,histhori_irregular
44  END INTERFACE
45!-
46  INTERFACE histwrite
47!---------------------------------------------------------------------
48!- The "histwrite" routines will give the data to the I/O system.
49!- It will trigger the operations to be performed,
50!- and the writting to the file if needed
51!-
52!- We test for the work to be done at this time here so that at a
53!- later stage we can call different operation and write subroutine
54!- for the REAL and INTEGER interfaces
55!-
56!- INPUT
57!- idf      : The ID of the file on which this variable is to be,
58!-            written. The variable should have been defined in
59!-            this file before.
60!- pvarname : The short name of the variable
61!- pitau    : Current timestep
62!- pdata    : The variable, I mean the real data !
63!- nbindex  : The number of indexes provided. If it is equal to
64!-            the size of the full field as provided in histdef
65!-            then nothing is done.
66!- nindex   : The indices used to expand the variable (pdata)
67!-            onto the full field.
68!---------------------------------------------------------------------
69!- histwrite - we have to prepare different type of fields :
70!-             real and integer, 1,2 or 3D
71    MODULE PROCEDURE histwrite_r1d,histwrite_r2d,histwrite_r3d
72  END INTERFACE
73!-
74! Fixed parameter
75!-
76  INTEGER,PARAMETER :: nb_files_max=20,nb_var_max=400, &
77 &                     nb_hax_max=5,nb_zax_max=10,nbopp_max=10
78  REAL,PARAMETER :: missing_val=nf90_fill_real
79  INTEGER,PARAMETER,PUBLIC :: &
80 &  hist_r4=nf90_real4, hist_r8=nf90_real8
81!-
82! Variable derived type
83!-
84TYPE T_D_V
85  INTEGER :: ncvid
86  INTEGER :: nbopp
87  CHARACTER(LEN=20) :: v_name,unit_name
88  CHARACTER(LEN=80) :: title,std_name,fullop
89  CHARACTER(LEN=7)  :: topp
90  CHARACTER(LEN=7),DIMENSION(nbopp_max) :: sopp
91  REAL,DIMENSION(nbopp_max) :: scal
92!-External type (for R4/R8)
93  INTEGER :: v_typ
94!-Sizes of the associated grid and zommed area
95  INTEGER,DIMENSION(3) :: scsize,zorig,zsize
96!-Sizes for the data as it goes through the various math operations
97  INTEGER,DIMENSION(3) :: datasz_in = -1
98  INTEGER :: datasz_max = -1
99!-
100  INTEGER :: h_axid,z_axid,t_axid
101!-
102  REAL,DIMENSION(2) :: hist_minmax
103  LOGICAL :: hist_calc_rng=.FALSE.,hist_wrt_rng=.FALSE.
104!-Book keeping of the axes
105  INTEGER :: tdimid,tax_last
106  CHARACTER(LEN=40) :: tax_name
107!-
108  REAL :: freq_opp,freq_wrt
109  INTEGER :: &
110 &  last_opp,last_wrt,last_opp_chk,last_wrt_chk,nb_opp,nb_wrt
111!- For future optimization
112  REAL,ALLOCATABLE,DIMENSION(:) :: t_bf
113!#  REAL,ALLOCATABLE,DIMENSION(:) :: V_1_D
114!#  REAL,ALLOCATABLE,DIMENSION(:,:) :: V_2_D
115!#  REAL,ALLOCATABLE,DIMENSION(:,:,:) :: V_3_D
116END TYPE T_D_V
117!-
118! File derived type
119!-
120TYPE :: T_D_F
121!-NETCDF IDs for file
122  INTEGER :: ncfid
123!-Time variables
124  INTEGER :: itau0=0
125  REAL :: date0,deltat
126!-Counter of elements (variables, time-horizontal-vertical axis
127  INTEGER :: n_var=0,n_tax=0,n_hax=0,n_zax=0
128!-NETCDF dimension IDs for time-longitude-latitude
129  INTEGER :: tid,xid,yid
130!-General definitions in the NETCDF file
131  INTEGER,DIMENSION(2) :: full_size=0,slab_ori,slab_sz
132!-The horizontal axes
133  CHARACTER(LEN=25),DIMENSION(nb_hax_max,2) :: hax_name
134!-The vertical axes
135  INTEGER,DIMENSION(nb_zax_max) :: zax_size,zax_ids
136  CHARACTER(LEN=20),DIMENSION(nb_zax_max) :: zax_name
137!-
138  LOGICAL :: regular=.TRUE.
139!-DOMAIN ID
140  INTEGER :: dom_id_svg=-1
141!-
142  TYPE(T_D_V),DIMENSION(nb_var_max) :: W_V
143END TYPE T_D_F
144!-
145TYPE(T_D_F),DIMENSION(nb_files_max),SAVE :: W_F
146!-
147! Counter of elements
148!-
149  INTEGER,SAVE :: nb_files=0
150!-
151! A list of functions which require special action
152! (Needs to be updated when functions are added
153!  but they are well located here)
154!-
155  CHARACTER(LEN=30),SAVE :: fuchnbout = 'scatter, fill'
156!- Some configurable variables with locks
157  CHARACTER(LEN=80),SAVE :: model_name='An IPSL model'
158  LOGICAL,SAVE :: lock_modname=.FALSE.
159!-
160!===
161CONTAINS
162!===
163!-
164SUBROUTINE histbeg_totreg                 &
165 & (pfilename,pim,plon,pjm,plat,          &
166 &  par_orix,par_szx,par_oriy,par_szy,    &
167 &  pitau0,pdate0,pdeltat,phoriid,idf,domain_id,nb_bits)
168!---------------------------------------------------------------------
169!- This is just an interface for histbeg_regular in case when
170!- the user provides plon and plat as vectors.
171!- Obviously this can only be used for very regular grids.
172!-
173!- INPUT
174!-
175!- pfilename : Name of the netcdf file to be created
176!- pim       : Size of arrays in longitude direction
177!- plon      : Coordinates of points in longitude
178!- pjm       : Size of arrays in latitude direction
179!- plat      : Coordinates of points in latitude
180!-
181!- The next 4 arguments allow to define a horizontal zoom
182!- for this file. It is assumed that all variables to come
183!- have the same index space. This can not be assumed for
184!- the z axis and thus we define the zoom in histdef.
185!-
186!- par_orix  : Origin of the slab of data within the X axis (pim)
187!- par_szx   : Size of the slab of data in X
188!- par_oriy  : Origin of the slab of data within the Y axis (pjm)
189!- par_szy   : Size of the slab of data in Y
190!-
191!- pitau0    : time step at which the history tape starts
192!- pdate0    : The Julian date at which the itau was equal to 0
193!- pdeltat   : Time step, in seconds, of the counter itau
194!-             used in histwrite for instance
195!-
196!- OUTPUT
197!-
198!- phoriid   : ID of the horizontal grid
199!- idf       : ID of the netcdf file
200!-
201!- Optional INPUT arguments
202!-
203!- domain_id       : Domain identifier
204!-
205!- TO DO
206!-
207!- This package should be written in f90
208!- and use the following features :
209!-    - structures for the meta-data of the files and variables
210!-    - memory allocation as needed
211!-    - Pointers
212!-
213!- VERSION
214!-
215!---------------------------------------------------------------------
216  IMPLICIT NONE
217!-
218  CHARACTER(LEN=*) :: pfilename
219  INTEGER,INTENT(IN) :: pim,pjm
220  REAL,DIMENSION(pim),INTENT(IN) :: plon
221  REAL,DIMENSION(pjm),INTENT(IN) :: plat
222  INTEGER,INTENT(IN):: par_orix,par_szx,par_oriy,par_szy
223  INTEGER,INTENT(IN) :: pitau0
224  REAL,INTENT(IN) :: pdate0,pdeltat
225  INTEGER,INTENT(OUT) :: idf,phoriid
226  INTEGER,INTENT(IN),OPTIONAL :: domain_id,nb_bits
227!-
228  REAL,ALLOCATABLE,DIMENSION(:,:) :: lon_tmp,lat_tmp
229  LOGICAL :: l_dbg
230!---------------------------------------------------------------------
231  CALL ipsldbg (old_status=l_dbg)
232!-
233  IF (l_dbg) WRITE(*,*) "histbeg_totreg"
234!-
235  ALLOCATE(lon_tmp(pim,pjm),lat_tmp(pim,pjm))
236!-
237  lon_tmp(:,:) = SPREAD(plon(:),2,pjm)
238  lat_tmp(:,:) = SPREAD(plat(:),1,pim)
239!-
240  CALL histbeg_regular &
241 &  (pfilename,pim,lon_tmp,pjm,lat_tmp, &
242 &   par_orix,par_szx,par_oriy,par_szy, &
243 &   pitau0,pdate0,pdeltat,phoriid,idf, &
244 &   .TRUE.,domain_id,nb_bits)
245!-
246  DEALLOCATE(lon_tmp,lat_tmp)
247!----------------------------
248END SUBROUTINE histbeg_totreg
249!===
250SUBROUTINE histbeg_regular &
251 & (pfilename,pim,plon,pjm,plat,           &
252 &  par_orix,par_szx,par_oriy,par_szy,     &
253 &  pitau0,pdate0,pdeltat,phoriid,idf, &
254 &  opt_rectilinear,domain_id,nb_bits)
255!---------------------------------------------------------------------
256!- This subroutine initializes a netcdf file and returns the ID.
257!- It will set up the geographical space on which the data will be
258!- stored and offers the possibility of seting a zoom.
259!- It also gets the global parameters into the I/O subsystem.
260!-
261!- INPUT
262!-
263!- pfilename : Name of the netcdf file to be created
264!- pim       : Size of arrays in longitude direction
265!- plon      : Coordinates of points in longitude
266!- pjm       : Size of arrays in latitude direction
267!- plat      : Coordinates of points in latitude
268!-
269!- The next 4 arguments allow to define a horizontal zoom
270!- for this file. It is assumed that all variables to come
271!- have the same index space. This can not be assumed for
272!- the z axis and thus we define the zoom in histdef.
273!-
274!- par_orix  : Origin of the slab of data within the X axis (pim)
275!- par_szx   : Size of the slab of data in X
276!- par_oriy  : Origin of the slab of data within the Y axis (pjm)
277!- par_szy   : Size of the slab of data in Y
278!-
279!- pitau0    : time step at which the history tape starts
280!- pdate0    : The Julian date at which the itau was equal to 0
281!- pdeltat   : Time step, in seconds, of the counter itau
282!-             used in histwrite for instance
283!-
284!- OUTPUT
285!-
286!- phoriid   : ID of the horizontal grid
287!- idf       : ID of the netcdf file
288!-
289!- Optional INPUT arguments
290!-
291!- opt_rectilinear : If true we know the grid is rectilinear
292!- domain_id       : Domain identifier
293!-
294!- TO DO
295!-
296!- This package should be written in F90 and use the following
297!- feature :
298!-   - structures for the meta-data of the files and variables
299!-   - memory allocation as needed
300!-   - Pointers
301!-
302!- VERSION
303!-
304!---------------------------------------------------------------------
305  IMPLICIT NONE
306!-
307  CHARACTER(LEN=*) :: pfilename
308  INTEGER,INTENT(IN) :: pim,pjm
309  REAL,DIMENSION(pim,pjm),INTENT(IN) :: plon,plat
310  INTEGER,INTENT(IN):: par_orix,par_szx,par_oriy,par_szy
311  INTEGER,INTENT(IN) :: pitau0
312  REAL,INTENT(IN) :: pdate0,pdeltat
313  INTEGER,INTENT(OUT) :: idf,phoriid
314  LOGICAL,INTENT(IN),OPTIONAL :: opt_rectilinear
315  INTEGER,INTENT(IN),OPTIONAL :: domain_id,nb_bits
316!-
317  INTEGER :: nfid,iret,m_c
318  CHARACTER(LEN=120) :: file
319  CHARACTER(LEN=30) :: timenow
320  LOGICAL :: rectilinear
321  LOGICAL :: l_dbg
322!---------------------------------------------------------------------
323  CALL ipsldbg (old_status=l_dbg)
324!-
325  IF (l_dbg) WRITE(*,*) "histbeg_regular 0.0"
326!-
327  nb_files = nb_files+1
328  IF (nb_files > nb_files_max) THEN
329    CALL ipslerr (3,"histbeg", &
330   &  'Table of files too small. You should increase nb_files_max', &
331   &  'in histcom.f90 in order to accomodate all these files',' ')
332  ENDIF
333  idf = nb_files
334!-
335! 1.0 Transfering into the common for future use
336!-
337  IF (l_dbg) WRITE(*,*) "histbeg_regular 1.0"
338!-
339  W_F(idf)%itau0  = pitau0
340  W_F(idf)%date0  = pdate0
341  W_F(idf)%deltat = pdeltat
342!-
343  IF (PRESENT(opt_rectilinear)) THEN
344    rectilinear = opt_rectilinear
345  ELSE
346    rectilinear = .FALSE.
347  ENDIF
348!-
349! 2.0 Initializes all variables for this file
350!-
351  IF (l_dbg) WRITE(*,*) "histbeg_regular 2.0"
352!-
353  W_F(idf)%n_var = 0
354  W_F(idf)%n_tax = 0
355  W_F(idf)%n_hax = 0
356  W_F(idf)%n_zax = 0
357!-
358  W_F(idf)%slab_ori(1:2) = (/ par_orix,par_oriy /)
359  W_F(idf)%slab_sz(1:2)  = (/ par_szx, par_szy  /)
360!-
361! 3.0 Opening netcdf file and defining dimensions
362!-
363  IF (l_dbg) WRITE(*,*) "histbeg_regular 3.0"
364!-
365! Add DOMAIN number and ".nc" suffix in file name if needed
366!-
367  file = pfilename
368  CALL flio_dom_file (file,domain_id)
369!-
370! Check the mode
371  IF (PRESENT(nb_bits)) THEN
372    SELECT CASE (nb_bits)
373    CASE(32)
374      m_c = NF90_CLOBBER
375    CASE(64)
376      m_c = IOR(NF90_CLOBBER,NF90_64BIT_OFFSET)
377    CASE DEFAULT
378      CALL ipslerr (3,"histbeg", &
379 &      'Invalid argument nb_bits for file :',TRIM(file), &
380 &      'Supported values are 32 or 64')
381    END SELECT
382  ELSE
383    m_c = IOR(NF90_CLOBBER,NF90_64BIT_OFFSET)
384  ENDIF
385!-
386! Create file
387  iret = NF90_CREATE (file,m_c,nfid)
388!-
389  IF (rectilinear) THEN
390    iret = NF90_DEF_DIM (nfid,'lon',par_szx,W_F(idf)%xid)
391    iret = NF90_DEF_DIM (nfid,'lat',par_szy,W_F(idf)%yid)
392  ELSE
393    iret = NF90_DEF_DIM (nfid,'x',par_szx,W_F(idf)%xid)
394    iret = NF90_DEF_DIM (nfid,'y',par_szy,W_F(idf)%yid)
395  ENDIF
396!-
397! 4.0 Declaring the geographical coordinates and other attributes
398!-
399  IF (l_dbg) WRITE(*,*) "histbeg_regular 4.0"
400!-
401! 4.3 Global attributes
402!-
403  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'Conventions','CF-1.1')
404  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'file_name',TRIM(file))
405  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'production',TRIM(model_name))
406  lock_modname = .TRUE.
407  CALL ioget_timestamp (timenow)
408  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'TimeStamp',TRIM(timenow))
409!-
410! 5.0 Saving some important information on this file in the common
411!-
412  IF (l_dbg) WRITE(*,*) "histbeg_regular 5.0"
413!-
414  IF (PRESENT(domain_id)) THEN
415    W_F(idf)%dom_id_svg = domain_id
416  ENDIF
417  W_F(idf)%ncfid = nfid
418  W_F(idf)%full_size(1:2) = (/ pim,pjm /)
419!-
420! 6.0 storing the geographical coordinates
421!-
422  W_F(idf)%regular=.TRUE.
423!-
424  CALL histhori_regular (idf,pim,plon,pjm,plat, &
425 &  ' ','Default grid',phoriid,rectilinear)
426!-----------------------------
427END SUBROUTINE histbeg_regular
428!===
429SUBROUTINE histbeg_irregular &
430 &  (pfilename,pim,plon,plon_bounds,plat,plat_bounds,   &
431 &   pitau0,pdate0,pdeltat,phoriid,idf,domain_id,nb_bits)
432!---------------------------------------------------------------------
433!- This subroutine initializes a netcdf file and returns the ID.
434!- This version is for totaly irregular grids. In this case all
435!- all the data comes in as vectors and for the grid we have
436!- the coordinates of the 4 corners.
437!- It also gets the global parameters into the I/O subsystem.
438!-
439!- INPUT
440!-
441!- pfilename   : Name of the netcdf file to be created
442!- pim         : Size of arrays in longitude direction
443!- plon        : Coordinates of points in longitude
444!- plon_bounds : The 2 corners of the grid in longitude
445!- plat        : Coordinates of points in latitude
446!- plat_bounds : The 2 corners of the grid in latitude
447!-
448!- pitau0    : time step at which the history tape starts
449!- pdate0    : The Julian date at which the itau was equal to 0
450!- pdeltat   : Time step, in seconds, of the counter itau
451!-             used in histwrite for instance
452!-
453!- OUTPUT
454!-
455!- phoriid   : ID of the horizontal grid
456!- idf       : ID of the netcdf file
457!-
458!- Optional INPUT arguments
459!-
460!- domain_id       : Domain identifier
461!-
462!- TO DO
463!-
464!- This package should be written in F90 and use the following
465!- feature :
466!-   - structures for the meta-data of the files and variables
467!-   - memory allocation as needed
468!-   - Pointers
469!-
470!- VERSION
471!-
472!---------------------------------------------------------------------
473  IMPLICIT NONE
474!-
475  CHARACTER(LEN=*) :: pfilename
476  INTEGER,INTENT(IN) :: pim
477  REAL,DIMENSION(pim),INTENT(IN) :: plon,plat
478  REAL,DIMENSION(:,:),INTENT(IN) :: plon_bounds,plat_bounds
479  INTEGER,INTENT(IN) :: pitau0
480  REAL,INTENT(IN) :: pdate0,pdeltat
481  INTEGER,INTENT(OUT) :: idf,phoriid
482  INTEGER,INTENT(IN),OPTIONAL :: domain_id,nb_bits
483!-
484  INTEGER :: nfid,iret,m_c
485  CHARACTER(LEN=120) :: file
486  CHARACTER(LEN=30) :: timenow
487  LOGICAL :: l_dbg
488!---------------------------------------------------------------------
489  CALL ipsldbg (old_status=l_dbg)
490!-
491  IF (l_dbg) WRITE(*,*) "histbeg_irregular 0.0"
492!-
493  nb_files = nb_files+1
494  IF (nb_files > nb_files_max) THEN
495    CALL ipslerr (3,"histbeg", &
496 &    'Table of files too small. You should increase nb_files_max', &
497 &    'in histcom.f90 in order to accomodate all these files',' ')
498  ENDIF
499  idf = nb_files
500!-
501! 1.0 Transfering into the common for future use
502!-
503  IF (l_dbg) WRITE(*,*) "histbeg_irregular 1.0"
504!-
505  W_F(idf)%itau0  = pitau0
506  W_F(idf)%date0  = pdate0
507  W_F(idf)%deltat = pdeltat
508!-
509! 2.0 Initializes all variables for this file
510!-
511  IF (l_dbg) WRITE(*,*) "histbeg_irregular 2.0"
512!-
513  W_F(idf)%n_var = 0
514  W_F(idf)%n_tax = 0
515  W_F(idf)%n_hax = 0
516  W_F(idf)%n_zax = 0
517!-
518  W_F(idf)%slab_ori(1:2) = (/ 1,1 /)
519  W_F(idf)%slab_sz(1:2)  = (/ pim,1 /)
520!-
521! 3.0 Opening netcdf file and defining dimensions
522!-
523  IF (l_dbg) WRITE(*,*) "histbeg_irregular 3.0"
524!-
525! Add DOMAIN number and ".nc" suffix in file name if needed
526!-
527  file  = pfilename
528  CALL flio_dom_file (file,domain_id)
529!-
530! Check the mode
531  IF (PRESENT(nb_bits)) THEN
532    SELECT CASE (nb_bits)
533    CASE(32)
534      m_c = NF90_CLOBBER
535    CASE(64)
536      m_c = IOR(NF90_CLOBBER,NF90_64BIT_OFFSET)
537    CASE DEFAULT
538      CALL ipslerr (3,"histbeg", &
539 &      'Invalid argument nb_bits for file :',TRIM(file), &
540 &      'Supported values are 32 or 64')
541    END SELECT
542  ELSE
543    m_c = IOR(NF90_CLOBBER,NF90_64BIT_OFFSET)
544  ENDIF
545!-
546! Create file
547  iret = NF90_CREATE (file,m_c,nfid)
548!-
549  iret = NF90_DEF_DIM (nfid,'x',pim,W_F(idf)%xid)
550  W_F(idf)%yid = 0
551!-
552! 4.0 Declaring the geographical coordinates and other attributes
553!-
554  IF (l_dbg) WRITE(*,*) "histbeg_irregular 4.0"
555!-
556! 4.3 Global attributes
557!-
558  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'Conventions','CF-1.1')
559  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'file_name',TRIM(file))
560  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'production',TRIM(model_name))
561  lock_modname = .TRUE.
562  CALL ioget_timestamp (timenow)
563  iret = NF90_PUT_ATT (nfid,NF90_GLOBAL,'TimeStamp',TRIM(timenow))
564!-
565! 5.0 Saving some important information on this file in the common
566!-
567  IF (l_dbg) WRITE(*,*) "histbeg_irregular 5.0"
568!-
569  IF (PRESENT(domain_id)) THEN
570    W_F(idf)%dom_id_svg = domain_id
571  ENDIF
572  W_F(idf)%ncfid = nfid
573  W_F(idf)%full_size(1:2) = (/ pim,1 /)
574!-
575! 6.0 storing the geographical coordinates
576!-
577  W_F(idf)%regular=.FALSE.
578!-
579  CALL histhori_irregular &
580 &  (idf,pim,plon,plon_bounds,plat,plat_bounds, &
581 &   ' ','Default grid',phoriid)
582!-------------------------------
583END SUBROUTINE histbeg_irregular
584!===
585SUBROUTINE histhori_regular &
586 &  (idf,pim,plon,pjm,plat,phname,phtitle,phid,opt_rectilinear)
587!---------------------------------------------------------------------
588!- This subroutine is made to declare a new horizontale grid.
589!- It has to have the same number of points as
590!- the original and thus in this routine we will only
591!- add two variable (longitude and latitude).
592!- Any variable in the file can thus point to this pair
593!- through an attribute. This routine is very usefull
594!- to allow staggered grids.
595!-
596!- INPUT
597!-
598!- idf     : The id of the file to which the grid should be added
599!- pim     : Size in the longitude direction
600!- plon    : The longitudes
601!- pjm     : Size in the latitude direction
602!- plat    : The latitudes
603!- phname  : The name of grid
604!- phtitle : The title of the grid
605!-
606!- OUTPUT
607!-
608!- phid    : Id of the created grid
609!-
610!- OPTIONAL
611!-
612!- opt_rectilinear : If true we know the grid is rectilinear.
613!-
614!---------------------------------------------------------------------
615  IMPLICIT NONE
616!-
617  INTEGER,INTENT(IN) :: idf,pim,pjm
618  REAL,INTENT(IN),DIMENSION(pim,pjm) :: plon,plat
619  CHARACTER(LEN=*),INTENT(IN) :: phname,phtitle
620  INTEGER,INTENT(OUT) :: phid
621  LOGICAL,INTENT(IN),OPTIONAL :: opt_rectilinear
622!-
623  CHARACTER(LEN=25) :: lon_name,lat_name
624  CHARACTER(LEN=80) :: tmp_title,tmp_name
625  INTEGER :: ndim
626  INTEGER,DIMENSION(2) :: dims
627  INTEGER :: nlonid,nlatid
628  INTEGER :: orix,oriy,par_szx,par_szy
629  INTEGER :: iret,nfid
630  LOGICAL :: rectilinear
631  LOGICAL :: l_dbg
632!---------------------------------------------------------------------
633  CALL ipsldbg (old_status=l_dbg)
634!-
635! 1.0 Check that all fits in the buffers
636!-
637  IF (    (pim /= W_F(idf)%full_size(1)) &
638 &    .OR.(pjm /= W_F(idf)%full_size(2)) ) THEN
639    CALL ipslerr (3,"histhori", &
640 &   'The new horizontal grid does not have the same size', &
641 &   'as the one provided to histbeg. This is not yet ', &
642 &   'possible in the hist package.')
643  ENDIF
644!-
645  IF (PRESENT(opt_rectilinear)) THEN
646    rectilinear = opt_rectilinear
647  ELSE
648    rectilinear = .FALSE.
649  ENDIF
650!-
651! 1.1 Create all the variables needed
652!-
653  IF (l_dbg) WRITE(*,*) "histhori_regular 1.0"
654!-
655  nfid = W_F(idf)%ncfid
656!-
657  ndim = 2
658  dims(1:2) = (/ W_F(idf)%xid,W_F(idf)%yid /)
659!-
660  tmp_name = phname
661  IF (rectilinear) THEN
662    IF (W_F(idf)%n_hax == 0) THEN
663      lon_name = 'lon'
664      lat_name = 'lat'
665    ELSE
666      lon_name = 'lon_'//TRIM(tmp_name)
667      lat_name = 'lat_'//TRIM(tmp_name)
668    ENDIF
669  ELSE
670    IF (W_F(idf)%n_hax == 0) THEN
671      lon_name = 'nav_lon'
672      lat_name = 'nav_lat'
673    ELSE
674      lon_name = 'nav_lon_'//TRIM(tmp_name)
675      lat_name = 'nav_lat_'//TRIM(tmp_name)
676    ENDIF
677  ENDIF
678!-
679! 1.2 Save the informations
680!-
681  phid = W_F(idf)%n_hax+1
682  W_F(idf)%n_hax = phid
683  W_F(idf)%hax_name(phid,1:2) = (/ lon_name,lat_name /)
684  tmp_title = phtitle
685!-
686! 2.0 Longitude
687!-
688  IF (l_dbg) WRITE(*,*) "histhori_regular 2.0"
689!-
690  IF (rectilinear) THEN
691    ndim = 1
692    dims(1:1) = (/ W_F(idf)%xid /)
693  ENDIF
694  iret = NF90_DEF_VAR (nfid,lon_name,NF90_FLOAT,dims(1:ndim),nlonid)
695  IF (rectilinear) THEN
696    iret = NF90_PUT_ATT (nfid,nlonid,'axis',"X")
697  ENDIF
698  iret = NF90_PUT_ATT (nfid,nlonid,'standard_name',"longitude")
699  iret = NF90_PUT_ATT (nfid,nlonid,'units',"degrees_east")
700  iret = NF90_PUT_ATT (nfid,nlonid,'valid_min', &
701 &                     REAL(MINVAL(plon),KIND=4))
702  iret = NF90_PUT_ATT (nfid,nlonid,'valid_max', &
703 &                     REAL(MAXVAL(plon),KIND=4))
704  iret = NF90_PUT_ATT (nfid,nlonid,'long_name',"Longitude")
705  iret = NF90_PUT_ATT (nfid,nlonid,'nav_model',TRIM(tmp_title))
706!-
707! 3.0 Latitude
708!-
709  IF (l_dbg) WRITE(*,*) "histhori_regular 3.0"
710!-
711  IF (rectilinear) THEN
712    ndim = 1
713    dims(1:1) = (/ W_F(idf)%yid /)
714  ENDIF
715  iret = NF90_DEF_VAR (nfid,lat_name,NF90_FLOAT,dims(1:ndim),nlatid)
716  IF (rectilinear) THEN
717    iret = NF90_PUT_ATT (nfid,nlatid,'axis',"Y")
718  ENDIF
719  iret = NF90_PUT_ATT (nfid,nlatid,'standard_name',"latitude")
720  iret = NF90_PUT_ATT (nfid,nlatid,'units',"degrees_north")
721  iret = NF90_PUT_ATT (nfid,nlatid,'valid_min', &
722 &                     REAL(MINVAL(plat),KIND=4))
723  iret = NF90_PUT_ATT (nfid,nlatid,'valid_max', &
724 &                     REAL(MAXVAL(plat),KIND=4))
725  iret = NF90_PUT_ATT (nfid,nlatid,'long_name',"Latitude")
726  iret = NF90_PUT_ATT (nfid,nlatid,'nav_model',TRIM(tmp_title))
727!-
728  iret = NF90_ENDDEF (nfid)
729!-
730! 4.0 storing the geographical coordinates
731!-
732  IF (l_dbg) WRITE(*,*) "histhori_regular 4.0"
733!-
734  orix = W_F(idf)%slab_ori(1)
735  oriy = W_F(idf)%slab_ori(2)
736  par_szx = W_F(idf)%slab_sz(1)
737  par_szy = W_F(idf)%slab_sz(2)
738!-
739! Transfer the longitude
740!-
741  IF (rectilinear) THEN
742    iret = NF90_PUT_VAR (nfid,nlonid,plon(orix:orix+par_szx-1,1))
743  ELSE
744    iret = NF90_PUT_VAR (nfid,nlonid, &
745 &           plon(orix:orix+par_szx-1,oriy:oriy+par_szy-1))
746  ENDIF
747!-
748! Transfer the latitude
749!-
750  IF (rectilinear) THEN
751    iret = NF90_PUT_VAR (nfid,nlatid,plat(1,oriy:oriy+par_szy-1))
752  ELSE
753    iret = NF90_PUT_VAR (nfid,nlatid, &
754 &           plat(orix:orix+par_szx-1,oriy:oriy+par_szy-1))
755  ENDIF
756!-
757  iret = NF90_REDEF (nfid)
758!------------------------------
759END SUBROUTINE histhori_regular
760!===
761SUBROUTINE histhori_irregular &
762 &  (idf,pim,plon,plon_bounds,plat,plat_bounds, &
763 &   phname,phtitle,phid)
764!---------------------------------------------------------------------
765!- This subroutine is made to declare a new horizontale grid.
766!- It has to have the same number of points as
767!- the original and thus in this routine we will only
768!- add two variable (longitude and latitude).
769!- Any variable in the file can thus point to this pair
770!- through an attribute. This routine is very usefull
771!- to allow staggered grids.
772!-
773!- INPUT
774!-
775!- idf         : The id of the file to which the grid should be added
776!- pim         : Size in the longitude direction
777!- plon        : The longitudes
778!- plon_bounds : The boundaries of the grid in longitude
779!- plat        : The latitudes
780!- plat_bounds : Boundaries of the grid in latitude
781!- phname      : The name of grid
782!- phtitle     : The title of the grid
783!-
784!- OUTPUT
785!-
786!- phid    : Id of the created grid
787!---------------------------------------------------------------------
788  IMPLICIT NONE
789!-
790  INTEGER,INTENT(IN) :: idf,pim
791  REAL,DIMENSION(pim),INTENT(IN) :: plon,plat
792  REAL,DIMENSION(:,:),INTENT(IN) :: plon_bounds,plat_bounds
793  CHARACTER(LEN=*),INTENT(IN) :: phname,phtitle
794  INTEGER,INTENT(OUT) :: phid
795!-
796  CHARACTER(LEN=25) :: lon_name,lat_name
797  CHARACTER(LEN=30) :: lonbound_name,latbound_name
798  CHARACTER(LEN=80) :: tmp_title,tmp_name,longname
799  INTEGER :: ndim,dims(2)
800  INTEGER :: ndimb,dimsb(2)
801  INTEGER :: nbbounds
802  INTEGER :: nlonid,nlatid,nlonidb,nlatidb
803  INTEGER :: iret,nfid,twoid
804  LOGICAL :: transp = .FALSE.
805  REAL,ALLOCATABLE,DIMENSION(:,:) :: bounds_trans
806  LOGICAL :: l_dbg
807!---------------------------------------------------------------------
808  CALL ipsldbg (old_status=l_dbg)
809!-
810! 1.0 Check that all fits in the buffers
811!-
812  IF (    (pim /= W_F(idf)%full_size(1)) &
813 &    .OR.(W_F(idf)%full_size(2) /= 1) ) THEN
814    CALL ipslerr (3,"histhori", &
815 &   'The new horizontal grid does not have the same size', &
816 &   'as the one provided to histbeg. This is not yet ', &
817 &   'possible in the hist package.')
818  ENDIF
819!-
820! 1.1 Create all the variables needed
821!-
822  IF (l_dbg) WRITE(*,*) 'histhori_irregular 1.0'
823!-
824  nfid = W_F(idf)%ncfid
825!-
826  IF     (SIZE(plon_bounds,DIM=1) == pim) THEN
827    nbbounds = SIZE(plon_bounds,DIM=2)
828    transp = .TRUE.
829  ELSEIF (SIZE(plon_bounds,DIM=2) == pim) THEN
830    nbbounds = SIZE(plon_bounds,DIM=1)
831    transp = .FALSE.
832  ELSE
833    CALL ipslerr (3,"histhori", &
834   &  'The boundary variable does not have any axis corresponding', &
835   &  'to the size of the longitude or latitude variable', &
836   &  '.')
837  ENDIF
838!-
839  ALLOCATE(bounds_trans(nbbounds,pim))
840!-
841  iret = NF90_DEF_DIM (nfid,'nbnd',nbbounds,twoid)
842  ndim = 1
843  dims(1) = W_F(idf)%xid
844  ndimb = 2
845  dimsb(1:2) = (/ twoid,W_F(idf)%xid /)
846!-
847  tmp_name = phname
848  IF (W_F(idf)%n_hax == 0) THEN
849    lon_name = 'nav_lon'
850    lat_name = 'nav_lat'
851  ELSE
852    lon_name = 'nav_lon_'//TRIM(tmp_name)
853    lat_name = 'nav_lat_'//TRIM(tmp_name)
854  ENDIF
855  lonbound_name = TRIM(lon_name)//'_bounds'
856  latbound_name = TRIM(lat_name)//'_bounds'
857!-
858! 1.2 Save the informations
859!-
860  phid = W_F(idf)%n_hax+1
861  W_F(idf)%n_hax = phid
862  W_F(idf)%hax_name(phid,1:2) = (/ lon_name,lat_name /)
863  tmp_title = phtitle
864!-
865! 2.0 Longitude
866!-
867  IF (l_dbg) WRITE(*,*) "histhori_irregular 2.0"
868!-
869  iret = NF90_DEF_VAR (nfid,lon_name,NF90_FLOAT,dims(1:ndim),nlonid)
870  iret = NF90_PUT_ATT (nfid,nlonid,'standard_name',"longitude")
871  iret = NF90_PUT_ATT (nfid,nlonid,'units',"degrees_east")
872  iret = NF90_PUT_ATT (nfid,nlonid,'valid_min', &
873 &                     REAL(MINVAL(plon),KIND=4))
874  iret = NF90_PUT_ATT (nfid,nlonid,'valid_max', &
875 &                     REAL(MAXVAL(plon),KIND=4))
876  iret = NF90_PUT_ATT (nfid,nlonid,'long_name',"Longitude")
877  iret = NF90_PUT_ATT (nfid,nlonid,'nav_model',TRIM(tmp_title))
878!-
879! 2.1 Longitude bounds
880!-
881  iret = NF90_PUT_ATT (nfid,nlonid,'bounds',TRIM(lonbound_name))
882  iret = NF90_DEF_VAR (nfid,lonbound_name,NF90_FLOAT, &
883 &                     dimsb(1:ndimb),nlonidb)
884  longname = 'Boundaries for coordinate variable '//TRIM(lon_name)
885  iret = NF90_PUT_ATT (nfid,nlonidb,'long_name',TRIM(longname))
886!-
887! 3.0 Latitude
888!-
889  IF (l_dbg) WRITE(*,*) "histhori_irregular 3.0"
890!-
891  iret = NF90_DEF_VAR (nfid,lat_name,NF90_FLOAT,dims(1:ndim),nlatid)
892  iret = NF90_PUT_ATT (nfid,nlatid,'standard_name',"latitude")
893  iret = NF90_PUT_ATT (nfid,nlatid,'units',"degrees_north")
894  iret = NF90_PUT_ATT (nfid,nlatid,'valid_min', &
895 &                     REAL(MINVAL(plat),KIND=4))
896  iret = NF90_PUT_ATT (nfid,nlatid,'valid_max', &
897 &                     REAL(MAXVAL(plat),KIND=4))
898  iret = NF90_PUT_ATT (nfid,nlatid,'long_name',"Latitude")
899  iret = NF90_PUT_ATT (nfid,nlatid,'nav_model',TRIM(tmp_title))
900!-
901! 3.1 Latitude bounds
902!-
903  iret = NF90_PUT_ATT (nfid,nlatid,'bounds',TRIM(latbound_name))
904  iret = NF90_DEF_VAR (nfid,latbound_name,NF90_FLOAT, &
905 &                     dimsb(1:ndimb),nlatidb)
906  longname = 'Boundaries for coordinate variable '//TRIM(lat_name)
907  iret = NF90_PUT_ATT (nfid,nlatidb,'long_name',TRIM(longname))
908!-
909  iret = NF90_ENDDEF (nfid)
910!-
911! 4.0 storing the geographical coordinates
912!-
913  IF (l_dbg) WRITE(*,*) "histhori_irregular 4.0"
914!-
915! 4.1 Write the longitude
916!-
917  iret = NF90_PUT_VAR (nfid,nlonid,plon(1:pim))
918!-
919! 4.2 Write the longitude bounds
920!-
921  IF (transp) THEN
922    bounds_trans = TRANSPOSE(plon_bounds)
923  ELSE
924    bounds_trans = plon_bounds
925  ENDIF
926  iret = NF90_PUT_VAR (nfid,nlonidb,bounds_trans(1:nbbounds,1:pim))
927!-
928! 4.3 Write the latitude
929!-
930  iret = NF90_PUT_VAR (nfid,nlatid,plat(1:pim))
931!-
932! 4.4 Write the latitude bounds
933!-
934  IF (transp) THEN
935    bounds_trans = TRANSPOSE(plat_bounds)
936  ELSE
937    bounds_trans = plat_bounds
938  ENDIF
939  iret = NF90_PUT_VAR (nfid,nlatidb,bounds_trans(1:nbbounds,1:pim))
940!-
941  DEALLOCATE(bounds_trans)
942!-
943  iret = NF90_REDEF (nfid)
944!--------------------------------
945END SUBROUTINE histhori_irregular
946!===
947SUBROUTINE histvert (idf,pzaxname,pzaxtitle,pzaxunit, &
948 &                   pzsize,pzvalues,pzaxid,pdirect)
949!---------------------------------------------------------------------
950!- This subroutine defines a vertical axis and returns it s id.
951!- It gives the user the possibility to the user to define many
952!- different vertical axes. For each variable defined with histdef a
953!- vertical axis can be specified with by it s ID.
954!-
955!- INPUT
956!-
957!- idf      : ID of the file the variable should be archived in
958!- pzaxname : Name of the vertical axis
959!- pzaxtitle: title of the vertical axis
960!- pzaxunit : Units of the vertical axis (no units if blank string)
961!- pzsize   : size of the vertical axis
962!- pzvalues : Coordinate values of the vetical axis
963!-
964!- pdirect  : is an optional argument which allows to specify the
965!-            the positive direction of the axis : up or down.
966!- OUTPUT
967!-
968!- pzaxid   : Returns the ID of the axis.
969!-            Note that this is not the netCDF ID !
970!-
971!- VERSION
972!-
973!---------------------------------------------------------------------
974  IMPLICIT NONE
975!-
976  INTEGER,INTENT(IN) :: idf,pzsize
977  CHARACTER(LEN=*),INTENT(IN) :: pzaxname,pzaxunit,pzaxtitle
978  REAL,INTENT(IN) :: pzvalues(pzsize)
979  INTEGER,INTENT(OUT) :: pzaxid
980  CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: pdirect
981!-
982  INTEGER :: pos,iv,zdimid,zaxid_tmp
983  CHARACTER(LEN=70) :: str71
984  CHARACTER(LEN=80) :: str80
985  CHARACTER(LEN=20) :: direction
986  INTEGER :: iret,leng,nfid
987  LOGICAL :: l_dbg
988!---------------------------------------------------------------------
989  CALL ipsldbg (old_status=l_dbg)
990!-
991! 1.0 Verifications :
992!    Do we have enough space for an extra axis ?
993!    Is the name already in use ?
994!-
995  IF (l_dbg) WRITE(*,*) "histvert : 1.0 Verifications", &
996 &                      pzaxname,'---',pzaxunit,'---',pzaxtitle
997!-
998! - Direction of axis. Can we get if from the user.
999!   If not we put unknown.
1000!-
1001  IF (PRESENT(pdirect)) THEN
1002    direction = TRIM(pdirect)
1003    CALL strlowercase (direction)
1004  ELSE
1005    direction = 'unknown'
1006  ENDIF
1007!-
1008! Check the consistency of the attribute
1009!-
1010  IF (     (direction /= 'unknown') &
1011 &    .AND.(direction /= 'up')      &
1012 &    .AND.(direction /= 'down')   ) THEN
1013    direction = 'unknown'
1014    str80 = 'The specified axis was : '//TRIM(direction)
1015    CALL ipslerr (2,"histvert",&
1016   & "The specified direction for the vertical axis is not possible.",&
1017   & "it is replaced by : unknown",str80)
1018  ENDIF
1019!-
1020  IF (W_F(idf)%n_zax+1 > nb_zax_max) THEN
1021    CALL ipslerr (3,"histvert", &
1022   &  'Table of vertical axes too small. You should increase ',&
1023   &  'nb_zax_max in histcom.f90 in order to accomodate all ', &
1024   &  'these variables ')
1025  ENDIF
1026!-
1027  iv = W_F(idf)%n_zax
1028  IF (iv > 1) THEN
1029    CALL find_str (W_F(idf)%zax_name(1:iv-1),pzaxname,pos)
1030  ELSE
1031    pos = 0
1032  ENDIF
1033!-
1034  IF (pos > 0) THEN
1035    WRITE(str71,'("Check variable ",A," in file",I3)') &
1036 &    TRIM(pzaxname),idf
1037    CALL ipslerr (3,"histvert", &
1038 &    "Vertical axis already exists",TRIM(str71), &
1039 &    "Can also be a wrong file ID in another declaration")
1040  ENDIF
1041!-
1042  iv = W_F(idf)%n_zax+1
1043!-
1044! 2.0 Add the information to the file
1045!-
1046  IF (l_dbg) &
1047 &  WRITE(*,*) "histvert : 2.0 Add the information to the file"
1048!-
1049  nfid = W_F(idf)%ncfid
1050!-
1051  leng = MIN(LEN_TRIM(pzaxname),20)
1052  iret = NF90_DEF_DIM (nfid,pzaxname(1:leng),pzsize,zaxid_tmp)
1053  iret = NF90_DEF_VAR (nfid,pzaxname(1:leng),NF90_FLOAT, &
1054 &                     zaxid_tmp,zdimid)
1055  iret = NF90_PUT_ATT (nfid,zdimid,'axis',"Z")
1056  iret = NF90_PUT_ATT (nfid,zdimid,'standard_name',"model_level_number")
1057  leng = MIN(LEN_TRIM(pzaxunit),20)
1058  IF (leng > 0) THEN
1059    iret = NF90_PUT_ATT (nfid,zdimid,'units',pzaxunit(1:leng))
1060  ENDIF
1061  iret = NF90_PUT_ATT (nfid,zdimid,'positive',TRIM(direction))
1062  iret = NF90_PUT_ATT (nfid,zdimid,'valid_min', &
1063 &                     REAL(MINVAL(pzvalues(1:pzsize)),KIND=4))
1064  iret = NF90_PUT_ATT (nfid,zdimid,'valid_max', &
1065 &                     REAL(MAXVAL(pzvalues(1:pzsize)),KIND=4))
1066  leng = MIN(LEN_TRIM(pzaxname),20)
1067  iret = NF90_PUT_ATT (nfid,zdimid,'title',pzaxname(1:leng))
1068  leng = MIN(LEN_TRIM(pzaxtitle),80)
1069  iret = NF90_PUT_ATT (nfid,zdimid,'long_name',pzaxtitle(1:leng))
1070!-
1071  iret = NF90_ENDDEF (nfid)
1072!-
1073  iret = NF90_PUT_VAR (nfid,zdimid,pzvalues(1:pzsize))
1074!-
1075  iret = NF90_REDEF (nfid)
1076!-
1077!- 3.0 add the information to the common
1078!-
1079  IF (l_dbg) &
1080  &  WRITE(*,*) "histvert : 3.0 add the information to the common"
1081!-
1082  W_F(idf)%n_zax = iv
1083  W_F(idf)%zax_size(iv) = pzsize
1084  W_F(idf)%zax_name(iv) = pzaxname
1085  W_F(idf)%zax_ids(iv) = zaxid_tmp
1086  pzaxid = iv
1087!----------------------
1088END SUBROUTINE histvert
1089!===
1090SUBROUTINE histdef &
1091 &  (idf,pvarname,ptitle,punit, &
1092 &   pxsize,pysize,phoriid,pzsize,par_oriz,par_szz,pzid, &
1093 &   xtype,popp,pfreq_opp,pfreq_wrt,var_range,standard_name)
1094!---------------------------------------------------------------------
1095!- With this subroutine each variable to be archived on the history
1096!- tape should be declared.
1097!-
1098!- It gives the user the choise of operation
1099!- to be performed on the variables, the frequency of this operation
1100!- and finaly the frequency of the archiving.
1101!-
1102!- INPUT
1103!-
1104!- idf      : ID of the file the variable should be archived in
1105!- pvarname : Name of the variable, short and easy to remember
1106!- ptitle   : Full name of the variable
1107!- punit    : Units of the variable (no units if blank string)
1108!-
1109!- The next 3 arguments give the size of that data
1110!- that will be passed to histwrite. The zoom will be
1111!- done there with the horizontal information obtained
1112!- in histbeg and the vertical information to follow.
1113!-
1114!- pxsize   : Size in X direction (size of the data that will be
1115!-            given to histwrite)
1116!- pysize   : Size in Y direction
1117!- phoriid  : ID of the horizontal axis
1118!-
1119!- The next two arguments give the vertical zoom to use.
1120!-
1121!- pzsize   : Size in Z direction (If 1 then no axis is declared
1122!-            for this variable and pzid is not used)
1123!- par_oriz : Off set of the zoom
1124!- par_szz  : Size of the zoom
1125!-
1126!- pzid     : ID of the vertical axis to use. It has to have
1127!-            the size of the zoom.
1128!- xtype    : External netCDF type (hist_r4/hist_r8)
1129!- popp     : Operation to be performed. The following options
1130!-            exist today :
1131!- inst : keeps instantaneous values for writting
1132!- ave  : Computes the average from call between writes
1133!- pfreq_opp: Frequency of this operation (in seconds)
1134!- pfreq_wrt: Frequency at which the variable should be
1135!-            written (in seconds)
1136!- var_range: Range of the variable.
1137!-            If the minimum is greater than the maximum,
1138!-            the values will be calculated.
1139!-
1140!- VERSION
1141!---------------------------------------------------------------------
1142  IMPLICIT NONE
1143!-
1144  INTEGER,INTENT(IN) :: idf,pxsize,pysize,pzsize,pzid
1145  INTEGER,INTENT(IN) :: par_oriz,par_szz,xtype,phoriid
1146  CHARACTER(LEN=*),INTENT(IN) :: pvarname,punit,popp,ptitle
1147  REAL,INTENT(IN) :: pfreq_opp,pfreq_wrt
1148  REAL,DIMENSION(2),OPTIONAL,INTENT(IN) :: var_range
1149  CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: standard_name
1150!-
1151  INTEGER :: iv
1152  CHARACTER(LEN=70) :: str70,str71,str72
1153  CHARACTER(LEN=20) :: tmp_name
1154  CHARACTER(LEN=40) :: str40
1155  CHARACTER(LEN=10) :: str10
1156  CHARACTER(LEN=120) :: ex_topps
1157  REAL :: un_an,un_jour,test_fopp,test_fwrt
1158  INTEGER :: pos,buff_sz
1159  LOGICAL :: l_dbg
1160!---------------------------------------------------------------------
1161  CALL ipsldbg (old_status=l_dbg)
1162!-
1163  ex_topps = 'ave, inst, t_min, t_max, t_sum, once, never, l_max, l_min'
1164!-
1165  W_F(idf)%n_var = W_F(idf)%n_var+1
1166  iv = W_F(idf)%n_var
1167!-
1168  IF (iv > nb_var_max) THEN
1169    CALL ipslerr (3,"histdef", &
1170   &  'Table of variables too small. You should increase nb_var_max',&
1171   &  'in histcom.f90 in order to accomodate all these variables', &
1172   &  ' ')
1173  ENDIF
1174!-
1175! 1.0 Transfer informations on the variable to the common
1176!     and verify that it does not already exist
1177!-
1178  IF (l_dbg) WRITE(*,*) "histdef : 1.0"
1179!-
1180  IF (iv > 1) THEN
1181    CALL find_str (W_F(idf)%W_V(1:iv-1)%v_name,pvarname,pos)
1182  ELSE
1183    pos = 0
1184  ENDIF
1185!-
1186  IF (pos > 0) THEN
1187    str70 = "Variable already exists"
1188    WRITE(str71,'("Check variable  ",a," in file",I3)') &
1189 &    TRIM(pvarname),idf
1190    str72 = "Can also be a wrong file ID in another declaration"
1191    CALL ipslerr (3,"histdef",str70,str71,str72)
1192  ENDIF
1193!-
1194  W_F(idf)%W_V(iv)%v_name = pvarname
1195  W_F(idf)%W_V(iv)%title = ptitle
1196  W_F(idf)%W_V(iv)%unit_name = punit
1197  IF (PRESENT(standard_name)) THEN
1198    W_F(idf)%W_V(iv)%std_name = standard_name
1199  ELSE
1200    W_F(idf)%W_V(iv)%std_name = ptitle
1201  ENDIF
1202  tmp_name = W_F(idf)%W_V(iv)%v_name
1203!-
1204! 1.1 decode the operations
1205!-
1206  W_F(idf)%W_V(iv)%fullop = popp
1207  CALL buildop &
1208 &  (TRIM(popp),ex_topps,W_F(idf)%W_V(iv)%topp,missing_val, &
1209 &   W_F(idf)%W_V(iv)%sopp,W_F(idf)%W_V(iv)%scal, &
1210 &   W_F(idf)%W_V(iv)%nbopp)
1211!-
1212! 1.2 If we have an even number of operations
1213!     then we need to add identity
1214!-
1215  IF ( MOD(W_F(idf)%W_V(iv)%nbopp,2) == 0) THEN
1216    W_F(idf)%W_V(iv)%nbopp = W_F(idf)%W_V(iv)%nbopp+1
1217    W_F(idf)%W_V(iv)%sopp(W_F(idf)%W_V(iv)%nbopp) = 'ident'
1218    W_F(idf)%W_V(iv)%scal(W_F(idf)%W_V(iv)%nbopp) = missing_val
1219  ENDIF
1220!-
1221! 1.3 External type of the variable
1222!-
1223  IF (xtype == hist_r8) THEN
1224    W_F(idf)%W_V(iv)%v_typ = hist_r8
1225  ELSE
1226    W_F(idf)%W_V(iv)%v_typ = hist_r4
1227  ENDIF
1228!-
1229! 2.0 Put the size of the variable in the common and check
1230!-
1231  IF (l_dbg) THEN
1232    WRITE(*,*) "histdef : 2.0",idf,iv,W_F(idf)%W_V(iv)%nbopp, &
1233 &    W_F(idf)%W_V(iv)%sopp(1:W_F(idf)%W_V(iv)%nbopp), &
1234 &    W_F(idf)%W_V(iv)%scal(1:W_F(idf)%W_V(iv)%nbopp)
1235  ENDIF
1236!-
1237  W_F(idf)%W_V(iv)%scsize(1:3) = (/ pxsize,pysize,pzsize /)
1238  W_F(idf)%W_V(iv)%zorig(1:3) = &
1239 &  (/ W_F(idf)%slab_ori(1),W_F(idf)%slab_ori(2),par_oriz /)
1240  W_F(idf)%W_V(iv)%zsize(1:3) = &
1241 &  (/ W_F(idf)%slab_sz(1),W_F(idf)%slab_sz(2),par_szz /)
1242!-
1243! Is the size of the full array the same as that of the coordinates ?
1244!-
1245  IF (    (pxsize > W_F(idf)%full_size(1)) &
1246 &    .OR.(pysize > W_F(idf)%full_size(2)) ) THEN
1247!-
1248    str70 = "The size of the variable is different "// &
1249 &          "from the one of the coordinates"
1250    WRITE(str71,'("Size of coordinates :",2I4)') &
1251 &   W_F(idf)%full_size(1),W_F(idf)%full_size(2)
1252    WRITE(str72,'("Size declared for variable ",a," :",2I4)') &
1253 &   TRIM(tmp_name),pxsize,pysize
1254    CALL ipslerr (3,"histdef",str70,str71,str72)
1255  ENDIF
1256!-
1257! Is the size of the zoom smaller than the coordinates ?
1258!-
1259  IF (    (W_F(idf)%full_size(1) < W_F(idf)%slab_sz(1)) &
1260 &    .OR.(W_F(idf)%full_size(2) < W_F(idf)%slab_sz(2)) ) THEN
1261    str70 = &
1262 &   "Size of variable should be greater or equal to those of the zoom"
1263    WRITE(str71,'("Size of XY zoom :",2I4)') &
1264 &   W_F(idf)%slab_sz(1),W_F(idf)%slab_sz(2)
1265    WRITE(str72,'("Size declared for variable ",A," :",2I4)') &
1266 &   TRIM(tmp_name),pxsize,pysize
1267    CALL ipslerr (3,"histdef",str70,str71,str72)
1268  ENDIF
1269!-
1270! 2.1 We store the horizontal grid information with minimal
1271!     and a fall back onto the default grid
1272!-
1273  IF ( (phoriid > 0).AND.(phoriid <= W_F(idf)%n_hax) ) THEN
1274    W_F(idf)%W_V(iv)%h_axid = phoriid
1275  ELSE
1276    W_F(idf)%W_V(iv)%h_axid = 1
1277    CALL ipslerr (2,"histdef", &
1278   &  'We use the default grid for variable as an invalide',&
1279   &  'ID was provided for variable : ',TRIM(pvarname))
1280  ENDIF
1281!-
1282! 2.2 Check the vertical coordinates if needed
1283!-
1284  IF (par_szz > 1) THEN
1285!-
1286!-- Does the vertical coordinate exist ?
1287!-
1288    IF (pzid > W_F(idf)%n_zax) THEN
1289      WRITE(str70, &
1290 &    '("The vertical coordinate chosen for variable ",a)') &
1291 &     TRIM(tmp_name)
1292      str71 = " Does not exist."
1293      CALL ipslerr (3,"histdef",str70,str71," ")
1294    ENDIF
1295!-
1296!-- Is the vertical size of the variable equal to that of the axis ?
1297!-
1298    IF (par_szz /= W_F(idf)%zax_size(pzid)) THEN
1299      str70 = "The size of the zoom does not correspond "// &
1300 &            "to the size of the chosen vertical axis"
1301      WRITE(str71,'("Size of zoom in z :",I4)') par_szz
1302      WRITE(str72,'("Size declared for axis ",A," :",I4)') &
1303 &     TRIM(W_F(idf)%zax_name(pzid)),W_F(idf)%zax_size(pzid)
1304      CALL ipslerr (3,"histdef",str70,str71,str72)
1305    ENDIF
1306!-
1307!-- Is the zoom smaller that the total size of the variable ?
1308!-
1309    IF (pzsize < par_szz) THEN
1310      str70 = "The vertical size of variable "// &
1311 &            "is smaller than that of the zoom."
1312      WRITE(str71,'("Declared vertical size of data :",I5)') pzsize
1313      WRITE(str72,'("Size of zoom for variable ",a," = ",I5)') &
1314 &     TRIM(tmp_name),par_szz
1315      CALL ipslerr (3,"histdef",str70,str71,str72)
1316    ENDIF
1317    W_F(idf)%W_V(iv)%z_axid = pzid
1318  ELSE
1319    W_F(idf)%W_V(iv)%z_axid = -99
1320  ENDIF
1321!-
1322! 3.0 We get the size of the arrays histwrite will get
1323!     and eventually allocate the time_buffer
1324!-
1325  IF (l_dbg) THEN
1326    WRITE(*,*) "histdef : 3.0"
1327  ENDIF
1328!-
1329  buff_sz = W_F(idf)%W_V(iv)%zsize(1) &
1330 &         *W_F(idf)%W_V(iv)%zsize(2) &
1331 &         *W_F(idf)%W_V(iv)%zsize(3)
1332!-
1333  IF (     (TRIM(W_F(idf)%W_V(iv)%topp) /= "inst") &
1334 &    .AND.(TRIM(W_F(idf)%W_V(iv)%topp) /= "once") &
1335 &    .AND.(TRIM(W_F(idf)%W_V(iv)%topp) /= "never") )THEN
1336    ALLOCATE(W_F(idf)%W_V(iv)%t_bf(buff_sz))
1337    W_F(idf)%W_V(iv)%t_bf(:) = 0.
1338    IF (l_dbg) THEN
1339      WRITE(*,*) "histdef : 3.0 allocating time_buffer for", &
1340 &      " idf = ",idf," iv = ",iv," size = ",buff_sz
1341    ENDIF
1342  ENDIF
1343!-
1344! 4.0 Transfer the frequency of the operations and check
1345!     for validity. We have to pay attention to negative values
1346!     of the frequency which indicate monthly time-steps.
1347!     The strategy is to bring it back to seconds for the tests
1348!-
1349  IF (l_dbg) WRITE(*,*) "histdef : 4.0"
1350!-
1351  W_F(idf)%W_V(iv)%freq_opp = pfreq_opp
1352  W_F(idf)%W_V(iv)%freq_wrt = pfreq_wrt
1353!-
1354  CALL ioget_calendar(un_an,un_jour)
1355  IF (pfreq_opp < 0) THEN
1356    CALL ioget_calendar(un_an)
1357    test_fopp = pfreq_opp*(-1.)*un_an/12.*un_jour
1358  ELSE
1359    test_fopp = pfreq_opp
1360  ENDIF
1361  IF (pfreq_wrt < 0) THEN
1362    CALL ioget_calendar(un_an)
1363    test_fwrt = pfreq_wrt*(-1.)*un_an/12.*un_jour
1364  ELSE
1365    test_fwrt = pfreq_wrt
1366  ENDIF
1367!-
1368! 4.1 Frequency of operations and output should be larger than deltat !
1369!-
1370  IF (test_fopp < W_F(idf)%deltat) THEN
1371    str70 = 'Frequency of operations should be larger than deltat'
1372    WRITE(str71,'("It is not the case for variable ",a," :",F10.4)') &
1373 &   TRIM(tmp_name),pfreq_opp
1374    str72 = "PATCH : frequency set to deltat"
1375!-
1376    CALL ipslerr (2,"histdef",str70,str71,str72)
1377!-
1378    W_F(idf)%W_V(iv)%freq_opp = W_F(idf)%deltat
1379  ENDIF
1380!-
1381  IF (test_fwrt < W_F(idf)%deltat) THEN
1382    str70 = 'Frequency of output should be larger than deltat'
1383    WRITE(str71,'("It is not the case for variable ",a," :",F10.4)') &
1384 &   TRIM(tmp_name),pfreq_wrt
1385    str72 = "PATCH : frequency set to deltat"
1386!-
1387    CALL ipslerr (2,"histdef",str70,str71,str72)
1388!-
1389    W_F(idf)%W_V(iv)%freq_wrt = W_F(idf)%deltat
1390  ENDIF
1391!-
1392! 4.2 First the existence of the operation is tested and then
1393!     its compaticility with the choice of frequencies
1394!-
1395  IF (TRIM(W_F(idf)%W_V(iv)%topp) == "inst") THEN
1396    IF (test_fopp /= test_fwrt) THEN
1397      str70 = 'For instantaneous output the frequency '// &
1398 &            'of operations and output'
1399      WRITE(str71, &
1400 &     '("should be the same, this was not case for variable ",a)') &
1401 &      TRIM(tmp_name)
1402      str72 = "PATCH : The smalest frequency of both is used"
1403      CALL ipslerr (2,"histdef",str70,str71,str72)
1404      IF (test_fopp < test_fwrt) THEN
1405        W_F(idf)%W_V(iv)%freq_opp = pfreq_opp
1406        W_F(idf)%W_V(iv)%freq_wrt = pfreq_opp
1407      ELSE
1408        W_F(idf)%W_V(iv)%freq_opp = pfreq_wrt
1409        W_F(idf)%W_V(iv)%freq_wrt = pfreq_wrt
1410      ENDIF
1411    ENDIF
1412  ELSE IF (INDEX(ex_topps,TRIM(W_F(idf)%W_V(iv)%topp)) > 0) THEN
1413    IF (test_fopp > test_fwrt) THEN
1414      str70 = 'For averages the frequency of operations '// &
1415 &            'should be smaller or equal'
1416      WRITE(str71, &
1417 &     '("to that of output. It is not the case for variable ",a)') &
1418 &     TRIM(tmp_name)
1419      str72 = 'PATCH : The output frequency is used for both'
1420      CALL ipslerr (2,"histdef",str70,str71,str72)
1421      W_F(idf)%W_V(iv)%freq_opp = pfreq_wrt
1422    ENDIF
1423  ELSE
1424    WRITE (str70,'("Operation on variable ",A," is unknown")') &
1425 &   TRIM(tmp_name)
1426    WRITE (str71,'("operation requested is :",A)') &
1427 &   W_F(idf)%W_V(iv)%topp
1428    WRITE (str72,'("File ID :",I3)') idf
1429    CALL ipslerr (3,"histdef",str70,str71,str72)
1430  ENDIF
1431!-
1432! 5.0 Initialize other variables of the common
1433!-
1434  IF (l_dbg) WRITE(*,*) "histdef : 5.0"
1435!-
1436  W_F(idf)%W_V(iv)%hist_wrt_rng = (PRESENT(var_range))
1437  IF (W_F(idf)%W_V(iv)%hist_wrt_rng) THEN
1438    W_F(idf)%W_V(iv)%hist_calc_rng = (var_range(1) > var_range(2))
1439    IF (W_F(idf)%W_V(iv)%hist_calc_rng) THEN
1440      W_F(idf)%W_V(iv)%hist_minmax(1:2) = &
1441 &      (/ ABS(missing_val),-ABS(missing_val) /)
1442    ELSE
1443      W_F(idf)%W_V(iv)%hist_minmax(1:2) = var_range(1:2)
1444    ENDIF
1445  ENDIF
1446!-
1447! - freq_opp(idf,iv)/2./deltat(idf)
1448  W_F(idf)%W_V(iv)%last_opp = W_F(idf)%itau0
1449! - freq_wrt(idf,iv)/2./deltat(idf)
1450  W_F(idf)%W_V(iv)%last_wrt = W_F(idf)%itau0
1451! - freq_opp(idf,iv)/2./deltat(idf)
1452  W_F(idf)%W_V(iv)%last_opp_chk = W_F(idf)%itau0
1453! - freq_wrt(idf,iv)/2./deltat(idf)
1454  W_F(idf)%W_V(iv)%last_wrt_chk = W_F(idf)%itau0
1455  W_F(idf)%W_V(iv)%nb_opp = 0
1456  W_F(idf)%W_V(iv)%nb_wrt = 0
1457!-
1458! 6.0 Get the time axis for this variable
1459!-
1460  IF (l_dbg) WRITE(*,*) "histdef : 6.0"
1461!-
1462  IF (W_F(idf)%W_V(iv)%freq_wrt > 0) THEN
1463    WRITE(str10,'(I8.8)') INT(W_F(idf)%W_V(iv)%freq_wrt)
1464    str40 = TRIM(W_F(idf)%W_V(iv)%topp)//"_"//TRIM(str10)
1465  ELSE
1466    WRITE(str10,'(I2.2,"month")') ABS(INT(W_F(idf)%W_V(iv)%freq_wrt))
1467    str40 = TRIM(W_F(idf)%W_V(iv)%topp)//"_"//TRIM(str10)
1468  ENDIF
1469  CALL find_str (W_F(idf)%W_V(1:W_F(idf)%n_tax)%tax_name,str40,pos)
1470!-
1471! No time axis for once, l_max, l_min or never operation
1472!-
1473  IF (     (TRIM(W_F(idf)%W_V(iv)%topp) /= 'once')  &
1474 &    .AND.(TRIM(W_F(idf)%W_V(iv)%topp) /= 'never') &
1475 &    .AND.(TRIM(W_F(idf)%W_V(iv)%topp) /= 'l_max') &
1476 &    .AND.(TRIM(W_F(idf)%W_V(iv)%topp) /= 'l_min') ) THEN
1477    IF (pos < 0) THEN
1478      W_F(idf)%n_tax = W_F(idf)%n_tax+1
1479      W_F(idf)%W_V(W_F(idf)%n_tax)%tax_name = str40
1480      W_F(idf)%W_V(W_F(idf)%n_tax)%tax_last = 0
1481      W_F(idf)%W_V(iv)%t_axid = W_F(idf)%n_tax
1482    ELSE
1483      W_F(idf)%W_V(iv)%t_axid = pos
1484    ENDIF
1485  ELSE
1486    IF (l_dbg) THEN
1487      WRITE(*,*) "histdef : 7.0 ",TRIM(W_F(idf)%W_V(iv)%topp),'----'
1488    ENDIF
1489    W_F(idf)%W_V(iv)%t_axid = -99
1490  ENDIF
1491!-
1492! 7.0 prepare frequence of writing and operation
1493!     for never or once operation
1494!-
1495  IF (    (TRIM(W_F(idf)%W_V(iv)%topp) == 'once')  &
1496 &    .OR.(TRIM(W_F(idf)%W_V(iv)%topp) == 'never') ) THEN
1497    W_F(idf)%W_V(iv)%freq_opp = 0.
1498    W_F(idf)%W_V(iv)%freq_wrt = 0.
1499  ENDIF
1500!---------------------
1501END SUBROUTINE histdef
1502!===
1503SUBROUTINE histend (idf)
1504!---------------------------------------------------------------------
1505!- This subroutine end the decalaration of variables and sets the
1506!- time axes in the netcdf file and puts it into the write mode.
1507!-
1508!- INPUT
1509!-
1510!- idf : ID of the file to be worked on
1511!-
1512!- VERSION
1513!-
1514!---------------------------------------------------------------------
1515  IMPLICIT NONE
1516!-
1517  INTEGER,INTENT(IN) :: idf
1518!-
1519  INTEGER :: nfid,nvid,iret,ndim,iv,itx,ziv,itax,dim_cnt
1520  INTEGER,DIMENSION(4) :: dims
1521  INTEGER :: year,month,day,hours,minutes
1522  REAL :: sec
1523  REAL :: rtime0
1524  CHARACTER(LEN=30) :: str30
1525  CHARACTER(LEN=120) :: assoc
1526  CHARACTER(LEN=70) :: str70
1527  CHARACTER(LEN=3),DIMENSION(12) :: cal =   &
1528 &  (/ 'JAN','FEB','MAR','APR','MAY','JUN', &
1529 &     'JUL','AUG','SEP','OCT','NOV','DEC' /)
1530  CHARACTER(LEN=7) :: tmp_opp
1531  LOGICAL :: l_dbg
1532!---------------------------------------------------------------------
1533  CALL ipsldbg (old_status=l_dbg)
1534!-
1535  nfid = W_F(idf)%ncfid
1536!-
1537! 1.0 Create the time axes
1538!-
1539  IF (l_dbg) WRITE(*,*) "histend : 1.0"
1540!---
1541  iret = NF90_DEF_DIM (nfid,'time_counter', &
1542 &                     NF90_UNLIMITED,W_F(idf)%tid)
1543!-
1544! 1.1 Define all the time axes needed for this file
1545!-
1546  DO itx=1,W_F(idf)%n_tax
1547    dims(1) = W_F(idf)%tid
1548    IF (W_F(idf)%n_tax > 1) THEN
1549      str30 = "t_"//W_F(idf)%W_V(itx)%tax_name
1550    ELSE
1551      str30 = "time_counter"
1552    ENDIF
1553    iret = NF90_DEF_VAR (nfid,str30,NF90_DOUBLE, &
1554 &           dims(1),W_F(idf)%W_V(itx)%tdimid)
1555    IF (W_F(idf)%n_tax <= 1) THEN
1556      iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid,'axis',"T")
1557    ENDIF
1558    iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid, &
1559 &           'standard_name',"time")
1560!---
1561!   To transform the current itau into a real date and take it
1562!   as the origin of the file requires the time counter to change.
1563!   Thus it is an operation the user has to ask for.
1564!   This function should thus only be re-instated
1565!   if there is a ioconf routine to control it.
1566!---
1567!-- rtime0 = itau2date(itau0(idf),date0(idf),deltat(idf))
1568    rtime0 = W_F(idf)%date0
1569!-
1570    CALL ju2ymds(rtime0,year,month,day,sec)
1571!---
1572!   Catch any error induced by a change in calendar !
1573!---
1574    IF (year < 0) THEN
1575      year = 2000+year
1576    ENDIF
1577!-
1578    hours = INT(sec/(60.*60.))
1579    minutes = INT((sec-hours*60.*60.)/60.)
1580    sec = sec-(hours*60.*60.+minutes*60.)
1581!-
1582    WRITE (UNIT=str70, &
1583 &   FMT='(A,I4.4,"-",I2.2,"-",I2.2," ",I2.2,":",I2.2,":",I2.2)') &
1584 &    'seconds since ',year,month,day,hours,minutes,INT(sec)
1585    iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid, &
1586 &           'units',TRIM(str70))
1587!-
1588    CALL ioget_calendar (str30)
1589    iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid, &
1590 &           'calendar',TRIM(str30))
1591!-
1592    iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid, &
1593 &           'title','Time')
1594!-
1595    iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid, &
1596 &           'long_name','Time axis')
1597!-
1598    WRITE (UNIT=str70, &
1599 &   FMT='(" ",I4.4,"-",A3,"-",I2.2," ",I2.2,":",I2.2,":",I2.2)') &
1600 &    year,cal(month),day,hours,minutes,INT(sec)
1601    iret = NF90_PUT_ATT (nfid,W_F(idf)%W_V(itx)%tdimid, &
1602 &           'time_origin',TRIM(str70))
1603  ENDDO
1604!-
1605! 2.0 declare the variables
1606!-
1607  IF (l_dbg) WRITE(*,*) "histend : 2.0"
1608!-
1609  DO iv=1,W_F(idf)%n_var
1610!---
1611    itax = W_F(idf)%W_V(iv)%t_axid
1612!---
1613    IF (W_F(idf)%regular) THEN
1614      dims(1:2) = (/ W_F(idf)%xid,W_F(idf)%yid /)
1615      dim_cnt = 2
1616    ELSE
1617      dims(1) = W_F(idf)%xid
1618      dim_cnt = 1
1619    ENDIF
1620!---
1621    tmp_opp = W_F(idf)%W_V(iv)%topp
1622    ziv = W_F(idf)%W_V(iv)%z_axid
1623!---
1624!   2.1 dimension of field
1625!---
1626    IF ((TRIM(tmp_opp) /= 'never')) THEN
1627      IF (     (TRIM(tmp_opp) /= 'once')  &
1628     &    .AND.(TRIM(tmp_opp) /= 'l_max') &
1629     &    .AND.(TRIM(tmp_opp) /= 'l_min') ) THEN
1630        IF (ziv == -99) THEN
1631          ndim = dim_cnt+1
1632          dims(dim_cnt+1:dim_cnt+2) = (/ W_F(idf)%tid,0 /)
1633        ELSE
1634          ndim = dim_cnt+2
1635          dims(dim_cnt+1:dim_cnt+2) = &
1636 &         (/ W_F(idf)%zax_ids(ziv),W_F(idf)%tid /)
1637        ENDIF
1638      ELSE
1639        IF (ziv == -99) THEN
1640          ndim = dim_cnt
1641          dims(dim_cnt+1:dim_cnt+2) = (/ 0,0 /)
1642        ELSE
1643          ndim = dim_cnt+1
1644          dims(dim_cnt+1:dim_cnt+2) = (/ W_F(idf)%zax_ids(ziv),0 /)
1645        ENDIF
1646      ENDIF
1647!-
1648      iret = NF90_DEF_VAR (nfid,TRIM(W_F(idf)%W_V(iv)%v_name), &
1649 &             W_F(idf)%W_V(iv)%v_typ,dims(1:ABS(ndim)),nvid)
1650!-
1651      W_F(idf)%W_V(iv)%ncvid = nvid
1652!-
1653      IF (LEN_TRIM(W_F(idf)%W_V(iv)%unit_name) > 0) THEN
1654        iret = NF90_PUT_ATT (nfid,nvid,'units', &
1655 &                           TRIM(W_F(idf)%W_V(iv)%unit_name))
1656      ENDIF
1657      iret = NF90_PUT_ATT (nfid,nvid,'standard_name', &
1658 &                         TRIM(W_F(idf)%W_V(iv)%std_name))
1659!-
1660      IF (W_F(idf)%W_V(iv)%v_typ == hist_r8) THEN
1661        iret = NF90_PUT_ATT (nfid,nvid,'_FillValue',NF90_FILL_REAL8)
1662      ELSE
1663        iret = NF90_PUT_ATT (nfid,nvid,'_FillValue',NF90_FILL_REAL4)
1664      ENDIF
1665      IF (W_F(idf)%W_V(iv)%hist_wrt_rng) THEN
1666        iret = NF90_PUT_ATT (nfid,nvid,'valid_min', &
1667 &               REAL(W_F(idf)%W_V(iv)%hist_minmax(1),KIND=4))
1668        iret = NF90_PUT_ATT (nfid,nvid,'valid_max', &
1669 &               REAL(W_F(idf)%W_V(iv)%hist_minmax(2),KIND=4))
1670      ENDIF
1671      iret = NF90_PUT_ATT (nfid,nvid,'long_name', &
1672 &                         TRIM(W_F(idf)%W_V(iv)%title))
1673      iret = NF90_PUT_ATT (nfid,nvid,'online_operation', &
1674 &                         TRIM(W_F(idf)%W_V(iv)%fullop))
1675!-
1676      SELECT CASE(ndim)
1677      CASE(-3,2:4)
1678      CASE DEFAULT
1679        CALL ipslerr (3,"histend", &
1680       &  'less than 2 or more than 4 dimensions are not', &
1681       &  'allowed at this stage',' ')
1682      END SELECT
1683!-
1684      assoc=TRIM(W_F(idf)%hax_name(W_F(idf)%W_V(iv)%h_axid,2)) &
1685 &   //' '//TRIM(W_F(idf)%hax_name(W_F(idf)%W_V(iv)%h_axid,1))
1686!-
1687      ziv = W_F(idf)%W_V(iv)%z_axid
1688      IF (ziv > 0) THEN
1689        str30 = W_F(idf)%zax_name(ziv)
1690        assoc = TRIM(str30)//' '//TRIM(assoc)
1691      ENDIF
1692!-
1693      IF (itax > 0) THEN
1694        IF (W_F(idf)%n_tax > 1) THEN
1695          str30 = "t_"//W_F(idf)%W_V(itax)%tax_name
1696        ELSE
1697          str30 = "time_counter"
1698        ENDIF
1699        assoc = TRIM(str30)//' '//TRIM(assoc)
1700!-
1701        IF (l_dbg) THEN
1702          WRITE(*,*) "histend : 2.0.n, freq_opp, freq_wrt", &
1703 &          W_F(idf)%W_V(iv)%freq_opp,W_F(idf)%W_V(iv)%freq_wrt
1704        ENDIF
1705!-
1706        iret = NF90_PUT_ATT (nfid,nvid,'interval_operation', &
1707 &                           REAL(W_F(idf)%W_V(iv)%freq_opp,KIND=4))
1708        iret = NF90_PUT_ATT (nfid,nvid,'interval_write', &
1709 &                           REAL(W_F(idf)%W_V(iv)%freq_wrt,KIND=4))
1710      ENDIF
1711      iret = NF90_PUT_ATT (nfid,nvid,'coordinates',TRIM(assoc))
1712    ENDIF
1713  ENDDO
1714!-
1715! 2.2 Add DOMAIN attributes if needed
1716!-
1717  IF (W_F(idf)%dom_id_svg >= 0) THEN
1718    CALL flio_dom_att (nfid,W_F(idf)%dom_id_svg)
1719  ENDIF
1720!-
1721! 3.0 Put the netcdf file into write mode
1722!-
1723  IF (l_dbg) WRITE(*,*) "histend : 3.0"
1724!-
1725  iret = NF90_ENDDEF (nfid)
1726!-
1727! 4.0 Give some informations to the user
1728!-
1729  IF (l_dbg) WRITE(*,*) "histend : 4.0"
1730!-
1731  WRITE(str70,'("All variables have been initialized on file :",I3)') idf
1732  CALL ipslerr (1,'histend',str70,'',' ')
1733!---------------------
1734END SUBROUTINE histend
1735!===
1736SUBROUTINE histwrite_r1d (idf,pvarname,pitau,pdata,nbindex,nindex)
1737!---------------------------------------------------------------------
1738  IMPLICIT NONE
1739!-
1740  INTEGER,INTENT(IN) :: idf,pitau,nbindex
1741  INTEGER,DIMENSION(nbindex),INTENT(IN) :: nindex
1742  REAL,DIMENSION(:),INTENT(IN) :: pdata
1743  CHARACTER(LEN=*),INTENT(IN) :: pvarname
1744!---------------------------------------------------------------------
1745  CALL histw_rnd (idf,pvarname,pitau,nbindex,nindex,pdata_1d=pdata)
1746!---------------------------
1747END SUBROUTINE histwrite_r1d
1748!===
1749SUBROUTINE histwrite_r2d (idf,pvarname,pitau,pdata,nbindex,nindex)
1750!---------------------------------------------------------------------
1751  IMPLICIT NONE
1752!-
1753  INTEGER,INTENT(IN) :: idf,pitau,nbindex
1754  INTEGER,DIMENSION(nbindex),INTENT(IN) :: nindex
1755  REAL,DIMENSION(:,:),INTENT(IN) :: pdata
1756  CHARACTER(LEN=*),INTENT(IN) :: pvarname
1757!---------------------------------------------------------------------
1758  CALL histw_rnd (idf,pvarname,pitau,nbindex,nindex,pdata_2d=pdata)
1759!---------------------------
1760END SUBROUTINE histwrite_r2d
1761!===
1762SUBROUTINE histwrite_r3d (idf,pvarname,pitau,pdata,nbindex,nindex)
1763!---------------------------------------------------------------------
1764  IMPLICIT NONE
1765!-
1766  INTEGER,INTENT(IN) :: idf,pitau,nbindex
1767  INTEGER,DIMENSION(nbindex),INTENT(IN) :: nindex
1768  REAL,DIMENSION(:,:,:),INTENT(IN) :: pdata
1769  CHARACTER(LEN=*),INTENT(IN) :: pvarname
1770!---------------------------------------------------------------------
1771  CALL histw_rnd (idf,pvarname,pitau,nbindex,nindex,pdata_3d=pdata)
1772!---------------------------
1773END SUBROUTINE histwrite_r3d
1774!===
1775SUBROUTINE histw_rnd (idf,pvarname,pitau,nbindex,nindex, &
1776  &                   pdata_1d,pdata_2d,pdata_3d)
1777!---------------------------------------------------------------------
1778  IMPLICIT NONE
1779!-
1780  INTEGER,INTENT(IN) :: idf,pitau,nbindex
1781  INTEGER,DIMENSION(nbindex),INTENT(IN) :: nindex
1782  CHARACTER(LEN=*),INTENT(IN) :: pvarname
1783  REAL,DIMENSION(:),INTENT(IN),OPTIONAL     :: pdata_1d
1784  REAL,DIMENSION(:,:),INTENT(IN),OPTIONAL   :: pdata_2d
1785  REAL,DIMENSION(:,:,:),INTENT(IN),OPTIONAL :: pdata_3d
1786!-
1787  LOGICAL :: do_oper,do_write,largebuf,l1d,l2d,l3d
1788  INTEGER :: iv,io,nbpt_out
1789  INTEGER              :: nbpt_in1
1790  INTEGER,DIMENSION(2) :: nbpt_in2
1791  INTEGER,DIMENSION(3) :: nbpt_in3
1792  REAL,ALLOCATABLE,DIMENSION(:),SAVE :: tbf_1
1793  CHARACTER(LEN=7) :: tmp_opp
1794  CHARACTER(LEN=13) :: c_nam
1795  LOGICAL :: l_dbg
1796!---------------------------------------------------------------------
1797  CALL ipsldbg (old_status=l_dbg)
1798!-
1799  l1d=PRESENT(pdata_1d); l2d=PRESENT(pdata_2d); l3d=PRESENT(pdata_3d);
1800  IF      (l1d) THEN
1801    c_nam = 'histwrite_r1d'
1802  ELSE IF (l2d) THEN
1803    c_nam = 'histwrite_r2d'
1804  ELSE IF (l3d) THEN
1805    c_nam = 'histwrite_r3d'
1806  ENDIF
1807!-
1808! 1.0 Try to catch errors like specifying the wrong file ID.
1809!     Thanks Marine for showing us what errors users can make !
1810!-
1811  IF ( (idf < 1).OR.(idf > nb_files) ) THEN
1812    CALL ipslerr (3,"histwrite", &
1813 &    'Illegal file ID in the histwrite of variable',pvarname,' ')
1814  ENDIF
1815!-
1816! 1.1 Find the id of the variable to be written and the real time
1817!-
1818  CALL histvar_seq (idf,pvarname,iv)
1819!-
1820! 2.0 do nothing for never operation
1821!-
1822  tmp_opp = W_F(idf)%W_V(iv)%topp
1823!-
1824  IF (TRIM(tmp_opp) == "never") THEN
1825    W_F(idf)%W_V(iv)%last_opp_chk = -99
1826    W_F(idf)%W_V(iv)%last_wrt_chk = -99
1827  ENDIF
1828!-
1829! 3.0 We check if we need to do an operation
1830!-
1831  IF (W_F(idf)%W_V(iv)%last_opp_chk == pitau) THEN
1832    CALL ipslerr (3,"histwrite", &
1833 &    'This variable has already been analysed at the present', &
1834 &    'time step',TRIM(pvarname))
1835  ENDIF
1836!-
1837  CALL isittime &
1838 &  (pitau,W_F(idf)%date0,W_F(idf)%deltat, &
1839 &   W_F(idf)%W_V(iv)%freq_opp, &
1840 &   W_F(idf)%W_V(iv)%last_opp, &
1841 &   W_F(idf)%W_V(iv)%last_opp_chk,do_oper)
1842!-
1843! 4.0 We check if we need to write the data
1844!-
1845  IF (W_F(idf)%W_V(iv)%last_wrt_chk == pitau) THEN
1846    CALL ipslerr (3,"histwrite", &
1847 &    'This variable as already been written for the present', &
1848 &    'time step',' ')
1849  ENDIF
1850!-
1851  CALL isittime &
1852 &  (pitau,W_F(idf)%date0,W_F(idf)%deltat, &
1853 &   W_F(idf)%W_V(iv)%freq_wrt, &
1854 &   W_F(idf)%W_V(iv)%last_wrt, &
1855 &   W_F(idf)%W_V(iv)%last_wrt_chk,do_write)
1856!-
1857! 5.0 histwrite called
1858!-
1859  IF (do_oper.OR.do_write) THEN
1860!-
1861!-- 5.1 Get the sizes of the data we will handle
1862!-
1863    IF (W_F(idf)%W_V(iv)%datasz_in(1) <= 0) THEN
1864!---- There is the risk here that the user has over-sized the array.
1865!---- But how can we catch this ?
1866!---- In the worst case we will do impossible operations
1867!---- on part of the data !
1868      W_F(idf)%W_V(iv)%datasz_in(1:3) = -1
1869      IF      (l1d) THEN
1870        W_F(idf)%W_V(iv)%datasz_in(1) = SIZE(pdata_1d)
1871      ELSE IF (l2d) THEN
1872        W_F(idf)%W_V(iv)%datasz_in(1) = SIZE(pdata_2d,DIM=1)
1873        W_F(idf)%W_V(iv)%datasz_in(2) = SIZE(pdata_2d,DIM=2)
1874      ELSE IF (l3d) THEN
1875        W_F(idf)%W_V(iv)%datasz_in(1) = SIZE(pdata_3d,DIM=1)
1876        W_F(idf)%W_V(iv)%datasz_in(2) = SIZE(pdata_3d,DIM=2)
1877        W_F(idf)%W_V(iv)%datasz_in(3) = SIZE(pdata_3d,DIM=3)
1878      ENDIF
1879    ENDIF
1880!-
1881!-- 5.2 The maximum size of the data will give the size of the buffer
1882!-
1883    IF (W_F(idf)%W_V(iv)%datasz_max <= 0) THEN
1884      largebuf = .FALSE.
1885      DO io=1,W_F(idf)%W_V(iv)%nbopp
1886        IF (INDEX(fuchnbout,W_F(idf)%W_V(iv)%sopp(io)) > 0) THEN
1887          largebuf = .TRUE.
1888        ENDIF
1889      ENDDO
1890      IF (largebuf) THEN
1891        W_F(idf)%W_V(iv)%datasz_max = &
1892 &        W_F(idf)%W_V(iv)%scsize(1) &
1893 &       *W_F(idf)%W_V(iv)%scsize(2) &
1894 &       *W_F(idf)%W_V(iv)%scsize(3)
1895      ELSE
1896        IF      (l1d) THEN
1897          W_F(idf)%W_V(iv)%datasz_max = &
1898 &          W_F(idf)%W_V(iv)%datasz_in(1)
1899        ELSE IF (l2d) THEN
1900          W_F(idf)%W_V(iv)%datasz_max = &
1901 &          W_F(idf)%W_V(iv)%datasz_in(1) &
1902 &         *W_F(idf)%W_V(iv)%datasz_in(2)
1903        ELSE IF (l3d) THEN
1904          W_F(idf)%W_V(iv)%datasz_max = &
1905 &          W_F(idf)%W_V(iv)%datasz_in(1) &
1906 &         *W_F(idf)%W_V(iv)%datasz_in(2) &
1907 &         *W_F(idf)%W_V(iv)%datasz_in(3)
1908        ENDIF
1909      ENDIF
1910    ENDIF
1911!-
1912    IF (.NOT.ALLOCATED(tbf_1)) THEN
1913      IF (l_dbg) THEN
1914        WRITE(*,*) &
1915 &       c_nam//" : allocate tbf_1 for size = ", &
1916 &       W_F(idf)%W_V(iv)%datasz_max
1917      ENDIF
1918      ALLOCATE(tbf_1(W_F(idf)%W_V(iv)%datasz_max))
1919    ELSE IF (W_F(idf)%W_V(iv)%datasz_max > SIZE(tbf_1)) THEN
1920      IF (l_dbg) THEN
1921        WRITE(*,*) &
1922 &       c_nam//" : re-allocate tbf_1 for size = ", &
1923 &       W_F(idf)%W_V(iv)%datasz_max
1924      ENDIF
1925      DEALLOCATE(tbf_1)
1926      ALLOCATE(tbf_1(W_F(idf)%W_V(iv)%datasz_max))
1927    ENDIF
1928!-
1929!-- We have to do the first operation anyway.
1930!-- Thus we do it here and change the ranke
1931!-- of the data at the same time. This should speed up things.
1932!-
1933    nbpt_out = W_F(idf)%W_V(iv)%datasz_max
1934    IF      (l1d) THEN
1935      nbpt_in1 = W_F(idf)%W_V(iv)%datasz_in(1)
1936      CALL mathop (W_F(idf)%W_V(iv)%sopp(1),nbpt_in1,pdata_1d, &
1937 &                 missing_val,nbindex,nindex, &
1938 &                 W_F(idf)%W_V(iv)%scal(1),nbpt_out,tbf_1)
1939    ELSE IF (l2d) THEN
1940      nbpt_in2(1:2) = W_F(idf)%W_V(iv)%datasz_in(1:2)
1941      CALL mathop (W_F(idf)%W_V(iv)%sopp(1),nbpt_in2,pdata_2d, &
1942 &                 missing_val,nbindex,nindex, &
1943 &                 W_F(idf)%W_V(iv)%scal(1),nbpt_out,tbf_1)
1944    ELSE IF (l3d) THEN
1945      nbpt_in3(1:3) = W_F(idf)%W_V(iv)%datasz_in(1:3)
1946      CALL mathop (W_F(idf)%W_V(iv)%sopp(1),nbpt_in3,pdata_3d, &
1947 &                 missing_val,nbindex,nindex, &
1948 &                 W_F(idf)%W_V(iv)%scal(1),nbpt_out,tbf_1)
1949    ENDIF
1950    CALL histwrite_real (idf,iv,pitau,nbpt_out, &
1951 &            tbf_1,nbindex,nindex,do_oper,do_write)
1952  ENDIF
1953!-
1954! 6.0 Manage time steps
1955!-
1956  IF ((TRIM(tmp_opp) /= "once").AND.(TRIM(tmp_opp) /= "never")) THEN
1957    W_F(idf)%W_V(iv)%last_opp_chk = pitau
1958    W_F(idf)%W_V(iv)%last_wrt_chk = pitau
1959  ELSE
1960    W_F(idf)%W_V(iv)%last_opp_chk = -99
1961    W_F(idf)%W_V(iv)%last_wrt_chk = -99
1962  ENDIF
1963!-----------------------
1964END SUBROUTINE histw_rnd
1965!===
1966SUBROUTINE histwrite_real &
1967 & (idf,iv,pitau,nbdpt,tbf_1,nbindex,nindex,do_oper,do_write)
1968!---------------------------------------------------------------------
1969!- This subroutine is internal and does the calculations and writing
1970!- if needed. At a later stage it should be split into an operation
1971!- and writing subroutines.
1972!---------------------------------------------------------------------
1973  IMPLICIT NONE
1974!-
1975  INTEGER,INTENT(IN) :: idf,pitau,iv, &
1976 &                      nbindex,nindex(nbindex),nbdpt
1977  REAL,DIMENSION(:)  :: tbf_1
1978  LOGICAL,INTENT(IN) :: do_oper,do_write
1979!-
1980  INTEGER :: tsz,nfid,nvid,iret,itax,io,nbin,nbout
1981  INTEGER :: nx,ny,nz,ky,kz,kt,kc
1982  INTEGER,DIMENSION(4) :: corner,edges
1983  INTEGER :: itime
1984!-
1985  REAL :: rtime
1986  CHARACTER(LEN=7) :: tmp_opp
1987  REAL,ALLOCATABLE,DIMENSION(:),SAVE :: tbf_2
1988  LOGICAL :: l_dbg
1989!---------------------------------------------------------------------
1990  CALL ipsldbg (old_status=l_dbg)
1991!-
1992  IF (l_dbg) THEN
1993    WRITE(*,*) "histwrite 0.0 : VAR : ",W_F(idf)%W_V(iv)%v_name
1994    WRITE(*,*) "histwrite 0.0 : nbindex :",nbindex
1995    WRITE(*,*) "histwrite 0.0 : nindex  :",nindex(1:MIN(3,nbindex)),'...'
1996  ENDIF
1997!-
1998! The sizes which can be encoutered
1999!-
2000  tsz =  W_F(idf)%W_V(iv)%zsize(1) &
2001 &      *W_F(idf)%W_V(iv)%zsize(2) &
2002 &      *W_F(idf)%W_V(iv)%zsize(3)
2003!-
2004! 1.0 We allocate and the temporary space needed for operations.
2005!     The buffers are only deallocated when more space is needed.
2006!     This reduces the umber of allocates but increases memory needs.
2007!-
2008  IF (.NOT.ALLOCATED(tbf_2)) THEN
2009    IF (l_dbg) THEN
2010      WRITE(*,*) "histwrite_real 1.1 allocate tbf_2 ",SIZE(tbf_1)
2011    ENDIF
2012    ALLOCATE(tbf_2(W_F(idf)%W_V(iv)%datasz_max))
2013  ELSE IF (W_F(idf)%W_V(iv)%datasz_max > SIZE(tbf_2)) THEN
2014    IF (l_dbg) THEN
2015      WRITE(*,*) "histwrite_real 1.2 re-allocate tbf_2 : ", &
2016     & SIZE(tbf_1)," instead of ",SIZE(tbf_2)
2017    ENDIF
2018    DEALLOCATE(tbf_2)
2019    ALLOCATE(tbf_2(W_F(idf)%W_V(iv)%datasz_max))
2020  ENDIF
2021!-
2022  rtime = pitau*W_F(idf)%deltat
2023  tmp_opp = W_F(idf)%W_V(iv)%topp
2024!-
2025! 3.0 Do the operations or transfer the slab of data into tbf_1
2026!-
2027  IF (l_dbg) THEN
2028    WRITE(*,*) "histwrite: 3.0",idf
2029  ENDIF
2030!-
2031! 3.1 DO the Operations only if needed
2032!-
2033  IF (do_oper) THEN
2034    nbout = nbdpt
2035!-
2036!-- 3.4 We continue the sequence of operations
2037!--     we started in the interface routine
2038!-
2039    DO io=2,W_F(idf)%W_V(iv)%nbopp,2
2040      nbin = nbout
2041      nbout = W_F(idf)%W_V(iv)%datasz_max
2042      CALL mathop(W_F(idf)%W_V(iv)%sopp(io),nbin,tbf_1, &
2043 &      missing_val,nbindex,nindex,W_F(idf)%W_V(iv)%scal(io), &
2044 &      nbout,tbf_2)
2045      IF (l_dbg) THEN
2046        WRITE(*,*) &
2047 &       "histwrite: 3.4a nbout : ",nbin,nbout,W_F(idf)%W_V(iv)%sopp(io)
2048      ENDIF
2049!-
2050      nbin = nbout
2051      nbout = W_F(idf)%W_V(iv)%datasz_max
2052      CALL mathop(W_F(idf)%W_V(iv)%sopp(io+1),nbin,tbf_2, &
2053 &      missing_val,nbindex,nindex,W_F(idf)%W_V(iv)%scal(io+1), &
2054 &      nbout,tbf_1)
2055      IF (l_dbg) THEN
2056        WRITE(*,*) &
2057 &     "histwrite: 3.4b nbout : ",nbin,nbout,W_F(idf)%W_V(iv)%sopp(io+1)
2058      ENDIF
2059    ENDDO
2060!-
2061!   3.5 Zoom into the data
2062!-
2063    IF (l_dbg) THEN
2064      WRITE(*,*) &
2065 &     "histwrite: 3.5 size(tbf_1) : ",SIZE(tbf_1)
2066      WRITE(*,*) &
2067 &     "histwrite: 3.5 slab in X :", &
2068 &     W_F(idf)%W_V(iv)%zorig(1),W_F(idf)%W_V(iv)%zsize(1)
2069      WRITE(*,*) &
2070 &     "histwrite: 3.5 slab in Y :", &
2071 &     W_F(idf)%W_V(iv)%zorig(2),W_F(idf)%W_V(iv)%zsize(2)
2072      WRITE(*,*) &
2073 &     "histwrite: 3.5 slab in Z :", &
2074 &     W_F(idf)%W_V(iv)%zorig(3),W_F(idf)%W_V(iv)%zsize(3)
2075      WRITE(*,*) &
2076 &     "histwrite: 3.5 slab of input:", &
2077 &     W_F(idf)%W_V(iv)%scsize(1), &
2078 &     W_F(idf)%W_V(iv)%scsize(2), &
2079 &     W_F(idf)%W_V(iv)%scsize(3)
2080    ENDIF
2081!---
2082!-- We have to consider blocks of contiguous data
2083!---
2084    nx=MAX(W_F(idf)%W_V(iv)%zsize(1),1)
2085    ny=MAX(W_F(idf)%W_V(iv)%zsize(2),1)
2086    nz=MAX(W_F(idf)%W_V(iv)%zsize(3),1)
2087    IF     (     (W_F(idf)%W_V(iv)%zorig(1) == 1) &
2088 &          .AND.(   W_F(idf)%W_V(iv)%zsize(1) &
2089 &                == W_F(idf)%W_V(iv)%scsize(1)) &
2090 &          .AND.(W_F(idf)%W_V(iv)%zorig(2) == 1) &
2091 &          .AND.(   W_F(idf)%W_V(iv)%zsize(2) &
2092 &                == W_F(idf)%W_V(iv)%scsize(2))) THEN
2093      kt = (W_F(idf)%W_V(iv)%zorig(3)-1)*nx*ny
2094      tbf_2(1:nx*ny*nz) = tbf_1(kt+1:kt+nx*ny*nz)
2095    ELSEIF (     (W_F(idf)%W_V(iv)%zorig(1) == 1) &
2096 &          .AND.(   W_F(idf)%W_V(iv)%zsize(1) &
2097 &                == W_F(idf)%W_V(iv)%scsize(1))) THEN
2098      kc = -nx*ny
2099      DO kz=W_F(idf)%W_V(iv)%zorig(3),W_F(idf)%W_V(iv)%zorig(3)+nz-1
2100        kc = kc+nx*ny
2101        kt = ( (kz-1)*W_F(idf)%W_V(iv)%scsize(2) &
2102 &            +W_F(idf)%W_V(iv)%zorig(2)-1)*nx
2103        tbf_2(kc+1:kc+nx*ny) = tbf_1(kt+1:kt+nx*ny)
2104      ENDDO
2105    ELSE
2106      kc = -nx
2107      DO kz=W_F(idf)%W_V(iv)%zorig(3),W_F(idf)%W_V(iv)%zorig(3)+nz-1
2108        DO ky=W_F(idf)%W_V(iv)%zorig(2),W_F(idf)%W_V(iv)%zorig(2)+ny-1
2109          kc = kc+nx
2110          kt = ((kz-1)*W_F(idf)%W_V(iv)%scsize(2)+ky-1) &
2111 &            *W_F(idf)%W_V(iv)%scsize(1) &
2112 &            +W_F(idf)%W_V(iv)%zorig(1)-1
2113          tbf_2(kc+1:kc+nx) = tbf_1(kt+1:kt+nx)
2114        ENDDO
2115      ENDDO
2116    ENDIF
2117!-
2118!-- 4.0 Get the min and max of the field
2119!-
2120    IF (l_dbg) THEN
2121      WRITE(*,*) "histwrite: 4.0 tbf_1",idf,iv, &
2122 &      TRIM(tmp_opp),' ---- ',LEN_TRIM(tmp_opp),nbindex
2123    ENDIF
2124!-
2125    IF (W_F(idf)%W_V(iv)%hist_calc_rng) THEN
2126      W_F(idf)%W_V(iv)%hist_minmax(1) = &
2127 &      MIN(W_F(idf)%W_V(iv)%hist_minmax(1), &
2128 &      MINVAL(tbf_2(1:tsz),MASK=tbf_2(1:tsz) /= missing_val))
2129      W_F(idf)%W_V(iv)%hist_minmax(2) = &
2130 &      MAX(W_F(idf)%W_V(iv)%hist_minmax(2), &
2131 &      MAXVAL(tbf_2(1:tsz),MASK=tbf_2(1:tsz) /= missing_val))
2132    ENDIF
2133!-
2134!-- 5.0 Do the operations if needed. In the case of instantaneous
2135!--     output we do not transfer to the time_buffer.
2136!-
2137    IF (l_dbg) THEN
2138      WRITE(*,*) "histwrite: 5.0 idf : ",idf," iv : ",iv," tsz : ",tsz
2139    ENDIF
2140!-
2141    IF (     (TRIM(tmp_opp) /= "inst") &
2142 &      .AND.(TRIM(tmp_opp) /= "once") ) THEN
2143      CALL moycum(tmp_opp,tsz,W_F(idf)%W_V(iv)%t_bf, &
2144 &           tbf_2,W_F(idf)%W_V(iv)%nb_opp)
2145    ENDIF
2146!-
2147    W_F(idf)%W_V(iv)%last_opp = pitau
2148    W_F(idf)%W_V(iv)%nb_opp = W_F(idf)%W_V(iv)%nb_opp+1
2149!-
2150  ENDIF
2151!-
2152! 6.0 Write to file if needed
2153!-
2154  IF (l_dbg) WRITE(*,*) "histwrite: 6.0",idf
2155!-
2156  IF (do_write) THEN
2157!-
2158    nfid = W_F(idf)%ncfid
2159    nvid = W_F(idf)%W_V(iv)%ncvid
2160!-
2161!-- 6.1 Do the operations that are needed before writting
2162!-
2163    IF (l_dbg) WRITE(*,*) "histwrite: 6.1",idf
2164!-
2165    IF (     (TRIM(tmp_opp) /= "inst") &
2166 &      .AND.(TRIM(tmp_opp) /= "once") ) THEN
2167      rtime = (rtime+W_F(idf)%W_V(iv)%last_wrt*W_F(idf)%deltat)/2.0
2168    ENDIF
2169!-
2170!-- 6.2 Add a value to the time axis of this variable if needed
2171!-
2172    IF (     (TRIM(tmp_opp) /= "l_max") &
2173 &      .AND.(TRIM(tmp_opp) /= "l_min") &
2174 &      .AND.(TRIM(tmp_opp) /= "once") ) THEN
2175!-
2176      IF (l_dbg) WRITE(*,*) "histwrite: 6.2",idf
2177!-
2178      itax  = W_F(idf)%W_V(iv)%t_axid
2179      itime = W_F(idf)%W_V(iv)%nb_wrt+1
2180!-
2181      IF (W_F(idf)%W_V(itax)%tax_last < itime) THEN
2182        iret = NF90_PUT_VAR (nfid,W_F(idf)%W_V(itax)%tdimid, &
2183 &               (/ rtime /),start=(/ itime /),count=(/ 1 /))
2184        W_F(idf)%W_V(itax)%tax_last = itime
2185      ENDIF
2186    ELSE
2187      itime=1
2188    ENDIF
2189!-
2190!-- 6.3 Write the data. Only in the case of instantaneous output
2191!       we do not write the buffer.
2192!-
2193    IF (l_dbg) THEN
2194      WRITE(*,*) "histwrite: 6.3",idf,nfid,nvid,iv,itime
2195    ENDIF
2196!-
2197    IF (W_F(idf)%W_V(iv)%scsize(3) == 1) THEN
2198      IF (W_F(idf)%regular) THEN
2199        corner(1:4) = (/ 1,1,itime,0 /)
2200        edges(1:4) = (/ W_F(idf)%W_V(iv)%zsize(1), &
2201 &                      W_F(idf)%W_V(iv)%zsize(2),1,0 /)
2202      ELSE
2203        corner(1:4) = (/ 1,itime,0,0 /)
2204        edges(1:4) = (/ W_F(idf)%W_V(iv)%zsize(1),1,0,0 /)
2205      ENDIF
2206    ELSE
2207      IF (W_F(idf)%regular) THEN
2208        corner(1:4) = (/ 1,1,1,itime /)
2209        edges(1:4) = (/ W_F(idf)%W_V(iv)%zsize(1), &
2210 &                      W_F(idf)%W_V(iv)%zsize(2), &
2211 &                      W_F(idf)%W_V(iv)%zsize(3),1 /)
2212      ELSE
2213        corner(1:4) = (/ 1,1,itime,0 /)
2214        edges(1:4) = (/ W_F(idf)%W_V(iv)%zsize(1), &
2215 &                      W_F(idf)%W_V(iv)%zsize(3),1,0 /)
2216      ENDIF
2217    ENDIF
2218!-
2219    IF (     (TRIM(tmp_opp) /= "inst") &
2220 &      .AND.(TRIM(tmp_opp) /= "once") ) THEN
2221      iret = NF90_PUT_VAR (nfid,nvid,W_F(idf)%W_V(iv)%t_bf, &
2222 &                         start=corner(1:4),count=edges(1:4))
2223    ELSE
2224      iret = NF90_PUT_VAR (nfid,nvid,tbf_2, &
2225 &                         start=corner(1:4),count=edges(1:4))
2226    ENDIF
2227!-
2228    W_F(idf)%W_V(iv)%last_wrt = pitau
2229    W_F(idf)%W_V(iv)%nb_wrt = W_F(idf)%W_V(iv)%nb_wrt+1
2230    W_F(idf)%W_V(iv)%nb_opp = 0
2231!---
2232!   After the write the file can be synchronized so that no data is
2233!   lost in case of a crash. This feature gives up on the benefits of
2234!   buffering and should only be used in debuging mode. A flag is
2235!   needed here to switch to this mode.
2236!---
2237!   iret = NF90_SYNC (nfid)
2238!-
2239  ENDIF
2240!----------------------------
2241END SUBROUTINE histwrite_real
2242!===
2243SUBROUTINE histvar_seq (idf,pvarname,idv)
2244!---------------------------------------------------------------------
2245!- This subroutine optimize the search for the variable in the table.
2246!- In a first phase it will learn the succession of the variables
2247!- called and then it will use the table to guess what comes next.
2248!- It is the best solution to avoid lengthy searches through array
2249!- vectors.
2250!-
2251!- ARGUMENTS :
2252!-
2253!- idf      : id of the file on which we work
2254!- pvarname : The name of the variable we are looking for
2255!- idv      : The var id we found
2256!---------------------------------------------------------------------
2257  IMPLICIT NONE
2258!-
2259  INTEGER,INTENT(in)  :: idf
2260  CHARACTER(LEN=*),INTENT(IN) :: pvarname
2261  INTEGER,INTENT(out) :: idv
2262!-
2263  LOGICAL,SAVE :: learning(nb_files_max)=.TRUE.
2264  INTEGER,SAVE :: overlap(nb_files_max) = -1
2265  INTEGER,SAVE :: varseq(nb_files_max,nb_var_max*3)
2266  INTEGER,SAVE :: varseq_len(nb_files_max) = 0
2267  INTEGER,SAVE :: varseq_pos(nb_files_max)
2268  INTEGER,SAVE :: varseq_err(nb_files_max) = 0
2269  INTEGER      :: ib,sp,nn,pos
2270  CHARACTER(LEN=70) :: str70
2271  LOGICAL :: l_dbg
2272!---------------------------------------------------------------------
2273  CALL ipsldbg (old_status=l_dbg)
2274!-
2275  IF (l_dbg) THEN
2276    WRITE(*,*) 'histvar_seq, start of the subroutine :',learning(idf)
2277  ENDIF
2278!-
2279  IF (learning(idf)) THEN
2280!-
2281!-- 1.0 We compute the length over which we are going
2282!--     to check the overlap
2283!-
2284    IF (overlap(idf) <= 0) THEN
2285      IF (W_F(idf)%n_var > 6) THEN
2286        overlap(idf) = W_F(idf)%n_var/3*2
2287      ELSE
2288        overlap(idf) = W_F(idf)%n_var
2289      ENDIF
2290    ENDIF
2291!-
2292!-- 1.1 Find the position of this string
2293!-
2294    CALL find_str (W_F(idf)%W_V(1:W_F(idf)%n_var)%v_name,pvarname,pos)
2295    IF (pos > 0) THEN
2296      idv = pos
2297    ELSE
2298      CALL ipslerr (3,"histvar_seq", &
2299 &      'The name of the variable you gave has not been declared', &
2300 &      'You should use subroutine histdef for declaring variable', &
2301 &      TRIM(pvarname))
2302    ENDIF
2303!-
2304!-- 1.2 If we have not given up we store the position
2305!--     in the sequence of calls
2306!-
2307    IF (varseq_err(idf) >= 0) THEN
2308      sp = varseq_len(idf)+1
2309      IF (sp <= nb_var_max*3) THEN
2310        varseq(idf,sp) = idv
2311        varseq_len(idf) = sp
2312      ELSE
2313        CALL ipslerr (2,"histvar_seq",&
2314 &       'The learning process has failed and we give up. '// &
2315 &       'Either you sequence is',&
2316 &       'too complex or I am too dumb. '// &
2317 &       'This will only affect the efficiency',&
2318 &       'of your code. Thus if you wish to save time'// &
2319 &       ' contact the IOIPSL team. ')
2320        WRITE(*,*) 'The sequence we have found up to now :'
2321        WRITE(*,*) varseq(idf,1:sp-1)
2322        varseq_err(idf) = -1
2323      ENDIF
2324!-
2325!---- 1.3 Check if we have found the right overlap
2326!-
2327      IF (varseq_len(idf) >= overlap(idf)*2) THEN
2328!-
2329!------ We skip a few variables if needed as they could come
2330!------ from the initialisation of the model.
2331!-
2332        DO ib = 0,sp-overlap(idf)*2
2333          IF ( learning(idf) .AND.&
2334            & SUM(ABS(varseq(idf,ib+1:ib+overlap(idf)) -&
2335            & varseq(idf,sp-overlap(idf)+1:sp))) == 0 ) THEN
2336            learning(idf) = .FALSE.
2337            varseq_len(idf) = sp-overlap(idf)-ib
2338            varseq_pos(idf) = overlap(idf)+ib
2339            varseq(idf,1:varseq_len(idf)) = &
2340 &            varseq(idf,ib+1:ib+varseq_len(idf))
2341          ENDIF
2342        ENDDO
2343      ENDIF
2344    ENDIF
2345  ELSE
2346!-
2347!-- 2.0 Now we know how the calls to histwrite are sequenced
2348!--     and we can get a guess at the var ID
2349!-
2350    nn = varseq_pos(idf)+1
2351    IF (nn > varseq_len(idf)) nn = 1
2352!-
2353    idv = varseq(idf,nn)
2354!-
2355    IF (TRIM(W_F(idf)%W_V(idv)%v_name) /= TRIM(pvarname)) THEN
2356      CALL find_str (W_F(idf)%W_V(1:W_F(idf)%n_var)%v_name,pvarname,pos)
2357      IF (pos > 0) THEN
2358        idv = pos
2359      ELSE
2360        CALL ipslerr (3,"histvar_seq", &
2361 &  'The name of the variable you gave has not been declared',&
2362 &  'You should use subroutine histdef for declaring variable', &
2363 &  TRIM(pvarname))
2364      ENDIF
2365      varseq_err(idf) = varseq_err(idf)+1
2366    ELSE
2367!-
2368!---- We only keep the new position if we have found the variable
2369!---- this way. This way an out of sequence call to histwrite does
2370!---- not defeat the process.
2371!-
2372      varseq_pos(idf) = nn
2373    ENDIF
2374!-
2375    IF (varseq_err(idf) >= 10) THEN
2376      WRITE(str70,'("for file ",I3)') idf
2377      CALL ipslerr (2,"histvar_seq", &
2378 &  'There were 10 errors in the learned sequence of variables',&
2379 &  str70,'This looks like a bug, please report it.')
2380         varseq_err(idf) = 0
2381    ENDIF
2382  ENDIF
2383!-
2384  IF (l_dbg) THEN
2385    WRITE(*,*) &
2386 &   'histvar_seq, end of the subroutine :',TRIM(pvarname),idv
2387  ENDIF
2388!-------------------------
2389END SUBROUTINE histvar_seq
2390!===
2391SUBROUTINE histsync (file)
2392!---------------------------------------------------------------------
2393!- This subroutine will synchronise all
2394!- (or one if defined) opened files.
2395!-
2396!- VERSION
2397!-
2398!---------------------------------------------------------------------
2399  IMPLICIT NONE
2400!-
2401! file  : optional argument for fileid
2402  INTEGER,INTENT(in),OPTIONAL :: file
2403!-
2404  INTEGER :: ifile,nfid,iret
2405!-
2406  LOGICAL :: file_exists
2407  LOGICAL :: l_dbg
2408!---------------------------------------------------------------------
2409  CALL ipsldbg (old_status=l_dbg)
2410!-
2411  IF (l_dbg) WRITE(*,*) 'Entering loop on files : ',nb_files
2412!-
2413! 1.The loop on files to synchronise
2414!-
2415  DO ifile=1,nb_files
2416!-
2417    IF (PRESENT(file)) THEN
2418      file_exists = (ifile == file)
2419    ELSE
2420      file_exists = .TRUE.
2421    ENDIF
2422!-
2423    IF (file_exists) THEN
2424      IF (l_dbg) THEN
2425        WRITE(*,*) 'Synchronising specified file number :',file
2426      ENDIF
2427      nfid = W_F(ifile)%ncfid
2428      iret = NF90_SYNC (nfid)
2429    ENDIF
2430!-
2431  ENDDO
2432!----------------------
2433END SUBROUTINE histsync
2434!===
2435SUBROUTINE histclo (idf)
2436!---------------------------------------------------------------------
2437!- This subroutine will close all (or one if defined) opened files
2438!-
2439!- VERSION
2440!-
2441!---------------------------------------------------------------------
2442  IMPLICIT NONE
2443!-
2444! idf  : optional argument for fileid
2445  INTEGER,INTENT(in),OPTIONAL :: idf
2446!-
2447  INTEGER :: ifile,nfid,nvid,iret,iv
2448  INTEGER :: start_loop,end_loop
2449  CHARACTER(LEN=70) :: str70
2450  LOGICAL :: l_dbg
2451!---------------------------------------------------------------------
2452  CALL ipsldbg (old_status=l_dbg)
2453!-
2454  IF (l_dbg) WRITE(*,*) 'Entering loop on files :',nb_files
2455!-
2456  IF (PRESENT(idf)) THEN
2457    start_loop = idf
2458    end_loop = idf
2459  ELSE
2460    start_loop = 1
2461    end_loop = nb_files
2462  ENDIF
2463!-
2464  DO ifile=start_loop,end_loop
2465    IF (l_dbg) WRITE(*,*) 'Closing specified file number :',ifile
2466    nfid = W_F(ifile)%ncfid
2467    iret = NF90_REDEF (nfid)
2468!---
2469!-- 1. Loop on the number of variables to add some final information
2470!---
2471    IF (l_dbg) WRITE(*,*) 'Entering loop on vars : ',W_F(ifile)%n_var
2472    DO iv=1,W_F(ifile)%n_var
2473!---- Extrema
2474      IF (W_F(ifile)%W_V(iv)%hist_wrt_rng) THEN
2475        IF (l_dbg) THEN
2476          WRITE(*,*) 'min value for file :',ifile,' var n. :',iv, &
2477         &           ' is : ',W_F(ifile)%W_V(iv)%hist_minmax(1)
2478          WRITE(*,*) 'max value for file :',ifile,' var n. :',iv, &
2479         &           ' is : ',W_F(ifile)%W_V(iv)%hist_minmax(2)
2480        ENDIF
2481        IF (W_F(ifile)%W_V(iv)%hist_calc_rng) THEN
2482!-------- Put the min and max values on the file
2483          nvid = W_F(ifile)%W_V(iv)%ncvid
2484          iret = NF90_PUT_ATT (nfid,nvid,'valid_min', &
2485 &                 REAL(W_F(ifile)%W_V(iv)%hist_minmax(1),KIND=4))
2486          iret = NF90_PUT_ATT (nfid,nvid,'valid_max', &
2487 &                 REAL(W_F(ifile)%W_V(iv)%hist_minmax(2),KIND=4))
2488        ENDIF
2489      ENDIF
2490!---- Time-Buffers
2491      IF (ALLOCATED(W_F(ifile)%W_V(iv)%t_bf)) THEN
2492        DEALLOCATE(W_F(ifile)%W_V(iv)%t_bf)
2493      ENDIF
2494    ENDDO
2495!---
2496!-- 2. Close the file
2497!---
2498    IF (l_dbg) WRITE(*,*) 'close file :',nfid
2499    iret = NF90_CLOSE (nfid)
2500    IF (iret /= NF90_NOERR) THEN
2501      WRITE(str70,'("This file has been already closed :",I3)') ifile
2502      CALL ipslerr (2,'histclo',str70,'','')
2503    ENDIF
2504  ENDDO
2505!---------------------
2506END SUBROUTINE histclo
2507!===
2508SUBROUTINE ioconf_modname (str)
2509!---------------------------------------------------------------------
2510!- This subroutine allows to configure the name
2511!- of the model written into the file
2512!---------------------------------------------------------------------
2513  IMPLICIT NONE
2514!-
2515  CHARACTER(LEN=*),INTENT(IN) :: str
2516!---------------------------------------------------------------------
2517  IF (.NOT.lock_modname) THEN
2518    model_name = str(1:MIN(LEN_TRIM(str),80))
2519    lock_modname = .TRUE.
2520  ELSE
2521    CALL ipslerr (2,"ioconf_modname", &
2522   &  'The model name can only be changed once and only', &
2523   &  'before it is used. It is now set to :',model_name)
2524  ENDIF
2525!----------------------------
2526END SUBROUTINE ioconf_modname
2527!-
2528!===
2529!-
2530!-----------------
2531END MODULE histcom
Note: See TracBrowser for help on using the repository browser.