Opened 2 years ago

Closed 2 years ago

#2103 closed Bug (fixed)

Segfault from BDY indexing and code error from fldread data load without time interpolation

Reported by: lovato Owned by: lovato
Priority: normal Milestone: 2018 release-4.0
Component: OCE Version: trunk
Severity: minor Keywords: BDY, SBC
Cc:

Description (last modified by lovato)

Context

1) BDY indexing randomly generate a segmentation fault

2) BDY data reading with fldread produces an error because code attempt to read data record beyond the end of file timeline

Analysis

1)
In the re-calculation of fmask without the land boundary condition (shlat) included in src/OCE/BDY/bdyini.F90 the temporary array zfmask is not set to zero is missing.
Thus, with certain domain decompositions and with land exclusion, the following loop may not fill the outer bound of the domain.
(in addition if compiled with check-bounds option the indexes generated in this piece of code point outside array boundaries)

      ! For the flagu/flagv calculation below we require a version of fmask without
      ! the land boundary condition (shlat) included:
      DO ij = 2, jpjm1
         DO ii = 2, jpim1
            zfmask(ii,ij) = tmask(ii,ij  ,1) * tmask(ii+1,ij  ,1)   &
           &              * tmask(ii,ij+1,1) * tmask(ii+1,ij+1,1)
         END DO
      END DO

      ! Lateral boundary conditions
      CALL lbc_lnk( zfmask, 'F', 1. )

2)
The revision made to the code after 2016 merge party bounded the update of file names in fldread only for the case of time-interpolation.
So when time interpolation is disabled the code block because it tries to read and after record that do not exist in the netcdf file

Fix

1)
Simply add the zeroing of zfmask before the loop, as in the example below

      ! For the flagu/flagv calculation below we require a version of fmask without
      ! the land boundary condition (shlat) included:
      zfmask(:,:) = 0
       DO ij = 2, jpjm1
         DO ii = 2, jpim1
            zfmask(ii,ij) = tmask(ii,ij  ,1) * tmask(ii+1,ij  ,1)   &
           &              * tmask(ii,ij+1,1) * tmask(ii+1,ij+1,1)
         END DO
      END DO

      ! Lateral boundary conditions
      CALL lbc_lnk( zfmask, 'F', 1. )

2)
Always check if the current file has reached the last record, independently from the use of time interpolation and update the name of the next file to be read.
Move the endif instance of time interpolation check in fldread as in the following

               CALL fld_clopn( sd(jf) )   ! Do we need to open a new year/month/week/day file?

               IF( sd(jf)%ln_tint ) THEN

                  ! if kn_fsbc*rdt is larger than nfreqh (which is kind of odd),
                  ! it is possible that the before value is no more the good one... we have to re-read it
                  ! if before record is not just just before the after record...
                  IF( .NOT. ll_firstcall .AND. MOD( sd(jf)%nrec_a(1), sd(jf)%nreclast ) /= 1 &
                     &                   .AND. sd(jf)%nrec_b(1) /= sd(jf)%nrec_a(1) - 1 ) THEN
                     sd(jf)%nrec_a(1) = sd(jf)%nrec_a(1) - 1       ! move back to before record
                     CALL fld_get( sd(jf), imap )                  ! read after data
                     sd(jf)%fdta(:,:,:,1) = sd(jf)%fdta(:,:,:,2)   ! re-swap before record field
                     sd(jf)%nrec_b(1) = sd(jf)%nrec_a(1)           ! update before record informations
                     sd(jf)%nrec_b(2) = sd(jf)%nrec_a(2) - NINT( sd(jf)%nfreqh * 3600 )  ! assume freq to be in hours in this case
                     sd(jf)%rotn(1)   = sd(jf)%rotn(2)             ! update before rotate informations
                     sd(jf)%nrec_a(1) = sd(jf)%nrec_a(1) + 1       ! move back to after record
                  ENDIF
               ENDIF ! temporal interpolation?

               ! do we have to change the year/month/week/day of the forcing field??
               ! if we do time interpolation we will need to open next year/month/week/day file before the end of the current
               ! one. If so, we are still before the end of the year/month/week/day when calling fld_rec so sd(jf)%nrec_a(1)
               ! will be larger than the record number that should be read for current year/month/week/day
               ! do we need next file data?
               ! This applies to both cases with or without time interpolation
               IF( sd(jf)%nrec_a(1) > sd(jf)%nreclast ) THEN

                  sd(jf)%nrec_a(1) = sd(jf)%nrec_a(1) - sd(jf)%nreclast   !

                  IF( .NOT. ( sd(jf)%ln_clim .AND. sd(jf)%cltype == 'yearly' ) ) THEN   ! close/open the current/new file

                     llnxtmth = sd(jf)%cltype == 'monthly' .OR. nday == nmonth_len(nmonth)      ! open next month file?
                     llnxtyr  = sd(jf)%cltype == 'yearly'  .OR. (nmonth == 12 .AND. llnxtmth)   ! open next year  file?

                     ! if the run finishes at the end of the current year/month/week/day, we will allow next
                     ! year/month/week/day file to be not present. If the run continue further than the current
                     ! year/month/week/day, next year/month/week/day file must exist
                     isecend = nsec_year + nsec1jan000 + (nitend - kt) * NINT(rdt)   ! second at the end of the run
                     llstop = isecend > sd(jf)%nrec_a(2)                                   ! read more than 1 record of next year
                     ! we suppose that the date of next file is next day (should be ok even for weekly files...)
                     CALL fld_clopn( sd(jf), nyear  + COUNT((/llnxtyr /))                                           ,         &
                        &                    nmonth + COUNT((/llnxtmth/)) - 12                 * COUNT((/llnxtyr /)),         &
                        &                    nday   + 1                   - nmonth_len(nmonth) * COUNT((/llnxtmth/)), llstop )

                     IF( sd(jf)%num <= 0 .AND. .NOT. llstop ) THEN    ! next year file does not exist
                        CALL ctl_warn('next year/month/week/day file: '//TRIM(sd(jf)%clname)//     &
                           &     ' not present -> back to current year/month/day')
                        CALL fld_clopn( sd(jf) )       ! back to the current year/month/day
                        sd(jf)%nrec_a(1) = sd(jf)%nreclast     ! force to read the last record in the current year file
                     ENDIF

                  ENDIF
               ENDIF   ! open need next file?

               ! read after data
               IF( PRESENT(jpk_bdy) ) THEN

Commit History (1)

ChangesetAuthorTimeChangeLog
9807lovato2018-06-16T00:51:16+02:00

trunk: apply bugfix to BDY indexing and fldread file advancement - #2103

Change History (3)

comment:1 Changed 2 years ago by nicolasmartin

  • Description modified (diff)

comment:2 Changed 2 years ago by lovato

In 9807:

trunk: apply bugfix to BDY indexing and fldread file advancement - #2103

comment:3 Changed 2 years ago by lovato

  • Description modified (diff)
  • Resolution set to fixed
  • Status changed from new to closed

The proposed solution was implemented at trunk revision r9807

Note: See TracTickets for help on using tickets.