Changeset 13616
- Timestamp:
- 2020-10-15T17:58:33+02:00 (4 years ago)
- Location:
- NEMO/trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
NEMO/trunk/src/OCE/stpctl.F90
r13458 r13616 67 67 REAL(wp) :: zzz ! local real 68 68 REAL(wp), DIMENSION(9) :: zmax, zmaxlocal 69 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns 69 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns, ll_0oce 70 70 LOGICAL, DIMENSION(jpi,jpj,jpk) :: llmsk 71 71 CHARACTER(len=20) :: clname … … 125 125 ! 126 126 llmsk(Nis0:Nie0,Njs0:Nje0,1) = ssmask(Nis0:Nie0,Njs0:Nje0) == 1._wp ! define only the inner domain 127 ! 128 ll_0oce = .NOT. ANY( llmsk(:,:,1) ) ! no ocean point in the inner domain? 129 ! 127 130 IF( ll_wd ) THEN 128 131 zmax(1) = MAXVAL( ABS( ssh(:,:,Kmm) + ssh_ref ), mask = llmsk(:,:,1) ) ! ssh max … … 149 152 ENDIF 150 153 zmax(9) = REAL( nstop, wp ) ! stop indicator 154 ! 151 155 ! !== get global extrema ==! 152 156 ! !== done by all processes if writting run.stat ==! 153 157 IF( ll_colruns ) THEN 154 158 zmaxlocal(:) = zmax(:) 155 CALL mpp_max( "stpctl", zmax ) ! max over the global domain 159 CALL mpp_max( "stpctl", zmax ) ! max over the global domain: ok even of ll_0oce = .true. 156 160 nstop = NINT( zmax(9) ) ! update nstop indicator (now sheared among all local domains) 157 ENDIF 161 ELSE 162 ! if no ocean point: MAXVAL returns -HUGE => we must overwrite this value to avoid error handling bellow. 163 IF( ll_0oce ) zmax(1:4) = (/ 0._wp, 0._wp, -1._wp, 1._wp /) ! default "valid" values... 164 ENDIF 165 ! 166 zmax(3) = -zmax(3) ! move back from max(-zz) to min(zz) : easier to manage! 167 zmax(5) = -zmax(5) ! move back from max(-zz) to min(zz) : easier to manage! 168 IF( ll_colruns ) THEN 169 zmaxlocal(3) = -zmaxlocal(3) ! move back from max(-zz) to min(zz) : easier to manage! 170 zmaxlocal(5) = -zmaxlocal(5) ! move back from max(-zz) to min(zz) : easier to manage! 171 ENDIF 172 ! 158 173 ! !== write "run.stat" files ==! 159 174 ! !== done only by 1st subdomain at writting timestep ==! 160 175 IF( ll_wrtruns ) THEN 161 WRITE(numrun,9500) kt, zmax(1), zmax(2), -zmax(3), zmax(4) 162 istatus = NF90_PUT_VAR( nrunid, nvarid(1), (/ zmax(1)/), (/kt/), (/1/) ) 163 istatus = NF90_PUT_VAR( nrunid, nvarid(2), (/ zmax(2)/), (/kt/), (/1/) ) 164 istatus = NF90_PUT_VAR( nrunid, nvarid(3), (/-zmax(3)/), (/kt/), (/1/) ) 165 istatus = NF90_PUT_VAR( nrunid, nvarid(4), (/ zmax(4)/), (/kt/), (/1/) ) 166 istatus = NF90_PUT_VAR( nrunid, nvarid(5), (/-zmax(5)/), (/kt/), (/1/) ) 167 istatus = NF90_PUT_VAR( nrunid, nvarid(6), (/ zmax(6)/), (/kt/), (/1/) ) 168 IF( ln_zad_Aimp ) THEN 169 istatus = NF90_PUT_VAR( nrunid, nvarid(7), (/ zmax(7)/), (/kt/), (/1/) ) 170 istatus = NF90_PUT_VAR( nrunid, nvarid(8), (/ zmax(8)/), (/kt/), (/1/) ) 171 ENDIF 176 WRITE(numrun,9500) kt, zmax(1), zmax(2), zmax(3), zmax(4) 177 DO ji = 1, 6 + 2 * COUNT( (/ln_zad_Aimp/) ) 178 istatus = NF90_PUT_VAR( nrunid, nvarid(ji), (/zmax(ji)/), (/kt/), (/1/) ) 179 END DO 172 180 IF( kt == nitend ) istatus = NF90_CLOSE(nrunid) 173 181 END IF … … 175 183 ! !== done by all processes at every time step ==! 176 184 ! 177 IF( 178 & 179 & zmax(3) >= 0._wp .OR. & ! negative or zero sea surface salinity180 & 181 & 182 & 183 & 185 IF( zmax(1) > 20._wp .OR. & ! too large sea surface height ( > 20 m ) 186 & zmax(2) > 10._wp .OR. & ! too large velocity ( > 10 m/s) 187 & zmax(3) <= 0._wp .OR. & ! negative or zero sea surface salinity 188 & zmax(4) >= 100._wp .OR. & ! too large sea surface salinity ( > 100 ) 189 & zmax(4) < 0._wp .OR. & ! too large sea surface salinity (keep this line for sea-ice) 190 & ISNAN( zmax(1) + zmax(2) + zmax(3) ) .OR. & ! NaN encounter in the tests 191 & ABS( zmax(1) + zmax(2) + zmax(3) ) > HUGE(1._wp) ) THEN ! Infinity encounter in the tests 184 192 ! 185 193 iloc(:,:) = 0 … … 221 229 ! 222 230 WRITE(ctmp1,*) ' stp_ctl: |ssh| > 20 m or |U| > 10 m/s or S <= 0 or S >= 100 or NaN encounter in the tests' 223 CALL wrt_line( ctmp2, kt, '|ssh| max', 224 CALL wrt_line( ctmp3, kt, '|U| max', 225 CALL wrt_line( ctmp4, kt, 'Sal min', -zmax(3), iloc(:,3), iareasum(3), iareamin(3), iareamax(3) )226 CALL wrt_line( ctmp5, kt, 'Sal max', 231 CALL wrt_line( ctmp2, kt, '|ssh| max', zmax(1), iloc(:,1), iareasum(1), iareamin(1), iareamax(1) ) 232 CALL wrt_line( ctmp3, kt, '|U| max', zmax(2), iloc(:,2), iareasum(2), iareamin(2), iareamax(2) ) 233 CALL wrt_line( ctmp4, kt, 'Sal min', zmax(3), iloc(:,3), iareasum(3), iareamin(3), iareamax(3) ) 234 CALL wrt_line( ctmp5, kt, 'Sal max', zmax(4), iloc(:,4), iareasum(4), iareamin(4), iareamax(4) ) 227 235 IF( Agrif_Root() ) THEN 228 236 WRITE(ctmp6,*) ' ===> output of last computed fields in output.abort* files' -
NEMO/trunk/src/SAS/stpctl.F90
r13546 r13616 68 68 REAL(wp) :: zzz ! local real 69 69 REAL(wp), DIMENSION(4) :: zmax, zmaxlocal 70 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns 70 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns, ll_0oce 71 71 LOGICAL, DIMENSION(jpi,jpj) :: llmsk 72 72 CHARACTER(len=20) :: clname … … 124 124 llmsk(:,Nje1: jpj) = .FALSE. 125 125 ! 126 llmsk(Nis0:Nie0,Njs0:Nje0) = tmask(Nis0:Nie0,Njs0:Nje0,1) == 1._wp ! test only the inner domain 127 IF( COUNT( llmsk(:,:) ) > 0 ) THEN ! avoid huge values sent back for land processors... 128 zmax(1) = MAXVAL( vt_i (:,:) , mask = llmsk ) ! max ice thickness 129 zmax(2) = MAXVAL( ABS( u_ice(:,:) ) , mask = llmsk ) ! max ice velocity (zonal only) 130 zmax(3) = MAXVAL( -tm_i (:,:) + rt0, mask = llmsk ) ! min ice temperature (in degC) 131 ELSE 132 IF( ll_colruns ) THEN ! default value: must not be kept when calling mpp_max -> must be as small as possible 133 zmax(1:3) = -HUGE(1._wp) 134 ELSE ! default value: must not give true for any of the tests bellow (-> avoid manipulating HUGE...) 135 zmax(1:3) = 0._wp 136 ENDIF 137 ENDIF 138 zmax(4) = REAL( nstop, wp ) ! stop indicator 126 llmsk(Nis0:Nie0,Njs0:Nje0) = tmask(Nis0:Nie0,Njs0:Nje0,1) == 1._wp ! test only the inner domain 127 ! 128 ll_0oce = .NOT. ANY( llmsk(:,:) ) ! no ocean point in the inner domain? 129 ! 130 zmax(1) = MAXVAL( vt_i (:,:) , mask = llmsk ) ! max ice thickness 131 zmax(2) = MAXVAL( ABS( u_ice(:,:) ) , mask = llmsk ) ! max ice velocity (zonal only) 132 zmax(3) = MAXVAL( -tm_i (:,:) + rt0, mask = llmsk ) ! min ice temperature (in degC) 133 zmax(4) = REAL( nstop, wp ) ! stop indicator 134 ! 139 135 ! !== get global extrema ==! 140 136 ! !== done by all processes if writting run.stat ==! 141 137 IF( ll_colruns ) THEN 142 138 zmaxlocal(:) = zmax(:) 143 CALL mpp_max( "stpctl", zmax ) ! max over the global domain 139 CALL mpp_max( "stpctl", zmax ) ! max over the global domain: ok even of ll_0oce = .true. 144 140 nstop = NINT( zmax(4) ) ! update nstop indicator (now sheared among all local domains) 145 ENDIF 141 ELSE 142 ! if no ocean point: MAXVAL returns -HUGE => we must overwrite this value to avoid error handling bellow. 143 IF( ll_0oce ) zmax(1:3) = 0._wp ! default "valid" values... 144 ENDIF 145 ! 146 zmax(3) = -zmax(3) ! move back from max(-zz) to min(zz) : easier to manage! 147 IF( ll_colruns ) zmaxlocal(3) = -zmaxlocal(3) ! move back from max(-zz) to min(zz) : easier to manage! 148 ! 146 149 ! !== write "run.stat" files ==! 147 150 ! !== done only by 1st subdomain at writting timestep ==! 148 151 IF( ll_wrtruns ) THEN 149 WRITE(numrun,9500) kt, zmax(1), zmax(2), -zmax(3)150 istatus = NF90_PUT_VAR( nrunid, nvarid(1), (/ zmax(1)/), (/kt/), (/1/) )151 istatus = NF90_PUT_VAR( nrunid, nvarid(2), (/ zmax(2)/), (/kt/), (/1/) )152 istatus = NF90_PUT_VAR( nrunid, nvarid(3), (/-zmax(3)/), (/kt/), (/1/) )152 WRITE(numrun,9500) kt, zmax(1), zmax(2), zmax(3) 153 DO ji = 1, 3 154 istatus = NF90_PUT_VAR( nrunid, nvarid(ji), (/zmax(ji)/), (/kt/), (/1/) ) 155 END DO 153 156 IF( kt == nitend ) istatus = NF90_CLOSE(nrunid) 154 157 END IF … … 158 161 IF( zmax(1) > 100._wp .OR. & ! too large ice thickness maximum ( > 100 m) 159 162 & zmax(2) > 10._wp .OR. & ! too large ice velocity ( > 10 m/s) 160 & zmax(3) >101._wp .OR. & ! too cold ice temperature ( < -100 degC)163 & zmax(3) < -101._wp .OR. & ! too cold ice temperature ( < -100 degC) 161 164 & ISNAN( zmax(1) + zmax(2) + zmax(3) ) .OR. & ! NaN encounter in the tests 162 165 & ABS( zmax(1) + zmax(2) + zmax(3) ) > HUGE(1._wp) ) THEN ! Infinity encounter in the tests … … 192 195 ! 193 196 WRITE(ctmp1,*) ' stp_ctl: ice_thick > 100 m or |ice_vel| > 10 m/s or ice_temp < -100 degC or NaN encounter in the tests' 194 CALL wrt_line( ctmp2, kt, 'ice_thick max', 195 CALL wrt_line( ctmp3, kt, '|ice_vel| max', 196 CALL wrt_line( ctmp4, kt, 'ice_temp min', -zmax(3), iloc(:,3), iareasum(3), iareamin(3), iareamax(3) )197 CALL wrt_line( ctmp2, kt, 'ice_thick max', zmax(1), iloc(:,1), iareasum(1), iareamin(1), iareamax(1) ) 198 CALL wrt_line( ctmp3, kt, '|ice_vel| max', zmax(2), iloc(:,2), iareasum(2), iareamin(2), iareamax(2) ) 199 CALL wrt_line( ctmp4, kt, 'ice_temp min', zmax(3), iloc(:,3), iareasum(3), iareamin(3), iareamax(3) ) 197 200 IF( Agrif_Root() ) THEN 198 201 WRITE(ctmp6,*) ' ===> output of last computed fields in output.abort* files' -
NEMO/trunk/tests/CANAL/MY_SRC/stpctl.F90
r13458 r13616 67 67 REAL(wp) :: zzz ! local real 68 68 REAL(wp), DIMENSION(9) :: zmax, zmaxlocal 69 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns 69 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns, ll_0oce 70 70 LOGICAL, DIMENSION(jpi,jpj,jpk) :: llmsk 71 71 CHARACTER(len=20) :: clname … … 125 125 ! 126 126 llmsk(Nis0:Nie0,Njs0:Nje0,1) = ssmask(Nis0:Nie0,Njs0:Nje0) == 1._wp ! define only the inner domain 127 ! 128 ll_0oce = .NOT. ANY( llmsk(:,:,1) ) ! no ocean point in the inner domain? 129 ! 127 130 IF( ll_wd ) THEN 128 131 zmax(1) = MAXVAL( ABS( ssh(:,:,Kmm) + ssh_ref ), mask = llmsk(:,:,1) ) ! ssh max … … 149 152 ENDIF 150 153 zmax(9) = REAL( nstop, wp ) ! stop indicator 154 ! 151 155 ! !== get global extrema ==! 152 156 ! !== done by all processes if writting run.stat ==! 153 157 IF( ll_colruns ) THEN 154 158 zmaxlocal(:) = zmax(:) 155 CALL mpp_max( "stpctl", zmax ) ! max over the global domain 159 CALL mpp_max( "stpctl", zmax ) ! max over the global domain: ok even of ll_0oce = .true. 156 160 nstop = NINT( zmax(9) ) ! update nstop indicator (now sheared among all local domains) 157 ENDIF 161 ELSE 162 ! if no ocean point: MAXVAL returns -HUGE => we must overwrite this value to avoid error handling bellow. 163 IF( ll_0oce ) zmax(1:4) = (/ 0._wp, 0._wp, -1._wp, 1._wp /) ! default "valid" values... 164 ENDIF 165 ! 166 zmax(3) = -zmax(3) ! move back from max(-zz) to min(zz) : easier to manage! 167 zmax(5) = -zmax(5) ! move back from max(-zz) to min(zz) : easier to manage! 168 IF( ll_colruns ) THEN 169 zmaxlocal(3) = -zmaxlocal(3) ! move back from max(-zz) to min(zz) : easier to manage! 170 zmaxlocal(5) = -zmaxlocal(5) ! move back from max(-zz) to min(zz) : easier to manage! 171 ENDIF 172 ! 158 173 ! !== write "run.stat" files ==! 159 174 ! !== done only by 1st subdomain at writting timestep ==! 160 175 IF( ll_wrtruns ) THEN 161 WRITE(numrun,9500) kt, zmax(1), zmax(2), -zmax(3), zmax(4) 162 istatus = NF90_PUT_VAR( nrunid, nvarid(1), (/ zmax(1)/), (/kt/), (/1/) ) 163 istatus = NF90_PUT_VAR( nrunid, nvarid(2), (/ zmax(2)/), (/kt/), (/1/) ) 164 istatus = NF90_PUT_VAR( nrunid, nvarid(3), (/-zmax(3)/), (/kt/), (/1/) ) 165 istatus = NF90_PUT_VAR( nrunid, nvarid(4), (/ zmax(4)/), (/kt/), (/1/) ) 166 istatus = NF90_PUT_VAR( nrunid, nvarid(5), (/-zmax(5)/), (/kt/), (/1/) ) 167 istatus = NF90_PUT_VAR( nrunid, nvarid(6), (/ zmax(6)/), (/kt/), (/1/) ) 168 IF( ln_zad_Aimp ) THEN 169 istatus = NF90_PUT_VAR( nrunid, nvarid(7), (/ zmax(7)/), (/kt/), (/1/) ) 170 istatus = NF90_PUT_VAR( nrunid, nvarid(8), (/ zmax(8)/), (/kt/), (/1/) ) 171 ENDIF 176 WRITE(numrun,9500) kt, zmax(1), zmax(2), zmax(3), zmax(4) 177 DO ji = 1, 6 + 2 * COUNT( (/ln_zad_Aimp/) ) 178 istatus = NF90_PUT_VAR( nrunid, nvarid(ji), (/zmax(ji)/), (/kt/), (/1/) ) 179 END DO 172 180 IF( kt == nitend ) istatus = NF90_CLOSE(nrunid) 173 181 END IF … … 175 183 ! !== done by all processes at every time step ==! 176 184 ! 177 IF( 178 & 179 !!$ & zmax(3) >= 0._wp .OR. & ! negative or zero sea surface salinity180 !!$ & 181 !!$ & 182 & 183 & 185 IF( zmax(1) > 20._wp .OR. & ! too large sea surface height ( > 20 m ) 186 & zmax(2) > 10._wp .OR. & ! too large velocity ( > 10 m/s) 187 !!$ & zmax(3) <= 0._wp .OR. & ! negative or zero sea surface salinity 188 !!$ & zmax(4) >= 100._wp .OR. & ! too large sea surface salinity ( > 100 ) 189 !!$ & zmax(4) < 0._wp .OR. & ! too large sea surface salinity (keep this line for sea-ice) 190 & ISNAN( zmax(1) + zmax(2) + zmax(3) ) .OR. & ! NaN encounter in the tests 191 & ABS( zmax(1) + zmax(2) + zmax(3) ) > HUGE(1._wp) ) THEN ! Infinity encounter in the tests 184 192 ! 185 193 iloc(:,:) = 0 … … 207 215 ELSE ! find local min and max locations: 208 216 ! if we are here, this means that the subdomain contains some oce points -> no need to test the mask used in maxloc 209 llmsk(Nis0:Nie0,Njs0:Nje0,1) = ssmask(Nis0:Nie0,Njs0:Nje0 ) == 1._wp 217 llmsk(Nis0:Nie0,Njs0:Nje0,1) = ssmask(Nis0:Nie0,Njs0:Nje0 ) == 1._wp ! define only the inner domain 210 218 iloc(1:2,1) = MAXLOC( ABS( ssh(:,:, Kmm)), mask = llmsk(:,:,1) ) 211 219 llmsk(Nis0:Nie0,Njs0:Nje0,:) = umask(Nis0:Nie0,Njs0:Nje0,:) == 1._wp ! define only the inner domain … … 221 229 ! 222 230 WRITE(ctmp1,*) ' stp_ctl: |ssh| > 20 m or |U| > 10 m/s or S <= 0 or S >= 100 or NaN encounter in the tests' 223 CALL wrt_line( ctmp2, kt, '|ssh| max', 224 CALL wrt_line( ctmp3, kt, '|U| max', 225 CALL wrt_line( ctmp4, kt, 'Sal min', -zmax(3), iloc(:,3), iareasum(3), iareamin(3), iareamax(3) )226 CALL wrt_line( ctmp5, kt, 'Sal max', 231 CALL wrt_line( ctmp2, kt, '|ssh| max', zmax(1), iloc(:,1), iareasum(1), iareamin(1), iareamax(1) ) 232 CALL wrt_line( ctmp3, kt, '|U| max', zmax(2), iloc(:,2), iareasum(2), iareamin(2), iareamax(2) ) 233 CALL wrt_line( ctmp4, kt, 'Sal min', zmax(3), iloc(:,3), iareasum(3), iareamin(3), iareamax(3) ) 234 CALL wrt_line( ctmp5, kt, 'Sal max', zmax(4), iloc(:,4), iareasum(4), iareamin(4), iareamax(4) ) 227 235 IF( Agrif_Root() ) THEN 228 236 WRITE(ctmp6,*) ' ===> output of last computed fields in output.abort* files' -
NEMO/trunk/tests/STATION_ASF/MY_SRC/stpctl.F90
r13458 r13616 65 65 REAL(wp) :: zzz ! local real 66 66 REAL(wp), DIMENSION(4) :: zmax, zmaxlocal 67 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns 67 LOGICAL :: ll_wrtstp, ll_colruns, ll_wrtruns, ll_0oce 68 68 LOGICAL, DIMENSION(jpi,jpj) :: llmsk 69 69 CHARACTER(len=20) :: clname … … 115 115 llmsk(:,Nje1: jpj) = .FALSE. 116 116 ! 117 llmsk(Nis0:Nie0,Njs0:Nje0) = tmask(Nis0:Nie0,Njs0:Nje0,1) == 1._wp ! test only the inner domain 118 IF( COUNT( llmsk(:,:) ) > 0 ) THEN ! avoid huge values sent back for land processors... 119 zmax(1) = MAXVAL( taum(:,:) , mask = llmsk ) ! max wind stress module 120 zmax(2) = MAXVAL( ABS( qns(:,:) ) , mask = llmsk ) ! max non-solar heat flux 121 zmax(3) = MAXVAL( ABS( emp(:,:) ) , mask = llmsk ) ! max E-P 122 ELSE 123 IF( ll_colruns ) THEN ! default value: must not be kept when calling mpp_max -> must be as small as possible 124 zmax(1:3) = -HUGE(1._wp) 125 ELSE ! default value: must not give true for any of the tests bellow (-> avoid manipulating HUGE...) 126 zmax(1:3) = 0._wp 127 ENDIF 128 ENDIF 129 zmax(4) = REAL( nstop, wp ) ! stop indicator 117 llmsk(Nis0:Nie0,Njs0:Nje0) = tmask(Nis0:Nie0,Njs0:Nje0,1) == 1._wp ! test only the inner domain 118 ! 119 ll_0oce = .NOT. ANY( llmsk(:,:) ) ! no ocean point in the inner domain? 120 ! 121 zmax(1) = MAXVAL( taum(:,:) , mask = llmsk ) ! max wind stress module 122 zmax(2) = MAXVAL( ABS( qns(:,:) ), mask = llmsk ) ! max non-solar heat flux 123 zmax(3) = MAXVAL( ABS( emp(:,:) ), mask = llmsk ) ! max E-P 124 zmax(4) = REAL( nstop, wp ) ! stop indicator 125 ! 130 126 ! !== get global extrema ==! 131 127 ! !== done by all processes if writting run.stat ==! … … 134 130 CALL mpp_max( "stpctl", zmax ) ! max over the global domain 135 131 nstop = NINT( zmax(4) ) ! update nstop indicator (now sheared among all local domains) 136 ENDIF 132 ELSE 133 ! if no ocean point: MAXVAL returns -HUGE => we must overwrite this value to avoid error handling bellow. 134 IF( ll_0oce ) zmax(1:3) = 0._wp ! default "valid" values... 135 ENDIF 136 ! !== error handling ==! 137 137 ! !== write "run.stat" files ==! 138 138 ! !== done only by 1st subdomain at writting timestep ==! 139 139 IF( ll_wrtruns ) THEN 140 140 WRITE(numrun,9500) kt, zmax(1), zmax(2), zmax(3) 141 istatus = NF90_PUT_VAR( nrunid, nvarid(1), (/ zmax(1)/), (/kt/), (/1/) )142 istatus = NF90_PUT_VAR( nrunid, nvarid(2), (/ zmax(2)/), (/kt/), (/1/) )143 istatus = NF90_PUT_VAR( nrunid, nvarid(3), (/ zmax(3)/), (/kt/), (/1/) )141 DO ji = 1, 3 142 istatus = NF90_PUT_VAR( nrunid, nvarid(ji), (/zmax(ji)/), (/kt/), (/1/) ) 143 END DO 144 144 IF( kt == nitend ) istatus = NF90_CLOSE(nrunid) 145 145 END IF
Note: See TracChangeset
for help on using the changeset viewer.