Skip to content

Commit 284e1ef

Browse files
authored
Add serial driver gswp3 support and fix serial-MPI non-reproducibility (#544)
Currently the offline serial driver does not support the namelist option `cable_user%MetType = 'gswp3'` - the option is only supported in the MPI drivers. This PR adds support for the namelist option to the serial driver so we can use these configurations for testing the MPI implementation with parallel-IO (which will be based off the serial driver). This PR also fixes several bugs found in the MPI drivers such that we have bitwise reproducibility between serial and MPI for the [gswp3 configuration](https://github.com/SeanBryan51/crujra_accessN96_1h) for outputs and restarts (run for 1 year on a reduced domain). Fixes #388 ## Type of change - [x] Bug fix ## Checklist - [x] The new content is accessible and located in the appropriate section - [x] I have checked that links are valid and point to the intended content - [x] I have checked my code/text and corrected any misspellings ## Testing - [x] Are the changes non bitwise-compatible with the main branch because of a bug fix or a feature being newly implemented or improved? If yes, add the link to the modelevaluation.org analysis versus the main branch or equivalent results below this line. - Changes are bitwise compatible with main for site runs but not for spatial MPI runs due to the bug fixes in the MPI drivers: ``` 2025-03-05 17:37:00,335 - INFO - benchcab.benchcab.py:380 - Running comparison tasks... 2025-03-05 17:37:00,358 - INFO - benchcab.benchcab.py:381 - tasks: 168 (models: 2, sites: 42, science configurations: 4) 2025-03-05 17:40:02,866 - INFO - benchcab.benchcab.py:391 - 0 failed, 168 passed ``` <!-- readthedocs-preview cable start --> ---- 📚 Documentation preview 📚: https://cable--544.org.readthedocs.build/en/544/ <!-- readthedocs-preview cable end -->
2 parents 630e2e1 + 1d423b7 commit 284e1ef

File tree

4 files changed

+119
-11
lines changed

4 files changed

+119
-11
lines changed

src/offline/cable_mpicommon.F90

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ MODULE cable_mpicommon
2929

3030
! base number of input fields: must correspond to CALLS to
3131
! MPI_address (field ) in *_mpimaster/ *_mpiworker
32-
INTEGER, PARAMETER :: nparam = 340
32+
INTEGER, PARAMETER :: nparam = 341
3333

3434
! MPI: extra params sent only if nsoilparmnew is true
3535
INTEGER, PARAMETER :: nsoilnew = 1
@@ -103,7 +103,7 @@ MODULE cable_mpicommon
103103
! MPI: number of fields included in restart_t type for data
104104
! that is returned only for creating a restart file at the end of the run
105105
! MPI: gol124: canopy%rwater removed when Bernard ported to CABLE_r491
106-
INTEGER, PARAMETER :: nrestart = 15
106+
INTEGER, PARAMETER :: nrestart = 17
107107
INTEGER, PARAMETER :: nsumcasaflux = 62
108108
INTEGER, PARAMETER :: nsumcasapool = 40
109109
INTEGER, PARAMETER :: nclimate = 30

src/offline/cable_mpimaster.F90

+94-5
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,77 @@ SUBROUTINE mpidrv_master (comm, trunk_sumbal, dels, koffset, kend, PLUME, CRU)
500500
CALL alloc_cbm_var (imet, mp)
501501
CALL alloc_cbm_var (iveg, mp)
502502

503+
imet%ca(:) = met%ca(:)
504+
imet%year(:) = met%year(:)
505+
imet%moy(:) = met%moy(:)
506+
imet%doy(:) = met%doy(:)
507+
imet%hod(:) = met%hod(:)
508+
imet%fsd(:,:) = met%fsd(:,:)
509+
imet%ofsd(:) = met%ofsd(:)
510+
imet%fld(:) = met%fld(:)
511+
imet%precip(:) = met%precip(:)
512+
imet%precip_sn(:) = met%precip_sn(:)
513+
imet%tk(:) = met%tk(:)
514+
imet%tvair(:) = met%tvair(:)
515+
imet%tvrad(:) = met%tvrad(:)
516+
imet%pmb(:) = met%pmb(:)
517+
imet%ua(:) = met%ua(:)
518+
imet%qv(:) = met%qv(:)
519+
imet%qvair(:) = met%qvair(:)
520+
imet%da(:) = met%da(:)
521+
imet%dva(:) = met%dva(:)
522+
imet%coszen(:) = met%coszen(:)
523+
imet%Ndep(:) = met%Ndep(:)
524+
imet%Pdep(:) = met%Pdep(:)
525+
526+
iveg%canst1(:) = veg%canst1(:)
527+
iveg%dleaf(:) = veg%dleaf(:)
528+
iveg%ejmax(:) = veg%ejmax(:)
529+
iveg%iveg(:) = veg%iveg(:)
530+
iveg%iLU(:) = veg%iLU(:)
531+
iveg%meth(:) = veg%meth(:)
532+
iveg%frac4(:) = veg%frac4(:)
533+
iveg%hc(:) = veg%hc(:)
534+
iveg%vlai(:) = veg%vlai(:)
535+
iveg%xalbnir(:) = veg%xalbnir(:)
536+
iveg%rp20(:) = veg%rp20(:)
537+
iveg%rpcoef(:) = veg%rpcoef(:)
538+
iveg%rs20(:) = veg%rs20(:)
539+
iveg%shelrb(:) = veg%shelrb(:)
540+
iveg%vegcf(:) = veg%vegcf(:)
541+
iveg%tminvj(:) = veg%tminvj(:)
542+
iveg%toptvj(:) = veg%toptvj(:)
543+
iveg%tmaxvj(:) = veg%tmaxvj(:)
544+
iveg%vbeta(:) = veg%vbeta(:)
545+
iveg%vcmax(:) = veg%vcmax(:)
546+
iveg%xfang(:) = veg%xfang(:)
547+
iveg%extkn(:) = veg%extkn(:)
548+
iveg%wai(:) = veg%wai(:)
549+
iveg%deciduous(:) = veg%deciduous(:)
550+
iveg%froot(:,:) = veg%froot(:,:)
551+
iveg%refl(:,:) = veg%refl(:,:)
552+
iveg%taul(:,:) = veg%taul(:,:)
553+
iveg%vlaimax(:) = veg%vlaimax(:)
554+
iveg%a1gs(:) = veg%a1gs(:)
555+
iveg%d0gs(:) = veg%d0gs(:)
556+
iveg%alpha(:) = veg%alpha(:)
557+
iveg%convex(:) = veg%convex(:)
558+
iveg%cfrd(:) = veg%cfrd(:)
559+
iveg%gswmin(:) = veg%gswmin(:)
560+
iveg%conkc0(:) = veg%conkc0(:)
561+
iveg%conko0(:) = veg%conko0(:)
562+
iveg%ekc(:) = veg%ekc(:)
563+
iveg%eko(:) = veg%eko(:)
564+
iveg%g0(:) = veg%g0(:)
565+
iveg%g1(:) = veg%g1(:)
566+
iveg%rootbeta(:) = veg%rootbeta(:)
567+
iveg%gamma(:) = veg%gamma(:)
568+
iveg%F10(:) = veg%F10(:)
569+
iveg%ZR(:) = veg%ZR(:)
570+
iveg%clitt(:) = veg%clitt(:)
571+
iveg%disturbance_interval(:,:) = veg%disturbance_interval(:,:)
572+
iveg%disturbance_intensity(:,:) = veg%disturbance_intensity(:,:)
573+
503574
! MPI: create inp_t types to scatter input data to the workers
504575
! at the start of every timestep
505576
!CALL master_intypes (comm,met,veg)
@@ -528,7 +599,7 @@ SUBROUTINE mpidrv_master (comm, trunk_sumbal, dels, koffset, kend, PLUME, CRU)
528599
! MPI: create type to send restart data back to the master
529600
! only if restart file is to be created
530601
IF(output%restart) THEN
531-
CALL master_restart_types (comm, canopy, air)
602+
CALL master_restart_types (comm, canopy, air, bgc)
532603
END IF
533604

534605
! CALL zero_sum_casa(sum_casapool, sum_casaflux)
@@ -680,6 +751,8 @@ SUBROUTINE mpidrv_master (comm, trunk_sumbal, dels, koffset, kend, PLUME, CRU)
680751
!$ CALL read_casa_dump( ncfile, casamet, casaflux, casa_it, kend, .FALSE. )
681752
!$ ENDIF
682753

754+
! Zero out lai where there is no vegetation acc. to veg. index
755+
WHERE ( iveg%iveg(:) .GE. 14 ) iveg%vlai = 0.
683756

684757
!$ ! At first time step of year, set tile area according to updated LU areas
685758
!$ IF (ktau == 1 .and. CABLE_USER%POPLUC) THEN
@@ -750,9 +823,6 @@ SUBROUTINE mpidrv_master (comm, trunk_sumbal, dels, koffset, kend, PLUME, CRU)
750823
met%ofsd = met%fsd(:,1) + met%fsd(:,2)
751824
canopy%oldcansto=canopy%cansto
752825

753-
! Zero out lai where there is no vegetation acc. to veg. index
754-
WHERE ( iveg%iveg(:) .GE. 14 ) iveg%vlai = 0.
755-
756826
! Write time step's output to file if either: we're not spinning up
757827
! or we're spinning up and the spinup has converged:
758828
! MPI: TODO: pull mass and energy balance calculation from write_output
@@ -1815,6 +1885,12 @@ SUBROUTINE master_cable_params (comm,met,air,ssnow,veg,bgc,soil,canopy,&
18151885
& types(bidx), ierr)
18161886
blen(bidx) = 1
18171887

1888+
bidx = bidx + 1
1889+
CALL MPI_Get_address (ssnow%wbliq(off,1), displs(bidx), ierr)
1890+
CALL MPI_Type_create_hvector (ms, r2len, r2stride, MPI_BYTE, &
1891+
& types(bidx), ierr)
1892+
blen(bidx) = 1
1893+
18181894
! additional for sli
18191895
bidx = bidx + 1
18201896
CALL MPI_Get_address (ssnow%S(off,1), displs(bidx), ierr)
@@ -7095,7 +7171,7 @@ END SUBROUTINE master_climate_types
70957171
!CLNEND SUBROUTINE master_casa_restart_types
70967172

70977173
! MPI: creates datatype handles to receive restart data from workers
7098-
SUBROUTINE master_restart_types (comm, canopy, air)
7174+
SUBROUTINE master_restart_types (comm, canopy, air, bgc)
70997175

71007176
USE mpi
71017177

@@ -7109,6 +7185,7 @@ SUBROUTINE master_restart_types (comm, canopy, air)
71097185

71107186
TYPE(canopy_type), INTENT(IN) :: canopy
71117187
TYPE (air_type),INTENT(IN) :: air
7188+
TYPE (bgc_pool_type), INTENT(IN) :: bgc
71127189
! TYPE (casa_pool), INTENT(INOUT) :: casapool
71137190
! TYPE (casa_flux), INTENT(INOUT) :: casaflux
71147191
! TYPE (casa_met), INTENT(INOUT) :: casamet
@@ -7170,6 +7247,18 @@ SUBROUTINE master_restart_types (comm, canopy, air)
71707247
& types(bidx), ierr)
71717248
blocks(bidx) = 1
71727249

7250+
bidx = bidx + 1
7251+
CALL MPI_Get_address (bgc%cplant(off,1), displs(bidx), ierr)
7252+
CALL MPI_Type_create_hvector (ncp, r1len, r1stride, MPI_BYTE, &
7253+
& types(bidx), ierr)
7254+
blocks(bidx) = 1
7255+
7256+
bidx = bidx + 1
7257+
CALL MPI_Get_address (bgc%csoil(off,1), displs(bidx), ierr)
7258+
CALL MPI_Type_create_hvector (ncs, r1len, r1stride, MPI_BYTE, &
7259+
& types(bidx), ierr)
7260+
blocks(bidx) = 1
7261+
71737262
last2d = bidx
71747263

71757264
! ------------- 1D vectors -------------

src/offline/cable_mpiworker.F90

+15-2
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ SUBROUTINE mpidrv_worker (comm)
365365
! only if restart file is to be created
366366
IF(output%restart) THEN
367367

368-
CALL worker_restart_type (comm, canopy, air)
368+
CALL worker_restart_type (comm, canopy, air, bgc)
369369

370370
END IF
371371

@@ -1147,6 +1147,10 @@ SUBROUTINE worker_cable_params (comm,met,air,ssnow,veg,bgc,soil,canopy,&
11471147
CALL MPI_Get_address (ssnow%wblf, displs(bidx), ierr)
11481148
blen(bidx) = ms * r2len
11491149

1150+
bidx = bidx + 1
1151+
CALL MPI_Get_address (ssnow%wbliq, displs(bidx), ierr)
1152+
blen(bidx) = ms * r2len
1153+
11501154
! additional for sli
11511155
bidx = bidx + 1
11521156
CALL MPI_Get_address (ssnow%S, displs(bidx), ierr)
@@ -6350,7 +6354,7 @@ END SUBROUTINE worker_climate_types
63506354
! MPI: creates restart_t type to send to the master the fields
63516355
! that are only required for the restart file but not included in the
63526356
! results sent at the end of each time step
6353-
SUBROUTINE worker_restart_type (comm, canopy, air)
6357+
SUBROUTINE worker_restart_type (comm, canopy, air, bgc)
63546358

63556359
USE mpi
63566360

@@ -6362,6 +6366,7 @@ SUBROUTINE worker_restart_type (comm, canopy, air)
63626366

63636367
TYPE(canopy_type), INTENT(IN) :: canopy
63646368
TYPE (air_type),INTENT(IN) :: air
6369+
TYPE (bgc_pool_type), INTENT(IN) :: bgc
63656370

63666371
! MPI: temp arrays for marshalling all types into a struct
63676372
INTEGER, ALLOCATABLE, DIMENSION(:) :: blocks
@@ -6404,6 +6409,14 @@ SUBROUTINE worker_restart_type (comm, canopy, air)
64046409
! MPI: gol124: changed to r1 when Bernard ported to CABLE_r491
64056410
blocks(bidx) = r1len * ms
64066411

6412+
bidx = bidx + 1
6413+
CALL MPI_Get_address (bgc%cplant(off,1), displs(bidx), ierr)
6414+
blocks(bidx) = r1len * ncp
6415+
6416+
bidx = bidx + 1
6417+
CALL MPI_Get_address (bgc%csoil(off,1), displs(bidx), ierr)
6418+
blocks(bidx) = r1len * ncs
6419+
64076420
bidx = bidx + 1
64086421
CALL MPI_Get_address (canopy%cduv(off), displs(bidx), ierr)
64096422
blocks(bidx) = r1len

src/offline/cable_serial.F90

+8-2
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ SUBROUTINE serialdrv(trunk_sumbal, NRRRR, dels, koffset, kend, GSWP_MID, PLUME,
338338
LOY = 365
339339
kend = NINT(24.0*3600.0/dels) * LOY
340340

341+
CASE ('gswp3')
342+
ncciy = CurYear
343+
CALL open_met_file( dels, koffset, kend, spinup, CTFRZ )
344+
341345
CASE ('site')
342346
! site experiment eg AmazonFace (spinup or transient run type)
343347
kend = NINT(24.0*3600.0/dels) * LOY
@@ -532,7 +536,7 @@ SUBROUTINE serialdrv(trunk_sumbal, NRRRR, dels, koffset, kend, GSWP_MID, PLUME,
532536
met%Pdep = site%Pdep *1000./10000./365. ! kg ha-1 y-1 > g m-2 d-1
533537
met%fsd = MAX(met%fsd,0.0)
534538

535-
CASE ('')
539+
CASE DEFAULT
536540
CALL get_met_data( spinup, spinConv, met, soil, &
537541
rad, veg, kend, dels, CTFRZ, ktau+koffset, &
538542
kstart+koffset )
@@ -702,7 +706,7 @@ SUBROUTINE serialdrv(trunk_sumbal, NRRRR, dels, koffset, kend, GSWP_MID, PLUME,
702706
IF ( (.NOT. CASAONLY) .AND. spinConv ) THEN
703707
!mpidiff
704708
SELECT CASE (TRIM(cable_user%MetType))
705-
CASE ('plum', 'cru', 'bios', 'gswp', 'site')
709+
CASE ('plum', 'cru', 'bios', 'gswp', 'gswp3', 'site')
706710
CALL write_output( dels, ktau_tot, met, canopy, casaflux, casapool, casamet, &
707711
ssnow, rad, bal, air, soil, veg, CSBOLTZ, CEMLEAF, CEMSOIL )
708712
CASE DEFAULT
@@ -911,6 +915,7 @@ SUBROUTINE serialdrv(trunk_sumbal, NRRRR, dels, koffset, kend, GSWP_MID, PLUME,
911915
IF ( YYYY .EQ. CABLE_USER%YearEnd .AND. &
912916
NRRRR .GT. 1 ) DEALLOCATE ( GSWP_MID )
913917
ENDIF
918+
IF (TRIM(cable_user%MetType) == "gswp3") CALL close_met_file
914919

915920
IF ((icycle.GT.0).AND.(.NOT.casaonly)) THEN
916921
! re-initalise annual flux sums
@@ -1025,6 +1030,7 @@ SUBROUTINE serialdrv(trunk_sumbal, NRRRR, dels, koffset, kend, GSWP_MID, PLUME,
10251030

10261031

10271032
IF ( TRIM(cable_user%MetType) .NE. "gswp" .AND. &
1033+
TRIM(cable_user%MetType) .NE. "gswp3" .AND. &
10281034
TRIM(cable_user%MetType) .NE. "plum" .AND. &
10291035
TRIM(cable_user%MetType) .NE. "cru" ) CALL close_met_file
10301036

0 commit comments

Comments
 (0)