# Bug in computation of potential temp from conservative temp (\`eos\_pt\_from\_ct\`)

**URL:** <https://nemo-ocean.discourse.group/t/bug-in-computation-of-potential-temp-from-conservative-temp-eos-pt-from-ct/953>\
**Category:** v4.2.x\
**Created:** [11 October 2025 13:34 UTC](https://nemo-ocean.discourse.group/t/bug-in-computation-of-potential-temp-from-conservative-temp-eos-pt-from-ct/953 "2025-10-11T13:34:53Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![rabbit](https://avatars.discourse-cdn.com/v4/letter/r/919ad9/32.png) [@rabbit](https://nemo-ocean.discourse.group/u/rabbit)\
**Post date:** [11 October 2025 13:34 UTC](https://nemo-ocean.discourse.group/t/bug-in-computation-of-potential-temp-from-conservative-temp-eos-pt-from-ct/953/1 "2025-10-11T13:34:53Z")

</div>

We are running nemo with TEOS-10 and open cavities. We came across the bug that the output variable `toce_pot`(thetao) is masked with surface tmask

In `src/OCE/TRA/eosbn2.F90` on line 1086:

```auto
       ztm = tmask(ji,jj,1)

```

Which is then applied to the derived potential temperature

```auto
         ptmp(ji,jj) = ( zt / z1_T0 + zn / zd ) * ztm

```

I think that there is no need to perform multiplication by `ztm` at all, which erroneously masks open cavities. `ztm` can be removed from the routine.

I checked that the bug is present in v5 as well.

Could you add the fix on nemo forge, @smasson so that this is not forgotten? And thank you for fixing hfbasin, we recently pulled in the patch to nemo4.2

---

<div class="post-metadata">

**Author:** ![Dorothee](https://avatars.discourse-cdn.com/v4/letter/d/edb3f5/32.png) [@Dorothee](https://nemo-ocean.discourse.group/u/Dorothee)\
**Post date:** [16 October 2025 20:47 UTC](https://nemo-ocean.discourse.group/t/bug-in-computation-of-potential-temp-from-conservative-temp-eos-pt-from-ct/953/2 "2025-10-16T20:47:03Z")

</div>

Hi!  
Here is a fix. I have added a 3d version of eos\_pt\_from\_ct  
In `src/OCE/TRA/eosbn2.F90:`

```auto
   FUNCTION eos_pt_from_ct_3d( ctmp, psal ) RESULT( ptmp )
      !!----------------------------------------------------------------------
      !! ***ROUTINE eos_pt_from_ct***
      !!
      !! ** Purpose : Compute pot.temp. from cons. temp. [Celsius]
      !!
      !! ** Method : rational approximation (5/3th order) of TEOS-10 algorithm
      !! checkvalue: pt=20.02391895 Celsius for sa=35.7g/kg, ct=20degC
      !!
      !! Reference : TEOS-10, UNESCO
      !! Rational approximation to TEOS10 algorithm (rms error on WOA13 values: 4.0e-5 degC)
      !!----------------------------------------------------------------------
      REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(in ) :: ctmp ! Cons. Temp [Celsius]
      REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(in ) :: psal ! salinity [psu]
      ! Leave result array automatic rather than making explicitly allocated
      REAL(wp), DIMENSION(jpi,jpj,jpk) :: ptmp ! potential temperature [Celsius]
      !
      INTEGER :: ji, jj, jk ! dummy loop indices
      REAL(wp) :: zt , zs , ztm ! local scalars
      REAL(wp) :: zn , zd ! local scalars
      REAL(wp) :: zdeltaS , z1_S0 , z1_T0
      !!----------------------------------------------------------------------
      !
      IF( ln_timing ) CALL timing_start('eos_pt_from_ct_3d')
      !
      zdeltaS = 5._wp
      z1_S0 = 0.875_wp/35.16504_wp
      z1_T0 = 1._wp/40._wp
      !
      DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 )
         !
         zt = ctmp (ji,jj,jk) * z1_T0
         zs = SQRT( ABS( psal(ji,jj,jk) + zdeltaS ) * z1_S0 )
         !jkt = mikt(ji,jj)
         ztm = tmask(ji,jj,jk)
         !
         zn = ((((-2.1385727895e-01_wp*zt &
            & - 2.7674419971e-01_wp*zs+1.0728094330_wp)*zt &
            & + (2.6366564313_wp*zs+3.3546960647_wp)*zs-7.8012209473_wp)*zt &
            & + ((1.8835586562_wp*zs+7.3949191679_wp)*zs-3.3937395875_wp)*zs-5.6414948432_wp)*zt &
            & + (((3.5737370589_wp*zs-1.5512427389e+01_wp)*zs+2.4625741105e+01_wp)*zs &
            & +1.9912291000e+01_wp)*zs-3.2191146312e+01_wp)*zt &
            & + ((((5.7153204649e-01_wp*zs-3.0943149543_wp)*zs+9.3052495181_wp)*zs &
            & -9.4528934807_wp)*zs+3.1066408996_wp)*zs-4.3504021262e-01_wp
            !
         zd = (2.0035003456_wp*zt &
            & -3.4570358592e-01_wp*zs+5.6471810638_wp)*zt &
            & + (1.5393993508_wp*zs-6.9394762624_wp)*zs+1.2750522650e+01_wp
            !
         ptmp(ji,jj,jk) = ( zt / z1_T0 + zn / zd ) * ztm
            !
      END_3D
      !
      IF( ln_timing ) CALL timing_stop('eos_pt_from_ct_3d')
      !
   END FUNCTION eos_pt_from_ct_3d

```

In `src/OCE/DIA/diaar5.F90`:

```auto
      IF( ln_teos10 ) THEN ! ! potential temperature (TEOS-10 case)
         IF( iom_use( 'toce_pot') .OR. iom_use( 'temptot_pot' ) .OR. iom_use( 'sst_pot' ) &
                                  .OR. iom_use( 'ssttot' ) .OR. iom_use( 'tosmint_pot' ) ) THEN
            !
            ALLOCATE( ztpot(jpi,jpj,jpk) )
            ztpot(:,:,jpk) = 0._wp
            !
            ztpot(:,:,:) =eos_pt_from_ct_3d( ts(:,:,:,jp_tem,Kmm), ts(:,:,:,jp_sal,Kmm) ) !
            CALL iom_put( 'toce_pot', ztpot(:,:,:) ) ! potential temperature (TEOS-10 case)
            CALL iom_put( 'sst_pot' , ztpot(:,:,1) ) ! surface temperature

```

---

<div class="post-metadata">

**Author:** ![Dorothee](https://avatars.discourse-cdn.com/v4/letter/d/edb3f5/32.png) [@Dorothee](https://nemo-ocean.discourse.group/u/Dorothee)\
**Post date:** [17 October 2025 20:10 UTC](https://nemo-ocean.discourse.group/t/bug-in-computation-of-potential-temp-from-conservative-temp-eos-pt-from-ct/953/3 "2025-10-17T20:10:43Z")

</div>

More elegant way:

```auto
   FUNCTION eos_pt_from_ct( ctmp, psal, pjk ) RESULT( ptmp )
      !!----------------------------------------------------------------------
      !! ***ROUTINE eos_pt_from_ct***
      !!
      !! ** Purpose : Compute pot.temp. from cons. temp. [Celsius]
      !!
      !! ** Method : rational approximation (5/3th order) of TEOS-10 algorithm
      !! checkvalue: pt=20.02391895 Celsius for sa=35.7g/kg, ct=20degC
      !!
      !! Reference : TEOS-10, UNESCO
      !! Rational approximation to TEOS10 algorithm (rms error on WOA13 values: 4.0e-5 degC)
      !!----------------------------------------------------------------------
      REAL(wp), DIMENSION(jpi,jpj), INTENT(in ) :: ctmp ! Cons. Temp [Celsius]
      REAL(wp), DIMENSION(jpi,jpj), INTENT(in ) :: psal ! salinity [psu]
      INTEGER, OPTIONAL, INTENT(in ) :: pjk ! level for tmask
      ! Leave result array automatic rather than making explicitly allocated
      REAL(wp), DIMENSION(jpi,jpj) :: ptmp ! potential temperature [Celsius]
      !
      INTEGER :: ji, jj, zjk ! dummy loop indices
      REAL(wp) :: zt , zs , ztm ! local scalars
      REAL(wp) :: zn , zd ! local scalars
      REAL(wp) :: zdeltaS , z1_S0 , z1_T0
      !!----------------------------------------------------------------------
      !
      IF( ln_timing ) CALL timing_start('eos_pt_from_ct')
      !
      zdeltaS = 5._wp
      z1_S0 = 0.875_wp/35.16504_wp
      z1_T0 = 1._wp/40._wp
      !
      IF (PRESENT(pjk)) THEN
         zjk = pjk
      ELSE
         zjk = 1 ! default value 
      END IF
      !
      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
         !
         zt = ctmp (ji,jj) * z1_T0
         zs = SQRT( ABS( psal(ji,jj) + zdeltaS ) * z1_S0 )
         ztm = tmask(ji,jj,zjk)
         !
         zn = ((((-2.1385727895e-01_wp*zt &
            & - 2.7674419971e-01_wp*zs+1.0728094330_wp)*zt &
            & + (2.6366564313_wp*zs+3.3546960647_wp)*zs-7.8012209473_wp)*zt &
            & + ((1.8835586562_wp*zs+7.3949191679_wp)*zs-3.3937395875_wp)*zs-5.6414948432_wp)*zt &
            & + (((3.5737370589_wp*zs-1.5512427389e+01_wp)*zs+2.4625741105e+01_wp)*zs &
            & +1.9912291000e+01_wp)*zs-3.2191146312e+01_wp)*zt &
            & + ((((5.7153204649e-01_wp*zs-3.0943149543_wp)*zs+9.3052495181_wp)*zs &
            & -9.4528934807_wp)*zs+3.1066408996_wp)*zs-4.3504021262e-01_wp
            !
         zd = (2.0035003456_wp*zt &
            & -3.4570358592e-01_wp*zs+5.6471810638_wp)*zt &
            & + (1.5393993508_wp*zs-6.9394762624_wp)*zs+1.2750522650e+01_wp
            !
         ptmp(ji,jj) = ( zt / z1_T0 + zn / zd ) * ztm
            !
      END_2D
      !
      IF( ln_timing ) CALL timing_stop('eos_pt_from_ct')
      !
   END FUNCTION eos_pt_from_ct

```
