source: branches/publications/ORCHIDEE_gmd_mict_peat_ch4/r4229/src_sechiba/sechiba_io_p.f90 @ 7346

Last change on this file since 7346 was 6209, checked in by chunjing.qiu, 5 years ago

Added agricultural peatland + bugs fixed

File size: 19.0 KB
Line 
1!! This subroutines initialize a variable or an array
2!! with a variable or an array of smaller rank
3!! - i is for integer interface - r for real interface
4!! - 0 is for a scalar - 1 for a 1D array - 2 for a 2D array
5!! Thee right routines is automatically called depending type of input variable
6!! This initialisation is done only if the value of input field is egal to val_exp
7!!
8!! If a key word is provided which is not equal to "NO_KEYWORD" or "NOKEYWORD" then
9!! we try to find the value to fill in in the configuration file.
10!!
11!! @author Marie-Alice Foujols and Jan Polcher
12!! @Version : $Revision: 1540 $, $Date: 2013-10-15 18:16:19 +0200 (Tue, 15 Oct 2013) $
13!!
14!< $HeadURL: svn://forge.ipsl.jussieu.fr/orchidee/perso/shushi.peng/ORCHIDEE/src_sechiba/sechiba_io_p.f90 $
15!< $Date: 2013-10-15 18:16:19 +0200 (Tue, 15 Oct 2013) $
16!< $Author: josefine.ghattas $
17!< $Revision: 1540 $
18!! IPSL (2006)
19!!  This software is governed by the CeCILL licence see ORCHIDEE/ORCHIDEE_CeCILL.LIC
20!!
21MODULE sechiba_io_p
22
23  USE defprec
24  USE constantes
25  USE ioipsl
26  USE ioipsl_para
27  USE mod_orchidee_para
28
29  IMPLICIT NONE
30
31  INTERFACE setvar_p
32    MODULE PROCEDURE i0setvar_p, i10setvar_p, i20setvar_p, i11setvar_p, i21setvar_p, i22setvar_p
33    MODULE PROCEDURE r0setvar_p, r10setvar_p, r20setvar_p, r11setvar_p, r21setvar_p, r22setvar_p, r30setvar_p
34  END INTERFACE
35
36  LOGICAL, SAVE                  :: long_print_setvar_p=.FALSE.  !! change to true to have more information
37!$OMP THREADPRIVATE(long_print_setvar_p)
38
39CONTAINS 
40
41!! Interface for integer scalar to scalar.
42SUBROUTINE i0setvar_p (var, val_exp, key_wd, val_put)
43
44  INTEGER(i_std), INTENT(inout)                   :: var                  !! Integer scalar to modify
45  INTEGER(i_std), INTENT(in)                      :: val_exp              !! Exceptional value
46  CHARACTER(LEN=*), INTENT(in)                    :: key_wd               !! The Key word we will look for
47  INTEGER(i_std), INTENT(in)                      :: val_put              !! Initial value to stored
48
49  INTEGER(i_std)                                  :: val_tmp
50  INTEGER(i_std)                                  :: is_key
51
52  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
53 
54  IF (long_print_setvar_p) WRITE (numout,*) "i0setvar :", key_wd, val_exp, val_put
55
56  val_tmp = val_put
57
58  IF ( var == val_exp ) THEN
59     IF ( is_key <= 0 ) THEN
60        CALL getin_p(key_wd,  val_tmp)
61     ENDIF
62     var = val_tmp
63  END IF
64 
65END SUBROUTINE i0setvar_p
66
67
68!! Interface for initialising an 1D integer array with a scalar integer.
69SUBROUTINE i10setvar_p (var, val_exp, key_wd, val_put)
70
71  INTEGER(i_std), DIMENSION(:), INTENT(inout)     :: var                  !! 1D integer array to modify
72  INTEGER(i_std), INTENT(in)                      :: val_exp              !! Exceptional value
73  CHARACTER(LEN=*), INTENT(in)                :: key_wd               !! The Key word we will look for
74  INTEGER(i_std), INTENT(in)                      :: val_put              !! Scalar value to stored
75 
76  INTEGER(i_std)                                  :: val_tmp
77  INTEGER(i_std)                                  :: is_key
78
79  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
80
81  IF (long_print_setvar_p) WRITE (numout,*) "i10setvar :", key_wd, val_exp, val_put
82
83  val_tmp = val_put
84
85  IF ( ALL( var(:) == val_exp ) ) THEN
86     IF ( is_key <= 0 ) THEN
87       CALL getin_p(key_wd,  val_tmp)
88     ENDIF
89     var(:) = val_tmp
90  END IF
91 
92END SUBROUTINE i10setvar_p
93
94
95!! Interface for initialising an 1D array integer with an other 1D array integer.
96SUBROUTINE i11setvar_p (var, val_exp, key_wd, val_put, is_grid)
97 
98  INTEGER(i_std), DIMENSION(:), INTENT(inout)     :: var                 !! 1D integer array to modify
99  INTEGER(i_std), INTENT(in)                      :: val_exp             !! Exceptional value
100  CHARACTER(LEN=*), INTENT(in)                    :: key_wd              !! The Key word we will look for
101  INTEGER(i_std), DIMENSION(:), INTENT(in)        :: val_put             !! 1D integer array to stored
102  LOGICAL,        OPTIONAL                        :: is_grid             !! Parameter present indicates a setvar for a grid variable
103
104  INTEGER(i_std), ALLOCATABLE,DIMENSION(:)        :: val_tmp
105  INTEGER(i_std), ALLOCATABLE,DIMENSION(:)        :: val_tmp_g
106  INTEGER(i_std)                                  :: is_key
107
108  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
109 
110  IF (long_print_setvar_p) WRITE (numout,*) "i11setvar :", key_wd, val_exp, SIZE(val_put), val_put(1)
111
112  ALLOCATE(val_tmp(SIZE(val_put)))
113  val_tmp(:) = val_put(:)
114
115  IF ( ALL( var(:) == val_exp ) ) THEN
116     IF ( is_key <= 0 ) THEN
117        IF (PRESENT(is_grid) ) THEN
118           IF (is_root_prc) THEN
119              ALLOCATE( val_tmp_g(nbp_glo) )
120           ELSE
121              ALLOCATE( val_tmp_g(1) )
122           ENDIF
123           CALL gather( val_tmp,val_tmp_g )
124           IF (is_root_prc) &
125              CALL getin(key_wd,  val_tmp_g)
126           CALL scatter( val_tmp,val_tmp_g )
127           DEALLOCATE( val_tmp_g )
128        ELSE
129           CALL getin_p(key_wd,  val_tmp)
130        ENDIF
131     ENDIF
132     var(:) = val_tmp (:)
133  END IF
134
135  DEALLOCATE(val_tmp)
136 
137END SUBROUTINE i11setvar_p
138
139
140!! Interface for initialising an 2D array integer with a scalar integer.
141SUBROUTINE i20setvar_p (var, val_exp, key_wd, val_put)
142 
143  INTEGER(i_std), DIMENSION(:,:), INTENT(inout)   :: var                  !! 2D integer array to modify
144  INTEGER(i_std), INTENT(in)                      :: val_exp              !! Exceptional value
145  CHARACTER(LEN=*), INTENT(in)                    :: key_wd               !! The Key word we will look for
146  INTEGER(i_std), INTENT(in)                      :: val_put              !! Scalar value to be used as default
147
148  INTEGER(i_std)                                  :: val_tmp
149  INTEGER(i_std)                                  :: is_key
150
151  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
152 
153  IF (long_print_setvar_p) WRITE (numout,*) "i20setvar :", key_wd, val_exp, val_put
154
155  val_tmp = val_put
156
157  IF ( ALL( var(:,:) == val_exp ) ) THEN
158     IF ( is_key <= 0 ) THEN
159       CALL getin_p(key_wd,  val_tmp)
160     ENDIF
161     var(:,:) = val_tmp
162  END IF
163 
164END SUBROUTINE i20setvar_p
165
166
167!! Interface for initialising an 2D array integer with an 1D array integer.
168!! Row or column depending size of 1D array to stored.
169!!
170!! example: 1D 1,2,3     2D is 1, 2, 3,
171!!                             1, 2, 3
172!!
173!!
174!! example: 1D 1,2,3     2D is 1, 1,
175!!                             2, 2,
176!!                             3, 3
177!!
178SUBROUTINE i21setvar_p (var, val_exp, key_wd, val_put, is_grid)
179 
180  INTEGER(i_std), DIMENSION(:,:), INTENT(inout)   :: var                  !! 2D integer array to modify
181  INTEGER(i_std), INTENT(in)                      :: val_exp              !! Exceptional value
182  CHARACTER(LEN=*), INTENT(in)                    :: key_wd               !! The Key word we will look for
183  INTEGER(i_std), DIMENSION(:), INTENT(in)        :: val_put              !! 1D integer array to stored
184  LOGICAL,        OPTIONAL                        :: is_grid              !! Parameter present indicates a setvar for a grid variable
185 
186  INTEGER(i_std), ALLOCATABLE,DIMENSION(:)        :: val_tmp
187  INTEGER(i_std)                                  :: is_key
188
189  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
190
191  ! test if the 1D array dimension is compatible with first or second
192  ! dimension of the 2D array
193
194  IF (long_print_setvar_p) WRITE (numout,*) "i21setvar :", key_wd, val_exp, val_put
195
196  ALLOCATE(val_tmp(SIZE(val_put)))
197  val_tmp(:) = val_put(:)
198
199  IF (SIZE(val_put)==SIZE(var,1)) THEN 
200      !
201      ! example: 1D 1.,2.,3.     2D is 1., 2., 3.,
202      !                                1., 2., 3.
203      !
204      IF ( ALL( var(:,:) == val_exp ) ) THEN
205         IF ( is_key <= 0 ) THEN
206           CALL getin_p(key_wd,  val_tmp)
207         ENDIF
208         var(:,:) = SPREAD(val_tmp(:),2,SIZE(var,1))
209      END IF
210  ELSEIF (SIZE(val_put)==SIZE(var,2)) THEN 
211      !
212      ! example: 1D 1.,2.,3.     2D is 1., 1.,
213      !                                2., 2.,
214      !                                3., 3.
215      !
216      IF ( ALL( var(:,:) == val_exp ) ) THEN
217         IF ( is_key <= 0 ) THEN
218           CALL getin_p(key_wd,  val_tmp)
219         ENDIF
220         var(:,:) = SPREAD(val_tmp(:),1,SIZE(var,1))
221      END IF
222  ELSE
223      WRITE (numout,*) ' incompatible dimension var and val_put'
224      WRITE (numout,*) ' var     ', SIZE(var,1), SIZE(var,2)
225      WRITE (numout,*) ' val_put ', SIZE(val_put)
226      STOP 'setvar'
227  END IF
228
229  DEALLOCATE(val_tmp)
230 
231END SUBROUTINE i21setvar_p
232
233!! Interface for initialising an 2D array integer with an other 2D array integer.
234SUBROUTINE i22setvar_p (var, val_exp, key_wd, val_put, is_grid)
235 
236  INTEGER(i_std), DIMENSION(:,:), INTENT(inout)   :: var                 !! 2D integer array to modify
237  INTEGER(i_std), INTENT(in)                      :: val_exp             !! Exceptional value
238  CHARACTER(LEN=*), INTENT(in)                :: key_wd              !! The Key word we will look for
239  INTEGER(i_std), DIMENSION(:,:), INTENT(in)      :: val_put             !! 2D integer array to stored
240  LOGICAL,        OPTIONAL                        :: is_grid              !! Parameter present indicates a setvar for a grid variable
241
242  INTEGER(i_std), ALLOCATABLE, DIMENSION(:,:)     :: val_tmp
243  INTEGER(i_std)                                  :: is_key
244
245  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
246 
247  IF (long_print_setvar_p) WRITE (numout,*) "i21setvar :", key_wd, val_exp, SIZE(val_put), val_put(1,1)
248
249  ALLOCATE(val_tmp(SIZE(val_put,DIM=1),SIZE(val_put,DIM=2)))
250  val_tmp(:,:) = val_put(:,:)
251
252  IF ( ALL(var(:,:) == val_exp ) ) THEN
253     IF ( is_key <= 0 ) THEN
254       CALL getin_p(key_wd,  val_tmp)
255     ENDIF
256     var(:,:) = val_tmp(:,:)
257  END IF
258
259  DEALLOCATE(val_tmp)
260 
261END SUBROUTINE i22setvar_p
262
263
264!! Interface for scalar to scalar real
265SUBROUTINE r0setvar_p (var, val_exp, key_wd, val_put)
266 
267  REAL(r_std), INTENT(inout)                   :: var                  !! Real scalar to modify
268  REAL(r_std), INTENT(in)                      :: val_exp              !! Exceptional value
269  CHARACTER(LEN=*), INTENT(in)                   :: key_wd               !! The Key word we will look for
270  REAL(r_std), INTENT(in)                      :: val_put              !! Initial value to stored
271 
272  REAL(r_std)                                  :: val_tmp
273  INTEGER(i_std)                                     :: is_key
274
275  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
276
277  IF (long_print_setvar_p) WRITE (numout,*) "r0setvar :", key_wd, val_exp, val_put
278
279  val_tmp = val_put
280
281  IF ( var==val_exp ) THEN
282     IF ( is_key <= 0 ) THEN
283       CALL getin_p(key_wd,  val_tmp)
284     ENDIF
285     var = val_tmp
286  END IF
287 
288END SUBROUTINE r0setvar_p
289
290
291!! Interface for initialising an 1D real array with a scalar real.
292SUBROUTINE r10setvar_p (var, val_exp, key_wd, val_put)
293 
294  REAL(r_std), DIMENSION(:), INTENT(inout)     :: var                  !! 1D real array to modify
295  REAL(r_std), INTENT(in)                      :: val_exp              !! Exceptional value
296  CHARACTER(LEN=*), INTENT(in)                 :: key_wd               !! The Key word we will look for
297  REAL(r_std), INTENT(in)                      :: val_put              !! Scalar value to stored
298   
299  REAL(r_std)                                  :: val_tmp
300  INTEGER(i_std)                               :: is_key
301
302  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
303 
304  IF (long_print_setvar_p) WRITE (numout,*) "r10setvar :", key_wd, val_exp, val_put
305
306  val_tmp = val_put
307
308  IF ( ALL( var(:) == val_exp ) ) THEN
309     IF ( is_key <= 0 ) THEN
310       CALL getin_p(key_wd,  val_tmp)
311     ENDIF
312     var(:) = val_tmp
313  END IF
314 
315END SUBROUTINE r10setvar_p
316
317
318!! Interface for initialising an 1D array real with an other 1D array real.
319SUBROUTINE r11setvar_p (var, val_exp, key_wd, val_put, is_grid)
320 
321  REAL(r_std), DIMENSION(:), INTENT(inout)     :: var                 !! 1D real array to modify
322  REAL(r_std), INTENT(in)                      :: val_exp             !! Exceptional value
323  CHARACTER(LEN=*), INTENT(in)                 :: key_wd              !! The Key word we will look for
324  REAL(r_std), DIMENSION(:), INTENT(in)        :: val_put             !! 1D integer array to stored
325  LOGICAL,        OPTIONAL                     :: is_grid             !! Parameter present indicates a setvar for a grid variable
326
327  REAL(r_std), ALLOCATABLE,DIMENSION(:)        :: val_tmp
328  INTEGER(i_std)                               :: is_key
329
330  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
331   
332  IF (long_print_setvar_p) WRITE (numout,*) "r11setvar :", key_wd, val_exp, SIZE(val_put), val_put(1)
333
334  ALLOCATE(val_tmp(SIZE(val_put)))
335  val_tmp(:) = val_put(:)
336
337  IF ( ALL( var(:) == val_exp ) ) THEN
338     IF ( is_key <= 0 ) THEN
339       CALL getin_p(key_wd,  val_tmp)
340     ENDIF
341     var(:) = val_tmp (:)
342  END IF
343
344  DEALLOCATE(val_tmp)
345 
346END SUBROUTINE r11setvar_p
347
348
349!! Interface for initialising an 2D array real with a scalar real.
350SUBROUTINE r20setvar_p (var, val_exp, key_wd, val_put)
351 
352  ! interface for scalar to 2D array real
353
354  REAL(r_std), DIMENSION(:,:), INTENT(inout)   :: var                  !! 2D integer array to modify
355  REAL(r_std), INTENT(in)                      :: val_exp              !! Exceptional value
356  CHARACTER(LEN=*), INTENT(in)                 :: key_wd               !! The Key word we will look for
357  REAL(r_std), INTENT(in)                      :: val_put              !! Scalar value to stored
358 
359  REAL(r_std)                                  :: val_tmp 
360  INTEGER(i_std)                               :: is_key
361
362  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
363 
364  IF (long_print_setvar_p) WRITE (numout,*) "r20setvar :", key_wd, val_exp, val_put
365
366  val_tmp = val_put
367
368  IF ( ALL( var(:,:) == val_exp ) ) THEN
369     IF ( is_key <= 0 ) THEN
370       CALL getin_p(key_wd,  val_tmp)
371     ENDIF
372     var(:,:) = val_tmp
373  END IF
374 
375END SUBROUTINE r20setvar_p
376
377
378!! Interface for initialising an 2D array real with an 1D array real.
379!! Row or column depending size of 1D array to stored.
380!!
381!! example: 1D 1.,2.,3.     2D is 1., 2., 3.,
382!!                                1., 2., 3.
383!!
384!!
385!! example: 1D 1.,2.,3.     2D is 1., 1.,
386!!                                2., 2.,
387!!                                3., 3.
388!!
389SUBROUTINE r21setvar_p (var, val_exp, key_wd, val_put, is_grid)
390 
391  ! interface for 1D array to 2D array real
392
393  REAL(r_std), DIMENSION(:,:), INTENT(inout)   :: var                  !! 2D real array to modify
394  REAL(r_std), INTENT(in)                      :: val_exp              !! Exceptional value
395  CHARACTER(LEN=*), INTENT(in)                 :: key_wd               !! The Key word we will look for
396  REAL(r_std), DIMENSION(:), INTENT(in)        :: val_put              !! 1D real array to stored
397  LOGICAL,        OPTIONAL                     :: is_grid              !! Parameter present indicates a setvar for a grid variable
398
399  REAL(r_std), ALLOCATABLE,DIMENSION(:)        :: val_tmp
400  INTEGER(i_std)                               :: is_key
401
402  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
403 
404  ! test if the 1D array dimension is compatible with first or second
405  ! dimension of the 2D array
406
407  IF (long_print_setvar_p) WRITE (numout,*) "r21setvar :", key_wd, val_exp, SIZE(val_put), val_put(1)
408
409  ALLOCATE(val_tmp(SIZE(val_put)))
410  val_tmp(:) = val_put(:)
411
412  IF (SIZE(val_put)==SIZE(var,1)) THEN 
413      !
414      ! example: 1D 1.,2.,3.     2D is 1., 2., 3.,
415      !                                1., 2., 3.
416      !
417      IF ( ALL( var(:,:) == val_exp ) ) THEN
418         IF ( is_key <= 0 ) THEN
419           CALL getin_p(key_wd,  val_tmp)
420         ENDIF
421         var(:,:) = SPREAD(val_tmp(:),2,SIZE(var,1))
422      END IF
423  ELSEIF (SIZE(val_put)==SIZE(var,2)) THEN 
424      !
425      ! example: 1D 1.,2.,3.     2D is 1., 1.,
426      !                                2., 2.,
427      !                                3., 3.
428      !
429      IF ( ALL( var(:,:) == val_exp ) ) THEN
430         IF ( is_key <= 0 ) THEN
431           CALL getin_p(key_wd,  val_tmp)
432         ENDIF
433         var(:,:) = SPREAD(val_tmp(:),1,SIZE(var,1))
434      END IF
435  ELSE
436      WRITE (numout,*) ' incompatible dimension var and val_put'
437      WRITE (numout,*) ' var     ', SIZE(var,1), SIZE(var,2)
438      WRITE (numout,*) ' val_put ', SIZE(val_put)
439      STOP 'setvar'
440  END IF
441
442  DEALLOCATE(val_tmp)
443 
444END SUBROUTINE r21setvar_p
445
446
447!! Interface for initialising a real 2D array with a scalar parameter from run.def or an other 2D array in argument
448SUBROUTINE r22setvar_p (var, val_exp, key_wd, val_put)
449 
450  ! interface for 2D array to 2D array real
451  ! If a key_wd is set, it is supposed to be a scalar parameter will be read from run.def
452  ! It is not possible to read a 2D variable from run.def
453
454  REAL(r_std), DIMENSION(:,:), INTENT(inout)   :: var                 !! 2D real array to modify
455  REAL(r_std), INTENT(in)                      :: val_exp             !! Exceptional value
456  CHARACTER(LEN=*), INTENT(in)                 :: key_wd              !! The Key word we will look for
457  REAL(r_std), DIMENSION(:,:), INTENT(in)      :: val_put             !! 2D integer array to stored
458  REAL(r_std), ALLOCATABLE, DIMENSION(:,:)     :: val_tmp
459  REAL(r_std)                                  :: val_scal            !! Temporary variable to read a scalar value from run.def
460  INTEGER(i_std)                               :: is_key
461
462  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
463
464  IF (long_print_setvar_p) WRITE (numout,*) "r22setvar :", key_wd, val_exp, SIZE(val_put), val_put(1,1)
465
466  ALLOCATE(val_tmp(SIZE(val_put,DIM=1),SIZE(val_put,DIM=2)))
467  val_tmp(:,:) = val_put(:,:)
468
469  IF ( ALL( var(:,:) == val_exp ) ) THEN
470     IF ( is_key <= 0 ) THEN
471        ! This case only read a scalar value with getin
472        val_scal=val_exp
473        CALL getin_p(key_wd, val_scal)
474        ! If a value was found in run.def, then set val_tmp to this value.
475        IF (val_scal/=val_exp) val_tmp(:,:)=val_scal 
476     ENDIF
477     var(:,:) = val_tmp(:,:)
478  END IF
479
480  DEALLOCATE(val_tmp)
481 
482END SUBROUTINE r22setvar_p
483
484!! Interface for initialising an 3D array real with a scalar real.
485SUBROUTINE r30setvar_p (var, val_exp, key_wd, val_put)
486
487  REAL(r_std), DIMENSION(:,:,:), INTENT(inout) :: var                  !! 3D integer array to modify
488  REAL(r_std), INTENT(in)                      :: val_exp              !! Exceptional value
489  CHARACTER(LEN=*), INTENT(in)                 :: key_wd               !! The Key word we will look for
490  REAL(r_std), INTENT(in)                      :: val_put              !! Scalar value to stored
491
492  REAL(r_std)                                  :: val_tmp 
493  INTEGER(i_std)                               :: is_key
494
495  is_key = MAX(INDEX(key_wd, 'NO_KEYWORD'), INDEX(key_wd, 'NOKEYWORD'))
496
497  IF (long_print_setvar_p) WRITE(numout,*) 'r30setvar',val_exp, val_put
498
499  val_tmp = val_put
500
501  IF ( ALL( var(:,:,:) == val_exp ) ) THEN
502     IF ( is_key <= 0 ) THEN
503       CALL getin_p(key_wd,  val_tmp)
504     ENDIF
505     var(:,:,:) = val_tmp
506  END IF
507
508END SUBROUTINE r30setvar_p
509
510END MODULE sechiba_io_p
Note: See TracBrowser for help on using the repository browser.