[2663] | 1 | module check_fields_mod |
---|
| 2 | |
---|
| 3 | real,save :: default_temp_min=5. ! minimum reasonable temperature (K) |
---|
| 4 | real,save :: default_temp_max=5000. ! maximum reasonable temperature (K) |
---|
| 5 | !$OMP THREADPRIVATE(default_temp_min,default_temp_max) |
---|
| 6 | |
---|
| 7 | real,save :: default_wind_max=5000. ! maximum reasonable wind magnitude (m/s) |
---|
| 8 | !$OMP THREADPRIVATE(default_wind_max) |
---|
| 9 | |
---|
| 10 | real,save :: default_ps_min=80. ! minimum reasonable surface pressure (Pa) |
---|
| 11 | real,save :: default_ps_max=3000000. ! maximum reasonable surface pressure (Pa) |
---|
| 12 | !$OMP THREADPRIVATE(default_ps_min,default_ps_max) |
---|
| 13 | |
---|
| 14 | contains |
---|
| 15 | |
---|
| 16 | subroutine check_physics_fields(message,temp,u,v,pplev,q) |
---|
| 17 | use dimphy, only: klon, klev |
---|
| 18 | use tracer_h, only: nqtot |
---|
| 19 | use ioipsl_getin_p_mod, only: getin_p |
---|
| 20 | |
---|
| 21 | implicit none |
---|
| 22 | character(len=*),intent(in):: message ! text message for outputs |
---|
| 23 | real,intent(in) :: temp(klon,klev) |
---|
| 24 | real,intent(in) :: u(klon,klev) ! zonal wind (m/s) |
---|
| 25 | real,intent(in) :: v(klon,klev) ! meridional wind (m/s) |
---|
| 26 | real,intent(in) :: pplev(klon,klev+1) ! pressure at level interfaces (Pa) |
---|
| 27 | real,intent(in) :: q(klon,klev,nqtot) ! tracer mixing ratio (.../kg_air) |
---|
| 28 | |
---|
| 29 | character(len=50) :: name="check_physics_fields" |
---|
| 30 | logical :: ok_t,ok_w,ok_ps,ok_q |
---|
| 31 | logical, save :: firstcall = .true. |
---|
| 32 | !$OMP THREADPRIVATE(firstcall) |
---|
| 33 | |
---|
| 34 | ! 0. Get user defaults |
---|
| 35 | if (firstcall) then |
---|
| 36 | call getin_p("check_temp_min", default_temp_min) |
---|
[2873] | 37 | call getin_p("check_temp_max", default_temp_max) |
---|
[2663] | 38 | call getin_p("check_wind_max", default_wind_max) |
---|
| 39 | call getin_p("check_ps_min", default_ps_min) |
---|
| 40 | call getin_p("check_ps_max", default_ps_max) |
---|
| 41 | firstcall = .false. |
---|
| 42 | endif |
---|
| 43 | |
---|
| 44 | ! 1. Initialisations |
---|
| 45 | ok_q=.true. |
---|
| 46 | |
---|
| 47 | ! 2. Check temperature, winds and surface pressure |
---|
| 48 | call check_temperature(message,temp,ok_t) |
---|
| 49 | call check_winds(message,u,v,ok_w) |
---|
| 50 | call check_ps(message,pplev(:,1),ok_ps) |
---|
| 51 | if (nqtot>=1) then |
---|
| 52 | call check_tracers(message,q,ok_q) |
---|
| 53 | endif |
---|
| 54 | |
---|
| 55 | if ((.not.ok_t).or.(.not.ok_w).or.(.not.ok_ps).or.(.not.ok_q)) then |
---|
| 56 | ! Something is wrong, might as well stop here |
---|
| 57 | if (.not.ok_t) write(*,*) trim(name)//":"//trim(message)//"Bad temperature values" |
---|
| 58 | if (.not.ok_w) write(*,*) trim(name)//":"//trim(message)//"Bad wind values " |
---|
| 59 | if (.not.ok_ps) write(*,*) trim(name)//":"//trim(message)//"Bad surface pressure values" |
---|
| 60 | if (.not.ok_q) write(*,*) trim(name)//":"//trim(message)//"Bad tracers values" |
---|
| 61 | call abort_physic(trim(name),trim(message)//" Invalid field values",1) |
---|
| 62 | endif |
---|
| 63 | |
---|
| 64 | end subroutine check_physics_fields |
---|
| 65 | |
---|
| 66 | |
---|
| 67 | subroutine check_temperature(message,temp,ok,temp_min,temp_max) |
---|
| 68 | use dimphy, only: klon, klev |
---|
| 69 | implicit none |
---|
| 70 | character(len=*),intent(in):: message ! text message for outputs |
---|
| 71 | real,intent(in) :: temp(klon,klev) |
---|
| 72 | logical,intent(out) :: ok ! returns .true. if everything OK, .false. otherwise |
---|
| 73 | real,intent(in),optional :: temp_min ! user provided acceptable minimum |
---|
| 74 | real,intent(in),optional :: temp_max ! user provided acceptable maximum |
---|
| 75 | |
---|
| 76 | character(len=50) :: name="check_temperature" |
---|
| 77 | real :: tmin,tmax |
---|
| 78 | integer :: i,k |
---|
| 79 | |
---|
| 80 | ! 0. Check optional inputs |
---|
| 81 | if (present(temp_min)) then |
---|
| 82 | tmin=temp_min |
---|
| 83 | else |
---|
| 84 | tmin=default_temp_min |
---|
| 85 | endif |
---|
| 86 | |
---|
| 87 | if (present(temp_max)) then |
---|
| 88 | tmax=temp_max |
---|
| 89 | else |
---|
| 90 | tmax=default_temp_max |
---|
| 91 | endif |
---|
| 92 | |
---|
| 93 | ! 1. initializations |
---|
| 94 | ok=.true. |
---|
| 95 | |
---|
| 96 | ! 2. do the checking |
---|
| 97 | do i=1,klon |
---|
| 98 | do k=1,klev |
---|
| 99 | ! look for NaN |
---|
| 100 | if (temp(i,k).ne.temp(i,k)) then |
---|
| 101 | ok=.false. |
---|
| 102 | write(*,*)trim(message)//" "//trim(name)//" temp(i,k)=",temp(i,k),& |
---|
| 103 | " for i=",i," k=",k |
---|
| 104 | endif |
---|
| 105 | ! check for temperatures too low |
---|
| 106 | if (temp(i,k).lt.tmin) then |
---|
| 107 | ok=.false. |
---|
| 108 | write(*,*)trim(message)//" "//trim(name)//" temp(i,k)=",temp(i,k),& |
---|
| 109 | " for i=",i," k=",k," <",tmin |
---|
| 110 | endif |
---|
| 111 | ! check for temperatures too high |
---|
| 112 | if (temp(i,k).gt.tmax) then |
---|
| 113 | ok=.false. |
---|
| 114 | write(*,*)trim(message)//" "//trim(name)//" temp(i,k)=",temp(i,k),& |
---|
| 115 | " for i=",i," k=",k," >",tmax |
---|
| 116 | endif |
---|
| 117 | enddo |
---|
| 118 | enddo |
---|
| 119 | |
---|
| 120 | end subroutine check_temperature |
---|
| 121 | |
---|
| 122 | subroutine check_winds(message,u,v,ok,wind_max) |
---|
| 123 | use dimphy, only: klon, klev |
---|
| 124 | implicit none |
---|
| 125 | character(len=*),intent(in):: message ! text message for outputs |
---|
| 126 | real,intent(in) :: u(klon,klev) ! zonal wind (m/s) |
---|
| 127 | real,intent(in) :: v(klon,klev) ! meridional wind (m/s) |
---|
| 128 | logical,intent(out) :: ok ! returns .true. if everything OK, .false. otherwise |
---|
| 129 | real,intent(in),optional :: wind_max ! user provided acceptable maximum magnitude |
---|
| 130 | |
---|
| 131 | character(len=50) :: name="check_winds" |
---|
| 132 | real :: wmax |
---|
| 133 | integer :: i,k |
---|
| 134 | |
---|
| 135 | ! 0. Check optional inputs |
---|
| 136 | |
---|
| 137 | if (present(wind_max)) then |
---|
| 138 | wmax=wind_max |
---|
| 139 | else |
---|
| 140 | wmax=default_wind_max |
---|
| 141 | endif |
---|
| 142 | |
---|
| 143 | ! 1. initializations |
---|
| 144 | ok=.true. |
---|
| 145 | |
---|
| 146 | ! 2. do the checking |
---|
| 147 | do i=1,klon |
---|
| 148 | do k=1,klev |
---|
| 149 | ! look for NaN |
---|
| 150 | if (u(i,k).ne.u(i,k)) then |
---|
| 151 | ok=.false. |
---|
| 152 | write(*,*)trim(message)//" "//trim(name)//" u(i,k)=",u(i,k),& |
---|
| 153 | " for i=",i," k=",k |
---|
| 154 | endif |
---|
| 155 | if (v(i,k).ne.v(i,k)) then |
---|
| 156 | ok=.false. |
---|
| 157 | write(*,*)trim(message)//" "//trim(name)//" v(i,k)=",v(i,k),& |
---|
| 158 | " for i=",i," k=",k |
---|
| 159 | endif |
---|
| 160 | ! check for magnitudes too high |
---|
| 161 | if (abs(u(i,k)).gt.wmax) then |
---|
| 162 | ok=.false. |
---|
| 163 | write(*,*)trim(message)//" "//trim(name)//" u(i,k)=",u(i,k),& |
---|
| 164 | " for i=",i," k=",k," >",wmax |
---|
| 165 | endif |
---|
| 166 | if (abs(v(i,k)).gt.wmax) then |
---|
| 167 | ok=.false. |
---|
| 168 | write(*,*)trim(message)//" "//trim(name)//" v(i,k)=",v(i,k),& |
---|
| 169 | " for i=",i," k=",k," >",wmax |
---|
| 170 | endif |
---|
| 171 | enddo |
---|
| 172 | enddo |
---|
| 173 | |
---|
| 174 | end subroutine check_winds |
---|
| 175 | |
---|
| 176 | subroutine check_ps(message,ps,ok,ps_min,ps_max) |
---|
| 177 | use dimphy, only: klon |
---|
| 178 | implicit none |
---|
| 179 | character(len=*),intent(in):: message ! text message for outputs |
---|
| 180 | real,intent(in) :: ps(klon) |
---|
| 181 | logical,intent(out) :: ok ! returns .true. if everything OK, .false. otherwise |
---|
| 182 | real,intent(in),optional :: ps_min ! user provided acceptable minimum |
---|
| 183 | real,intent(in),optional :: ps_max ! user provided acceptable maximum |
---|
| 184 | |
---|
| 185 | character(len=50) :: name="check_ps" |
---|
| 186 | real :: pmin,pmax |
---|
| 187 | integer :: i |
---|
| 188 | |
---|
| 189 | ! 0. Check optional inputs |
---|
| 190 | if (present(ps_min)) then |
---|
| 191 | pmin=ps_min |
---|
| 192 | else |
---|
| 193 | pmin=default_ps_min |
---|
| 194 | endif |
---|
| 195 | |
---|
| 196 | if (present(ps_max)) then |
---|
| 197 | pmax=ps_max |
---|
| 198 | else |
---|
| 199 | pmax=default_ps_max |
---|
| 200 | endif |
---|
| 201 | |
---|
| 202 | ! 1. initializations |
---|
| 203 | ok=.true. |
---|
| 204 | |
---|
| 205 | ! 2. do the checking |
---|
| 206 | do i=1,klon |
---|
| 207 | ! look for NaN |
---|
| 208 | if (ps(i).ne.ps(i)) then |
---|
| 209 | ok=.false. |
---|
| 210 | write(*,*)trim(message)//" "//trim(name)//" ps(i)=",ps(i)," for i=",i |
---|
| 211 | endif |
---|
| 212 | ! check for pressures too low |
---|
| 213 | if (ps(i).lt.pmin) then |
---|
| 214 | ok=.false. |
---|
| 215 | write(*,*)trim(message)//" "//trim(name)//" ps(i)=",ps(i)," for i=",i,& |
---|
| 216 | " <",pmin |
---|
| 217 | endif |
---|
| 218 | ! check for pressures too high |
---|
| 219 | if (ps(i).gt.pmax) then |
---|
| 220 | ok=.false. |
---|
| 221 | write(*,*)trim(message)//" "//trim(name)//" ps(i)=",ps(i)," for i=",i,& |
---|
| 222 | " >",pmax |
---|
| 223 | endif |
---|
| 224 | enddo |
---|
| 225 | |
---|
| 226 | end subroutine check_ps |
---|
| 227 | |
---|
| 228 | subroutine check_tracers(message,q,ok) |
---|
| 229 | use dimphy, only: klon, klev |
---|
| 230 | use tracer_h, only: nqtot,noms |
---|
| 231 | implicit none |
---|
| 232 | character(len=*),intent(in):: message ! text message for outputs |
---|
| 233 | real,intent(in) :: q(klon,klev,nqtot) ! tracer mixing ratio |
---|
| 234 | logical,intent(inout) :: ok ! set to .false. if something is wrong |
---|
| 235 | |
---|
| 236 | character(len=50) :: name="check_tracers" |
---|
| 237 | integer :: i,k,iq |
---|
| 238 | integer :: nb_bad_neg ! number of problematic points (negative values) |
---|
| 239 | integer :: nb_bad_nan ! number of problematic points (NaNs) |
---|
| 240 | |
---|
| 241 | ! 1. initializations |
---|
| 242 | nb_bad_nan=0 |
---|
| 243 | |
---|
| 244 | ! 2. do the checking |
---|
| 245 | do iq=1,nqtot |
---|
| 246 | nb_bad_neg=0 ! initialize |
---|
| 247 | do i=1,klon |
---|
| 248 | do k=1,klev |
---|
| 249 | ! look for NaN |
---|
| 250 | if (q(i,k,iq).ne.q(i,k,iq)) then |
---|
| 251 | ok=.false. |
---|
| 252 | nb_bad_nan=nb_bad_nan+1 |
---|
| 253 | endif |
---|
| 254 | ! look for negative values |
---|
| 255 | if (q(i,k,iq).lt.0) then |
---|
| 256 | ! ok=.false. |
---|
| 257 | nb_bad_neg=nb_bad_neg+1 |
---|
| 258 | endif |
---|
| 259 | enddo |
---|
| 260 | enddo |
---|
| 261 | if (nb_bad_neg>0) then |
---|
| 262 | write(*,*)trim(message)//" "//trim(name)//" tracer "//trim(noms(iq))//& |
---|
| 263 | " contains ",nb_bad_neg," negative values!" |
---|
| 264 | endif |
---|
| 265 | enddo !of do iq=1,nqtot |
---|
| 266 | |
---|
| 267 | end subroutine check_tracers |
---|
| 268 | |
---|
| 269 | end module check_fields_mod |
---|