obs_oper.F90 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442
  1. MODULE obs_oper
  2. !!======================================================================
  3. !! *** MODULE obs_oper ***
  4. !! Observation diagnostics: Observation operators for various observation
  5. !! types
  6. !!======================================================================
  7. !!----------------------------------------------------------------------
  8. !! obs_pro_opt : Compute the model counterpart of temperature and
  9. !! salinity observations from profiles
  10. !! obs_sla_opt : Compute the model counterpart of sea level anomaly
  11. !! observations
  12. !! obs_sst_opt : Compute the model counterpart of sea surface temperature
  13. !! observations
  14. !! obs_sss_opt : Compute the model counterpart of sea surface salinity
  15. !! observations
  16. !! obs_seaice_opt : Compute the model counterpart of sea ice concentration
  17. !! observations
  18. !!
  19. !! obs_vel_opt : Compute the model counterpart of zonal and meridional
  20. !! components of velocity from observations.
  21. !!----------------------------------------------------------------------
  22. !! * Modules used
  23. USE par_kind, ONLY : & ! Precision variables
  24. & wp
  25. USE in_out_manager ! I/O manager
  26. USE obs_inter_sup ! Interpolation support
  27. USE obs_inter_h2d, ONLY : & ! Horizontal interpolation to the observation pt
  28. & obs_int_h2d, &
  29. & obs_int_h2d_init
  30. USE obs_inter_z1d, ONLY : & ! Vertical interpolation to the observation pt
  31. & obs_int_z1d, &
  32. & obs_int_z1d_spl
  33. USE obs_const, ONLY : &
  34. & obfillflt ! Fillvalue
  35. USE dom_oce, ONLY : &
  36. & glamt, glamu, glamv, &
  37. & gphit, gphiu, gphiv
  38. USE lib_mpp, ONLY : &
  39. & ctl_warn, ctl_stop
  40. IMPLICIT NONE
  41. !! * Routine accessibility
  42. PRIVATE
  43. PUBLIC obs_pro_opt, & ! Compute the model counterpart of profile observations
  44. & obs_sla_opt, & ! Compute the model counterpart of SLA observations
  45. & obs_sst_opt, & ! Compute the model counterpart of SST observations
  46. & obs_sss_opt, & ! Compute the model counterpart of SSS observations
  47. & obs_seaice_opt, &
  48. & obs_vel_opt ! Compute the model counterpart of velocity profile data
  49. INTEGER, PARAMETER, PUBLIC :: imaxavtypes = 20 ! Max number of daily avgd obs types
  50. !!----------------------------------------------------------------------
  51. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  52. !! $Id: obs_oper.F90 4245 2013-11-19 11:19:21Z cetlod $
  53. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  54. !!----------------------------------------------------------------------
  55. CONTAINS
  56. SUBROUTINE obs_pro_opt( prodatqc, kt, kpi, kpj, kpk, kit000, kdaystp, &
  57. & ptn, psn, pgdept, ptmask, k1dint, k2dint, &
  58. & kdailyavtypes )
  59. !!-----------------------------------------------------------------------
  60. !!
  61. !! *** ROUTINE obs_pro_opt ***
  62. !!
  63. !! ** Purpose : Compute the model counterpart of profiles
  64. !! data by interpolating from the model grid to the
  65. !! observation point.
  66. !!
  67. !! ** Method : Linearly interpolate to each observation point using
  68. !! the model values at the corners of the surrounding grid box.
  69. !!
  70. !! First, a vertical profile of horizontally interpolated model
  71. !! now temperatures is computed at the obs (lon, lat) point.
  72. !! Several horizontal interpolation schemes are available:
  73. !! - distance-weighted (great circle) (k2dint = 0)
  74. !! - distance-weighted (small angle) (k2dint = 1)
  75. !! - bilinear (geographical grid) (k2dint = 2)
  76. !! - bilinear (quadrilateral grid) (k2dint = 3)
  77. !! - polynomial (quadrilateral grid) (k2dint = 4)
  78. !!
  79. !! Next, the vertical temperature profile is interpolated to the
  80. !! data depth points. Two vertical interpolation schemes are
  81. !! available:
  82. !! - linear (k1dint = 0)
  83. !! - Cubic spline (k1dint = 1)
  84. !!
  85. !! For the cubic spline the 2nd derivative of the interpolating
  86. !! polynomial is computed before entering the vertical interpolation
  87. !! routine.
  88. !!
  89. !! For ENACT moored buoy data (e.g., TAO), the model equivalent is
  90. !! a daily mean model temperature field. So, we first compute
  91. !! the mean, then interpolate only at the end of the day.
  92. !!
  93. !! Note: the in situ temperature observations must be converted
  94. !! to potential temperature (the model variable) prior to
  95. !! assimilation.
  96. !!??????????????????????????????????????????????????????????????
  97. !! INCLUDE POTENTIAL TEMP -> IN SITU TEMP IN OBS OPERATOR???
  98. !!??????????????????????????????????????????????????????????????
  99. !!
  100. !! ** Action :
  101. !!
  102. !! History :
  103. !! ! 97-11 (A. Weaver, S. Ricci, N. Daget)
  104. !! ! 06-03 (G. Smith) NEMOVAR migration
  105. !! ! 06-10 (A. Weaver) Cleanup
  106. !! ! 07-01 (K. Mogensen) Merge of temperature and salinity
  107. !! ! 07-03 (K. Mogensen) General handling of profiles
  108. !!-----------------------------------------------------------------------
  109. !! * Modules used
  110. USE obs_profiles_def ! Definition of storage space for profile obs.
  111. IMPLICIT NONE
  112. !! * Arguments
  113. TYPE(obs_prof), INTENT(INOUT) :: prodatqc ! Subset of profile data not failing screening
  114. INTEGER, INTENT(IN) :: kt ! Time step
  115. INTEGER, INTENT(IN) :: kpi ! Model grid parameters
  116. INTEGER, INTENT(IN) :: kpj
  117. INTEGER, INTENT(IN) :: kpk
  118. INTEGER, INTENT(IN) :: kit000 ! Number of the first time step
  119. ! (kit000-1 = restart time)
  120. INTEGER, INTENT(IN) :: k1dint ! Vertical interpolation type (see header)
  121. INTEGER, INTENT(IN) :: k2dint ! Horizontal interpolation type (see header)
  122. INTEGER, INTENT(IN) :: kdaystp ! Number of time steps per day
  123. REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj,kpk) :: &
  124. & ptn, & ! Model temperature field
  125. & psn, & ! Model salinity field
  126. & ptmask ! Land-sea mask
  127. REAL(KIND=wp), INTENT(IN), DIMENSION(kpk) :: &
  128. & pgdept ! Model array of depth levels
  129. INTEGER, DIMENSION(imaxavtypes), OPTIONAL :: &
  130. & kdailyavtypes! Types for daily averages
  131. !! * Local declarations
  132. INTEGER :: ji
  133. INTEGER :: jj
  134. INTEGER :: jk
  135. INTEGER :: jobs
  136. INTEGER :: inrc
  137. INTEGER :: ipro
  138. INTEGER :: idayend
  139. INTEGER :: ista
  140. INTEGER :: iend
  141. INTEGER :: iobs
  142. INTEGER, DIMENSION(imaxavtypes) :: &
  143. & idailyavtypes
  144. REAL(KIND=wp) :: zlam
  145. REAL(KIND=wp) :: zphi
  146. REAL(KIND=wp) :: zdaystp
  147. REAL(KIND=wp), DIMENSION(kpk) :: &
  148. & zobsmask, &
  149. & zobsk, &
  150. & zobs2k
  151. REAL(KIND=wp), DIMENSION(2,2,kpk) :: &
  152. & zweig
  153. REAL(wp), DIMENSION(:,:,:,:), ALLOCATABLE :: &
  154. & zmask, &
  155. & zintt, &
  156. & zints, &
  157. & zinmt, &
  158. & zinms
  159. REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
  160. & zglam, &
  161. & zgphi
  162. INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
  163. & igrdi, &
  164. & igrdj
  165. !------------------------------------------------------------------------
  166. ! Local initialization
  167. !------------------------------------------------------------------------
  168. ! ... Record and data counters
  169. inrc = kt - kit000 + 2
  170. ipro = prodatqc%npstp(inrc)
  171. ! Daily average types
  172. IF ( PRESENT(kdailyavtypes) ) THEN
  173. idailyavtypes(:) = kdailyavtypes(:)
  174. ELSE
  175. idailyavtypes(:) = -1
  176. ENDIF
  177. ! Initialize daily mean for first timestep
  178. idayend = MOD( kt - kit000 + 1, kdaystp )
  179. ! Added kt == 0 test to catch restart case
  180. IF ( idayend == 1 .OR. kt == 0) THEN
  181. IF (lwp) WRITE(numout,*) 'Reset prodatqc%vdmean on time-step: ',kt
  182. DO jk = 1, jpk
  183. DO jj = 1, jpj
  184. DO ji = 1, jpi
  185. prodatqc%vdmean(ji,jj,jk,1) = 0.0
  186. prodatqc%vdmean(ji,jj,jk,2) = 0.0
  187. END DO
  188. END DO
  189. END DO
  190. ENDIF
  191. DO jk = 1, jpk
  192. DO jj = 1, jpj
  193. DO ji = 1, jpi
  194. ! Increment the temperature field for computing daily mean
  195. prodatqc%vdmean(ji,jj,jk,1) = prodatqc%vdmean(ji,jj,jk,1) &
  196. & + ptn(ji,jj,jk)
  197. ! Increment the salinity field for computing daily mean
  198. prodatqc%vdmean(ji,jj,jk,2) = prodatqc%vdmean(ji,jj,jk,2) &
  199. & + psn(ji,jj,jk)
  200. END DO
  201. END DO
  202. END DO
  203. ! Compute the daily mean at the end of day
  204. zdaystp = 1.0 / REAL( kdaystp )
  205. IF ( idayend == 0 ) THEN
  206. DO jk = 1, jpk
  207. DO jj = 1, jpj
  208. DO ji = 1, jpi
  209. prodatqc%vdmean(ji,jj,jk,1) = prodatqc%vdmean(ji,jj,jk,1) &
  210. & * zdaystp
  211. prodatqc%vdmean(ji,jj,jk,2) = prodatqc%vdmean(ji,jj,jk,2) &
  212. & * zdaystp
  213. END DO
  214. END DO
  215. END DO
  216. ENDIF
  217. ! Get the data for interpolation
  218. ALLOCATE( &
  219. & igrdi(2,2,ipro), &
  220. & igrdj(2,2,ipro), &
  221. & zglam(2,2,ipro), &
  222. & zgphi(2,2,ipro), &
  223. & zmask(2,2,kpk,ipro), &
  224. & zintt(2,2,kpk,ipro), &
  225. & zints(2,2,kpk,ipro) &
  226. & )
  227. DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
  228. iobs = jobs - prodatqc%nprofup
  229. igrdi(1,1,iobs) = prodatqc%mi(jobs,1)-1
  230. igrdj(1,1,iobs) = prodatqc%mj(jobs,1)-1
  231. igrdi(1,2,iobs) = prodatqc%mi(jobs,1)-1
  232. igrdj(1,2,iobs) = prodatqc%mj(jobs,1)
  233. igrdi(2,1,iobs) = prodatqc%mi(jobs,1)
  234. igrdj(2,1,iobs) = prodatqc%mj(jobs,1)-1
  235. igrdi(2,2,iobs) = prodatqc%mi(jobs,1)
  236. igrdj(2,2,iobs) = prodatqc%mj(jobs,1)
  237. END DO
  238. CALL obs_int_comm_2d( 2, 2, ipro, igrdi, igrdj, glamt, zglam )
  239. CALL obs_int_comm_2d( 2, 2, ipro, igrdi, igrdj, gphit, zgphi )
  240. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdi, igrdj, ptmask,zmask )
  241. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdi, igrdj, ptn, zintt )
  242. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdi, igrdj, psn, zints )
  243. ! At the end of the day also get interpolated means
  244. IF ( idayend == 0 ) THEN
  245. ALLOCATE( &
  246. & zinmt(2,2,kpk,ipro), &
  247. & zinms(2,2,kpk,ipro) &
  248. & )
  249. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdi, igrdj, &
  250. & prodatqc%vdmean(:,:,:,1), zinmt )
  251. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdi, igrdj, &
  252. & prodatqc%vdmean(:,:,:,2), zinms )
  253. ENDIF
  254. DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
  255. iobs = jobs - prodatqc%nprofup
  256. IF ( kt /= prodatqc%mstp(jobs) ) THEN
  257. IF(lwp) THEN
  258. WRITE(numout,*)
  259. WRITE(numout,*) ' E R R O R : Observation', &
  260. & ' time step is not consistent with the', &
  261. & ' model time step'
  262. WRITE(numout,*) ' ========='
  263. WRITE(numout,*)
  264. WRITE(numout,*) ' Record = ', jobs, &
  265. & ' kt = ', kt, &
  266. & ' mstp = ', prodatqc%mstp(jobs), &
  267. & ' ntyp = ', prodatqc%ntyp(jobs)
  268. ENDIF
  269. CALL ctl_stop( 'obs_pro_opt', 'Inconsistent time' )
  270. ENDIF
  271. zlam = prodatqc%rlam(jobs)
  272. zphi = prodatqc%rphi(jobs)
  273. ! Horizontal weights and vertical mask
  274. IF ( ( prodatqc%npvend(jobs,1) > 0 ) .OR. &
  275. & ( prodatqc%npvend(jobs,2) > 0 ) ) THEN
  276. CALL obs_int_h2d_init( kpk, kpk, k2dint, zlam, zphi, &
  277. & zglam(:,:,iobs), zgphi(:,:,iobs), &
  278. & zmask(:,:,:,iobs), zweig, zobsmask )
  279. ENDIF
  280. IF ( prodatqc%npvend(jobs,1) > 0 ) THEN
  281. zobsk(:) = obfillflt
  282. IF ( ANY (idailyavtypes(:) == prodatqc%ntyp(jobs)) ) THEN
  283. IF ( idayend == 0 ) THEN
  284. ! Daily averaged moored buoy (MRB) data
  285. CALL obs_int_h2d( kpk, kpk, &
  286. & zweig, zinmt(:,:,:,iobs), zobsk )
  287. ELSE
  288. CALL ctl_stop( ' A nonzero' // &
  289. & ' number of profile T BUOY data should' // &
  290. & ' only occur at the end of a given day' )
  291. ENDIF
  292. ELSE
  293. ! Point data
  294. CALL obs_int_h2d( kpk, kpk, &
  295. & zweig, zintt(:,:,:,iobs), zobsk )
  296. ENDIF
  297. !-------------------------------------------------------------
  298. ! Compute vertical second-derivative of the interpolating
  299. ! polynomial at obs points
  300. !-------------------------------------------------------------
  301. IF ( k1dint == 1 ) THEN
  302. CALL obs_int_z1d_spl( kpk, zobsk, zobs2k, &
  303. & pgdept, zobsmask )
  304. ENDIF
  305. !-----------------------------------------------------------------
  306. ! Vertical interpolation to the observation point
  307. !-----------------------------------------------------------------
  308. ista = prodatqc%npvsta(jobs,1)
  309. iend = prodatqc%npvend(jobs,1)
  310. CALL obs_int_z1d( kpk, &
  311. & prodatqc%var(1)%mvk(ista:iend), &
  312. & k1dint, iend - ista + 1, &
  313. & prodatqc%var(1)%vdep(ista:iend), &
  314. & zobsk, zobs2k, &
  315. & prodatqc%var(1)%vmod(ista:iend), &
  316. & pgdept, zobsmask )
  317. ENDIF
  318. IF ( prodatqc%npvend(jobs,2) > 0 ) THEN
  319. zobsk(:) = obfillflt
  320. IF ( ANY (idailyavtypes(:) == prodatqc%ntyp(jobs)) ) THEN
  321. IF ( idayend == 0 ) THEN
  322. ! Daily averaged moored buoy (MRB) data
  323. CALL obs_int_h2d( kpk, kpk, &
  324. & zweig, zinms(:,:,:,iobs), zobsk )
  325. ELSE
  326. CALL ctl_stop( ' A nonzero' // &
  327. & ' number of profile S BUOY data should' // &
  328. & ' only occur at the end of a given day' )
  329. ENDIF
  330. ELSE
  331. ! Point data
  332. CALL obs_int_h2d( kpk, kpk, &
  333. & zweig, zints(:,:,:,iobs), zobsk )
  334. ENDIF
  335. !-------------------------------------------------------------
  336. ! Compute vertical second-derivative of the interpolating
  337. ! polynomial at obs points
  338. !-------------------------------------------------------------
  339. IF ( k1dint == 1 ) THEN
  340. CALL obs_int_z1d_spl( kpk, zobsk, zobs2k, &
  341. & pgdept, zobsmask )
  342. ENDIF
  343. !----------------------------------------------------------------
  344. ! Vertical interpolation to the observation point
  345. !----------------------------------------------------------------
  346. ista = prodatqc%npvsta(jobs,2)
  347. iend = prodatqc%npvend(jobs,2)
  348. CALL obs_int_z1d( kpk, &
  349. & prodatqc%var(2)%mvk(ista:iend),&
  350. & k1dint, iend - ista + 1, &
  351. & prodatqc%var(2)%vdep(ista:iend),&
  352. & zobsk, zobs2k, &
  353. & prodatqc%var(2)%vmod(ista:iend),&
  354. & pgdept, zobsmask )
  355. ENDIF
  356. END DO
  357. ! Deallocate the data for interpolation
  358. DEALLOCATE( &
  359. & igrdi, &
  360. & igrdj, &
  361. & zglam, &
  362. & zgphi, &
  363. & zmask, &
  364. & zintt, &
  365. & zints &
  366. & )
  367. ! At the end of the day also get interpolated means
  368. IF ( idayend == 0 ) THEN
  369. DEALLOCATE( &
  370. & zinmt, &
  371. & zinms &
  372. & )
  373. ENDIF
  374. prodatqc%nprofup = prodatqc%nprofup + ipro
  375. END SUBROUTINE obs_pro_opt
  376. SUBROUTINE obs_sla_opt( sladatqc, kt, kpi, kpj, kit000, &
  377. & psshn, psshmask, k2dint )
  378. !!-----------------------------------------------------------------------
  379. !!
  380. !! *** ROUTINE obs_sla_opt ***
  381. !!
  382. !! ** Purpose : Compute the model counterpart of sea level anomaly
  383. !! data by interpolating from the model grid to the
  384. !! observation point.
  385. !!
  386. !! ** Method : Linearly interpolate to each observation point using
  387. !! the model values at the corners of the surrounding grid box.
  388. !!
  389. !! The now model SSH is first computed at the obs (lon, lat) point.
  390. !!
  391. !! Several horizontal interpolation schemes are available:
  392. !! - distance-weighted (great circle) (k2dint = 0)
  393. !! - distance-weighted (small angle) (k2dint = 1)
  394. !! - bilinear (geographical grid) (k2dint = 2)
  395. !! - bilinear (quadrilateral grid) (k2dint = 3)
  396. !! - polynomial (quadrilateral grid) (k2dint = 4)
  397. !!
  398. !! The sea level anomaly at the observation points is then computed
  399. !! by removing a mean dynamic topography (defined at the obs. point).
  400. !!
  401. !! ** Action :
  402. !!
  403. !! History :
  404. !! ! 07-03 (A. Weaver)
  405. !!-----------------------------------------------------------------------
  406. !! * Modules used
  407. USE obs_surf_def ! Definition of storage space for surface observations
  408. IMPLICIT NONE
  409. !! * Arguments
  410. TYPE(obs_surf), INTENT(INOUT) :: sladatqc ! Subset of surface data not failing screening
  411. INTEGER, INTENT(IN) :: kt ! Time step
  412. INTEGER, INTENT(IN) :: kpi ! Model grid parameters
  413. INTEGER, INTENT(IN) :: kpj
  414. INTEGER, INTENT(IN) :: kit000 ! Number of the first time step
  415. ! (kit000-1 = restart time)
  416. INTEGER, INTENT(IN) :: k2dint ! Horizontal interpolation type (see header)
  417. REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
  418. & psshn, & ! Model SSH field
  419. & psshmask ! Land-sea mask
  420. !! * Local declarations
  421. INTEGER :: ji
  422. INTEGER :: jj
  423. INTEGER :: jobs
  424. INTEGER :: inrc
  425. INTEGER :: isla
  426. INTEGER :: iobs
  427. REAL(KIND=wp) :: zlam
  428. REAL(KIND=wp) :: zphi
  429. REAL(KIND=wp) :: zext(1), zobsmask(1)
  430. REAL(kind=wp), DIMENSION(2,2,1) :: &
  431. & zweig
  432. REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
  433. & zmask, &
  434. & zsshl, &
  435. & zglam, &
  436. & zgphi
  437. INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
  438. & igrdi, &
  439. & igrdj
  440. !------------------------------------------------------------------------
  441. ! Local initialization
  442. !------------------------------------------------------------------------
  443. ! ... Record and data counters
  444. inrc = kt - kit000 + 2
  445. isla = sladatqc%nsstp(inrc)
  446. ! Get the data for interpolation
  447. ALLOCATE( &
  448. & igrdi(2,2,isla), &
  449. & igrdj(2,2,isla), &
  450. & zglam(2,2,isla), &
  451. & zgphi(2,2,isla), &
  452. & zmask(2,2,isla), &
  453. & zsshl(2,2,isla) &
  454. & )
  455. DO jobs = sladatqc%nsurfup + 1, sladatqc%nsurfup + isla
  456. iobs = jobs - sladatqc%nsurfup
  457. igrdi(1,1,iobs) = sladatqc%mi(jobs)-1
  458. igrdj(1,1,iobs) = sladatqc%mj(jobs)-1
  459. igrdi(1,2,iobs) = sladatqc%mi(jobs)-1
  460. igrdj(1,2,iobs) = sladatqc%mj(jobs)
  461. igrdi(2,1,iobs) = sladatqc%mi(jobs)
  462. igrdj(2,1,iobs) = sladatqc%mj(jobs)-1
  463. igrdi(2,2,iobs) = sladatqc%mi(jobs)
  464. igrdj(2,2,iobs) = sladatqc%mj(jobs)
  465. END DO
  466. CALL obs_int_comm_2d( 2, 2, isla, &
  467. & igrdi, igrdj, glamt, zglam )
  468. CALL obs_int_comm_2d( 2, 2, isla, &
  469. & igrdi, igrdj, gphit, zgphi )
  470. CALL obs_int_comm_2d( 2, 2, isla, &
  471. & igrdi, igrdj, psshmask, zmask )
  472. CALL obs_int_comm_2d( 2, 2, isla, &
  473. & igrdi, igrdj, psshn, zsshl )
  474. ! Loop over observations
  475. DO jobs = sladatqc%nsurfup + 1, sladatqc%nsurfup + isla
  476. iobs = jobs - sladatqc%nsurfup
  477. IF ( kt /= sladatqc%mstp(jobs) ) THEN
  478. IF(lwp) THEN
  479. WRITE(numout,*)
  480. WRITE(numout,*) ' E R R O R : Observation', &
  481. & ' time step is not consistent with the', &
  482. & ' model time step'
  483. WRITE(numout,*) ' ========='
  484. WRITE(numout,*)
  485. WRITE(numout,*) ' Record = ', jobs, &
  486. & ' kt = ', kt, &
  487. & ' mstp = ', sladatqc%mstp(jobs), &
  488. & ' ntyp = ', sladatqc%ntyp(jobs)
  489. ENDIF
  490. CALL ctl_stop( 'obs_sla_opt', 'Inconsistent time' )
  491. ENDIF
  492. zlam = sladatqc%rlam(jobs)
  493. zphi = sladatqc%rphi(jobs)
  494. ! Get weights to interpolate the model SSH to the observation point
  495. CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi, &
  496. & zglam(:,:,iobs), zgphi(:,:,iobs), &
  497. & zmask(:,:,iobs), zweig, zobsmask )
  498. ! Interpolate the model SSH to the observation point
  499. CALL obs_int_h2d( 1, 1, &
  500. & zweig, zsshl(:,:,iobs), zext )
  501. sladatqc%rext(jobs,1) = zext(1)
  502. ! ... Remove the MDT at the observation point
  503. sladatqc%rmod(jobs,1) = sladatqc%rext(jobs,1) - sladatqc%rext(jobs,2)
  504. END DO
  505. ! Deallocate the data for interpolation
  506. DEALLOCATE( &
  507. & igrdi, &
  508. & igrdj, &
  509. & zglam, &
  510. & zgphi, &
  511. & zmask, &
  512. & zsshl &
  513. & )
  514. sladatqc%nsurfup = sladatqc%nsurfup + isla
  515. END SUBROUTINE obs_sla_opt
  516. SUBROUTINE obs_sst_opt( sstdatqc, kt, kpi, kpj, kit000, kdaystp, &
  517. & psstn, psstmask, k2dint, ld_nightav )
  518. !!-----------------------------------------------------------------------
  519. !!
  520. !! *** ROUTINE obs_sst_opt ***
  521. !!
  522. !! ** Purpose : Compute the model counterpart of surface temperature
  523. !! data by interpolating from the model grid to the
  524. !! observation point.
  525. !!
  526. !! ** Method : Linearly interpolate to each observation point using
  527. !! the model values at the corners of the surrounding grid box.
  528. !!
  529. !! The now model SST is first computed at the obs (lon, lat) point.
  530. !!
  531. !! Several horizontal interpolation schemes are available:
  532. !! - distance-weighted (great circle) (k2dint = 0)
  533. !! - distance-weighted (small angle) (k2dint = 1)
  534. !! - bilinear (geographical grid) (k2dint = 2)
  535. !! - bilinear (quadrilateral grid) (k2dint = 3)
  536. !! - polynomial (quadrilateral grid) (k2dint = 4)
  537. !!
  538. !!
  539. !! ** Action :
  540. !!
  541. !! History :
  542. !! ! 07-07 (S. Ricci ) : Original
  543. !!
  544. !!-----------------------------------------------------------------------
  545. !! * Modules used
  546. USE obs_surf_def ! Definition of storage space for surface observations
  547. USE sbcdcy
  548. IMPLICIT NONE
  549. !! * Arguments
  550. TYPE(obs_surf), INTENT(INOUT) :: &
  551. & sstdatqc ! Subset of surface data not failing screening
  552. INTEGER, INTENT(IN) :: kt ! Time step
  553. INTEGER, INTENT(IN) :: kpi ! Model grid parameters
  554. INTEGER, INTENT(IN) :: kpj
  555. INTEGER, INTENT(IN) :: kit000 ! Number of the first time step
  556. ! (kit000-1 = restart time)
  557. INTEGER, INTENT(IN) :: k2dint ! Horizontal interpolation type (see header)
  558. INTEGER, INTENT(IN) :: kdaystp ! Number of time steps per day
  559. REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
  560. & psstn, & ! Model SST field
  561. & psstmask ! Land-sea mask
  562. !! * Local declarations
  563. INTEGER :: ji
  564. INTEGER :: jj
  565. INTEGER :: jobs
  566. INTEGER :: inrc
  567. INTEGER :: isst
  568. INTEGER :: iobs
  569. INTEGER :: idayend
  570. REAL(KIND=wp) :: zlam
  571. REAL(KIND=wp) :: zphi
  572. REAL(KIND=wp) :: zext(1), zobsmask(1)
  573. REAL(KIND=wp) :: zdaystp
  574. INTEGER, DIMENSION(:,:), SAVE, ALLOCATABLE :: &
  575. & icount_sstnight, &
  576. & imask_night
  577. REAL(kind=wp), DIMENSION(:,:), SAVE, ALLOCATABLE :: &
  578. & zintmp, &
  579. & zouttmp, &
  580. & zmeanday ! to compute model sst in region of 24h daylight (pole)
  581. REAL(kind=wp), DIMENSION(2,2,1) :: &
  582. & zweig
  583. REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
  584. & zmask, &
  585. & zsstl, &
  586. & zsstm, &
  587. & zglam, &
  588. & zgphi
  589. INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
  590. & igrdi, &
  591. & igrdj
  592. LOGICAL, INTENT(IN) :: ld_nightav
  593. !-----------------------------------------------------------------------
  594. ! Local initialization
  595. !-----------------------------------------------------------------------
  596. ! ... Record and data counters
  597. inrc = kt - kit000 + 2
  598. isst = sstdatqc%nsstp(inrc)
  599. IF ( ld_nightav ) THEN
  600. ! Initialize array for night mean
  601. IF ( kt .EQ. 0 ) THEN
  602. ALLOCATE ( icount_sstnight(kpi,kpj) )
  603. ALLOCATE ( imask_night(kpi,kpj) )
  604. ALLOCATE ( zintmp(kpi,kpj) )
  605. ALLOCATE ( zouttmp(kpi,kpj) )
  606. ALLOCATE ( zmeanday(kpi,kpj) )
  607. nday_qsr = -1 ! initialisation flag for nbc_dcy
  608. ENDIF
  609. ! Initialize daily mean for first timestep
  610. idayend = MOD( kt - kit000 + 1, kdaystp )
  611. ! Added kt == 0 test to catch restart case
  612. IF ( idayend == 1 .OR. kt == 0) THEN
  613. IF (lwp) WRITE(numout,*) 'Reset sstdatqc%vdmean on time-step: ',kt
  614. DO jj = 1, jpj
  615. DO ji = 1, jpi
  616. sstdatqc%vdmean(ji,jj) = 0.0
  617. zmeanday(ji,jj) = 0.0
  618. icount_sstnight(ji,jj) = 0
  619. END DO
  620. END DO
  621. ENDIF
  622. zintmp(:,:) = 0.0
  623. zouttmp(:,:) = sbc_dcy( zintmp(:,:), .TRUE. )
  624. imask_night(:,:) = INT( zouttmp(:,:) )
  625. DO jj = 1, jpj
  626. DO ji = 1, jpi
  627. ! Increment the temperature field for computing night mean and counter
  628. sstdatqc%vdmean(ji,jj) = sstdatqc%vdmean(ji,jj) &
  629. & + psstn(ji,jj)*imask_night(ji,jj)
  630. zmeanday(ji,jj) = zmeanday(ji,jj) + psstn(ji,jj)
  631. icount_sstnight(ji,jj) = icount_sstnight(ji,jj) + imask_night(ji,jj)
  632. END DO
  633. END DO
  634. ! Compute the daily mean at the end of day
  635. zdaystp = 1.0 / REAL( kdaystp )
  636. IF ( idayend == 0 ) THEN
  637. DO jj = 1, jpj
  638. DO ji = 1, jpi
  639. ! Test if "no night" point
  640. IF ( icount_sstnight(ji,jj) .NE. 0 ) THEN
  641. sstdatqc%vdmean(ji,jj) = sstdatqc%vdmean(ji,jj) &
  642. & / icount_sstnight(ji,jj)
  643. ELSE
  644. sstdatqc%vdmean(ji,jj) = zmeanday(ji,jj) * zdaystp
  645. ENDIF
  646. END DO
  647. END DO
  648. ENDIF
  649. ENDIF
  650. ! Get the data for interpolation
  651. ALLOCATE( &
  652. & igrdi(2,2,isst), &
  653. & igrdj(2,2,isst), &
  654. & zglam(2,2,isst), &
  655. & zgphi(2,2,isst), &
  656. & zmask(2,2,isst), &
  657. & zsstl(2,2,isst) &
  658. & )
  659. DO jobs = sstdatqc%nsurfup + 1, sstdatqc%nsurfup + isst
  660. iobs = jobs - sstdatqc%nsurfup
  661. igrdi(1,1,iobs) = sstdatqc%mi(jobs)-1
  662. igrdj(1,1,iobs) = sstdatqc%mj(jobs)-1
  663. igrdi(1,2,iobs) = sstdatqc%mi(jobs)-1
  664. igrdj(1,2,iobs) = sstdatqc%mj(jobs)
  665. igrdi(2,1,iobs) = sstdatqc%mi(jobs)
  666. igrdj(2,1,iobs) = sstdatqc%mj(jobs)-1
  667. igrdi(2,2,iobs) = sstdatqc%mi(jobs)
  668. igrdj(2,2,iobs) = sstdatqc%mj(jobs)
  669. END DO
  670. CALL obs_int_comm_2d( 2, 2, isst, &
  671. & igrdi, igrdj, glamt, zglam )
  672. CALL obs_int_comm_2d( 2, 2, isst, &
  673. & igrdi, igrdj, gphit, zgphi )
  674. CALL obs_int_comm_2d( 2, 2, isst, &
  675. & igrdi, igrdj, psstmask, zmask )
  676. CALL obs_int_comm_2d( 2, 2, isst, &
  677. & igrdi, igrdj, psstn, zsstl )
  678. ! At the end of the day get interpolated means
  679. IF ( idayend == 0 .AND. ld_nightav ) THEN
  680. ALLOCATE( &
  681. & zsstm(2,2,isst) &
  682. & )
  683. CALL obs_int_comm_2d( 2, 2, isst, igrdi, igrdj, &
  684. & sstdatqc%vdmean(:,:), zsstm )
  685. ENDIF
  686. ! Loop over observations
  687. DO jobs = sstdatqc%nsurfup + 1, sstdatqc%nsurfup + isst
  688. iobs = jobs - sstdatqc%nsurfup
  689. IF ( kt /= sstdatqc%mstp(jobs) ) THEN
  690. IF(lwp) THEN
  691. WRITE(numout,*)
  692. WRITE(numout,*) ' E R R O R : Observation', &
  693. & ' time step is not consistent with the', &
  694. & ' model time step'
  695. WRITE(numout,*) ' ========='
  696. WRITE(numout,*)
  697. WRITE(numout,*) ' Record = ', jobs, &
  698. & ' kt = ', kt, &
  699. & ' mstp = ', sstdatqc%mstp(jobs), &
  700. & ' ntyp = ', sstdatqc%ntyp(jobs)
  701. ENDIF
  702. CALL ctl_stop( 'obs_sst_opt', 'Inconsistent time' )
  703. ENDIF
  704. zlam = sstdatqc%rlam(jobs)
  705. zphi = sstdatqc%rphi(jobs)
  706. ! Get weights to interpolate the model SST to the observation point
  707. CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi, &
  708. & zglam(:,:,iobs), zgphi(:,:,iobs), &
  709. & zmask(:,:,iobs), zweig, zobsmask )
  710. ! Interpolate the model SST to the observation point
  711. IF ( ld_nightav ) THEN
  712. IF ( idayend == 0 ) THEN
  713. ! Daily averaged/diurnal cycle of SST data
  714. CALL obs_int_h2d( 1, 1, &
  715. & zweig, zsstm(:,:,iobs), zext )
  716. ELSE
  717. CALL ctl_stop( ' ld_nightav is set to true: a nonzero' // &
  718. & ' number of night SST data should' // &
  719. & ' only occur at the end of a given day' )
  720. ENDIF
  721. ELSE
  722. CALL obs_int_h2d( 1, 1, &
  723. & zweig, zsstl(:,:,iobs), zext )
  724. ENDIF
  725. sstdatqc%rmod(jobs,1) = zext(1)
  726. END DO
  727. ! Deallocate the data for interpolation
  728. DEALLOCATE( &
  729. & igrdi, &
  730. & igrdj, &
  731. & zglam, &
  732. & zgphi, &
  733. & zmask, &
  734. & zsstl &
  735. & )
  736. ! At the end of the day also get interpolated means
  737. IF ( idayend == 0 .AND. ld_nightav ) THEN
  738. DEALLOCATE( &
  739. & zsstm &
  740. & )
  741. ENDIF
  742. sstdatqc%nsurfup = sstdatqc%nsurfup + isst
  743. END SUBROUTINE obs_sst_opt
  744. SUBROUTINE obs_sss_opt
  745. !!-----------------------------------------------------------------------
  746. !!
  747. !! *** ROUTINE obs_sss_opt ***
  748. !!
  749. !! ** Purpose : Compute the model counterpart of sea surface salinity
  750. !! data by interpolating from the model grid to the
  751. !! observation point.
  752. !!
  753. !! ** Method :
  754. !!
  755. !! ** Action :
  756. !!
  757. !! History :
  758. !! ! ??-??
  759. !!-----------------------------------------------------------------------
  760. IMPLICIT NONE
  761. END SUBROUTINE obs_sss_opt
  762. SUBROUTINE obs_seaice_opt( seaicedatqc, kt, kpi, kpj, kit000, &
  763. & pseaicen, pseaicemask, k2dint )
  764. !!-----------------------------------------------------------------------
  765. !!
  766. !! *** ROUTINE obs_seaice_opt ***
  767. !!
  768. !! ** Purpose : Compute the model counterpart of surface temperature
  769. !! data by interpolating from the model grid to the
  770. !! observation point.
  771. !!
  772. !! ** Method : Linearly interpolate to each observation point using
  773. !! the model values at the corners of the surrounding grid box.
  774. !!
  775. !! The now model sea ice is first computed at the obs (lon, lat) point.
  776. !!
  777. !! Several horizontal interpolation schemes are available:
  778. !! - distance-weighted (great circle) (k2dint = 0)
  779. !! - distance-weighted (small angle) (k2dint = 1)
  780. !! - bilinear (geographical grid) (k2dint = 2)
  781. !! - bilinear (quadrilateral grid) (k2dint = 3)
  782. !! - polynomial (quadrilateral grid) (k2dint = 4)
  783. !!
  784. !!
  785. !! ** Action :
  786. !!
  787. !! History :
  788. !! ! 07-07 (S. Ricci ) : Original
  789. !!
  790. !!-----------------------------------------------------------------------
  791. !! * Modules used
  792. USE obs_surf_def ! Definition of storage space for surface observations
  793. IMPLICIT NONE
  794. !! * Arguments
  795. TYPE(obs_surf), INTENT(INOUT) :: seaicedatqc ! Subset of surface data not failing screening
  796. INTEGER, INTENT(IN) :: kt ! Time step
  797. INTEGER, INTENT(IN) :: kpi ! Model grid parameters
  798. INTEGER, INTENT(IN) :: kpj
  799. INTEGER, INTENT(IN) :: kit000 ! Number of the first time step
  800. ! (kit000-1 = restart time)
  801. INTEGER, INTENT(IN) :: k2dint ! Horizontal interpolation type (see header)
  802. REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
  803. & pseaicen, & ! Model sea ice field
  804. & pseaicemask ! Land-sea mask
  805. !! * Local declarations
  806. INTEGER :: ji
  807. INTEGER :: jj
  808. INTEGER :: jobs
  809. INTEGER :: inrc
  810. INTEGER :: iseaice
  811. INTEGER :: iobs
  812. REAL(KIND=wp) :: zlam
  813. REAL(KIND=wp) :: zphi
  814. REAL(KIND=wp) :: zext(1), zobsmask(1)
  815. REAL(kind=wp), DIMENSION(2,2,1) :: &
  816. & zweig
  817. REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
  818. & zmask, &
  819. & zseaicel, &
  820. & zglam, &
  821. & zgphi
  822. INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
  823. & igrdi, &
  824. & igrdj
  825. !------------------------------------------------------------------------
  826. ! Local initialization
  827. !------------------------------------------------------------------------
  828. ! ... Record and data counters
  829. inrc = kt - kit000 + 2
  830. iseaice = seaicedatqc%nsstp(inrc)
  831. ! Get the data for interpolation
  832. ALLOCATE( &
  833. & igrdi(2,2,iseaice), &
  834. & igrdj(2,2,iseaice), &
  835. & zglam(2,2,iseaice), &
  836. & zgphi(2,2,iseaice), &
  837. & zmask(2,2,iseaice), &
  838. & zseaicel(2,2,iseaice) &
  839. & )
  840. DO jobs = seaicedatqc%nsurfup + 1, seaicedatqc%nsurfup + iseaice
  841. iobs = jobs - seaicedatqc%nsurfup
  842. igrdi(1,1,iobs) = seaicedatqc%mi(jobs)-1
  843. igrdj(1,1,iobs) = seaicedatqc%mj(jobs)-1
  844. igrdi(1,2,iobs) = seaicedatqc%mi(jobs)-1
  845. igrdj(1,2,iobs) = seaicedatqc%mj(jobs)
  846. igrdi(2,1,iobs) = seaicedatqc%mi(jobs)
  847. igrdj(2,1,iobs) = seaicedatqc%mj(jobs)-1
  848. igrdi(2,2,iobs) = seaicedatqc%mi(jobs)
  849. igrdj(2,2,iobs) = seaicedatqc%mj(jobs)
  850. END DO
  851. CALL obs_int_comm_2d( 2, 2, iseaice, &
  852. & igrdi, igrdj, glamt, zglam )
  853. CALL obs_int_comm_2d( 2, 2, iseaice, &
  854. & igrdi, igrdj, gphit, zgphi )
  855. CALL obs_int_comm_2d( 2, 2, iseaice, &
  856. & igrdi, igrdj, pseaicemask, zmask )
  857. CALL obs_int_comm_2d( 2, 2, iseaice, &
  858. & igrdi, igrdj, pseaicen, zseaicel )
  859. DO jobs = seaicedatqc%nsurfup + 1, seaicedatqc%nsurfup + iseaice
  860. iobs = jobs - seaicedatqc%nsurfup
  861. IF ( kt /= seaicedatqc%mstp(jobs) ) THEN
  862. IF(lwp) THEN
  863. WRITE(numout,*)
  864. WRITE(numout,*) ' E R R O R : Observation', &
  865. & ' time step is not consistent with the', &
  866. & ' model time step'
  867. WRITE(numout,*) ' ========='
  868. WRITE(numout,*)
  869. WRITE(numout,*) ' Record = ', jobs, &
  870. & ' kt = ', kt, &
  871. & ' mstp = ', seaicedatqc%mstp(jobs), &
  872. & ' ntyp = ', seaicedatqc%ntyp(jobs)
  873. ENDIF
  874. CALL ctl_stop( 'obs_seaice_opt', 'Inconsistent time' )
  875. ENDIF
  876. zlam = seaicedatqc%rlam(jobs)
  877. zphi = seaicedatqc%rphi(jobs)
  878. ! Get weights to interpolate the model sea ice to the observation point
  879. CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi, &
  880. & zglam(:,:,iobs), zgphi(:,:,iobs), &
  881. & zmask(:,:,iobs), zweig, zobsmask )
  882. ! ... Interpolate the model sea ice to the observation point
  883. CALL obs_int_h2d( 1, 1, &
  884. & zweig, zseaicel(:,:,iobs), zext )
  885. seaicedatqc%rmod(jobs,1) = zext(1)
  886. END DO
  887. ! Deallocate the data for interpolation
  888. DEALLOCATE( &
  889. & igrdi, &
  890. & igrdj, &
  891. & zglam, &
  892. & zgphi, &
  893. & zmask, &
  894. & zseaicel &
  895. & )
  896. seaicedatqc%nsurfup = seaicedatqc%nsurfup + iseaice
  897. END SUBROUTINE obs_seaice_opt
  898. SUBROUTINE obs_vel_opt( prodatqc, kt, kpi, kpj, kpk, kit000, kdaystp, &
  899. & pun, pvn, pgdept, pumask, pvmask, k1dint, k2dint, &
  900. & ld_dailyav )
  901. !!-----------------------------------------------------------------------
  902. !!
  903. !! *** ROUTINE obs_vel_opt ***
  904. !!
  905. !! ** Purpose : Compute the model counterpart of velocity profile
  906. !! data by interpolating from the model grid to the
  907. !! observation point.
  908. !!
  909. !! ** Method : Linearly interpolate zonal and meridional components of velocity
  910. !! to each observation point using the model values at the corners of
  911. !! the surrounding grid box. The model velocity components are on a
  912. !! staggered C- grid.
  913. !!
  914. !! For velocity data from the TAO array, the model equivalent is
  915. !! a daily mean velocity field. So, we first compute
  916. !! the mean, then interpolate only at the end of the day.
  917. !!
  918. !! ** Action :
  919. !!
  920. !! History :
  921. !! ! 07-03 (K. Mogensen) : Temperature and Salinity profiles
  922. !! ! 08-10 (Maria Valdivieso) : Velocity component (U,V) profiles
  923. !!-----------------------------------------------------------------------
  924. !! * Modules used
  925. USE obs_profiles_def ! Definition of storage space for profile obs.
  926. IMPLICIT NONE
  927. !! * Arguments
  928. TYPE(obs_prof), INTENT(INOUT) :: &
  929. & prodatqc ! Subset of profile data not failing screening
  930. INTEGER, INTENT(IN) :: kt ! Time step
  931. INTEGER, INTENT(IN) :: kpi ! Model grid parameters
  932. INTEGER, INTENT(IN) :: kpj
  933. INTEGER, INTENT(IN) :: kpk
  934. INTEGER, INTENT(IN) :: kit000 ! Number of the first time step
  935. ! (kit000-1 = restart time)
  936. INTEGER, INTENT(IN) :: k1dint ! Vertical interpolation type (see header)
  937. INTEGER, INTENT(IN) :: k2dint ! Horizontal interpolation type (see header)
  938. INTEGER, INTENT(IN) :: kdaystp ! Number of time steps per day
  939. REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj,kpk) :: &
  940. & pun, & ! Model zonal component of velocity
  941. & pvn, & ! Model meridional component of velocity
  942. & pumask, & ! Land-sea mask
  943. & pvmask ! Land-sea mask
  944. REAL(KIND=wp), INTENT(IN), DIMENSION(kpk) :: &
  945. & pgdept ! Model array of depth levels
  946. LOGICAL, INTENT(IN) :: ld_dailyav
  947. !! * Local declarations
  948. INTEGER :: ji
  949. INTEGER :: jj
  950. INTEGER :: jk
  951. INTEGER :: jobs
  952. INTEGER :: inrc
  953. INTEGER :: ipro
  954. INTEGER :: idayend
  955. INTEGER :: ista
  956. INTEGER :: iend
  957. INTEGER :: iobs
  958. INTEGER, DIMENSION(imaxavtypes) :: &
  959. & idailyavtypes
  960. REAL(KIND=wp) :: zlam
  961. REAL(KIND=wp) :: zphi
  962. REAL(KIND=wp) :: zdaystp
  963. REAL(KIND=wp), DIMENSION(kpk) :: &
  964. & zobsmasku, &
  965. & zobsmaskv, &
  966. & zobsmask, &
  967. & zobsk, &
  968. & zobs2k
  969. REAL(KIND=wp), DIMENSION(2,2,kpk) :: &
  970. & zweigu,zweigv
  971. REAL(wp), DIMENSION(:,:,:,:), ALLOCATABLE :: &
  972. & zumask, zvmask, &
  973. & zintu, &
  974. & zintv, &
  975. & zinmu, &
  976. & zinmv
  977. REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
  978. & zglamu, zglamv, &
  979. & zgphiu, zgphiv
  980. INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
  981. & igrdiu, &
  982. & igrdju, &
  983. & igrdiv, &
  984. & igrdjv
  985. !------------------------------------------------------------------------
  986. ! Local initialization
  987. !------------------------------------------------------------------------
  988. ! ... Record and data counters
  989. inrc = kt - kit000 + 2
  990. ipro = prodatqc%npstp(inrc)
  991. ! Initialize daily mean for first timestep
  992. idayend = MOD( kt - kit000 + 1, kdaystp )
  993. ! Added kt == 0 test to catch restart case
  994. IF ( idayend == 1 .OR. kt == 0) THEN
  995. IF (lwp) WRITE(numout,*) 'Reset prodatqc%vdmean on time-step: ',kt
  996. prodatqc%vdmean(:,:,:,1) = 0.0
  997. prodatqc%vdmean(:,:,:,2) = 0.0
  998. ENDIF
  999. ! Increment the zonal velocity field for computing daily mean
  1000. prodatqc%vdmean(:,:,:,1) = prodatqc%vdmean(:,:,:,1) + pun(:,:,:)
  1001. ! Increment the meridional velocity field for computing daily mean
  1002. prodatqc%vdmean(:,:,:,2) = prodatqc%vdmean(:,:,:,2) + pvn(:,:,:)
  1003. ! Compute the daily mean at the end of day
  1004. zdaystp = 1.0 / REAL( kdaystp )
  1005. IF ( idayend == 0 ) THEN
  1006. prodatqc%vdmean(:,:,:,1) = prodatqc%vdmean(:,:,:,1) * zdaystp
  1007. prodatqc%vdmean(:,:,:,2) = prodatqc%vdmean(:,:,:,2) * zdaystp
  1008. ENDIF
  1009. ! Get the data for interpolation
  1010. ALLOCATE( &
  1011. & igrdiu(2,2,ipro), &
  1012. & igrdju(2,2,ipro), &
  1013. & igrdiv(2,2,ipro), &
  1014. & igrdjv(2,2,ipro), &
  1015. & zglamu(2,2,ipro), zglamv(2,2,ipro), &
  1016. & zgphiu(2,2,ipro), zgphiv(2,2,ipro), &
  1017. & zumask(2,2,kpk,ipro), zvmask(2,2,kpk,ipro), &
  1018. & zintu(2,2,kpk,ipro), &
  1019. & zintv(2,2,kpk,ipro) &
  1020. & )
  1021. DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
  1022. iobs = jobs - prodatqc%nprofup
  1023. igrdiu(1,1,iobs) = prodatqc%mi(jobs,1)-1
  1024. igrdju(1,1,iobs) = prodatqc%mj(jobs,1)-1
  1025. igrdiu(1,2,iobs) = prodatqc%mi(jobs,1)-1
  1026. igrdju(1,2,iobs) = prodatqc%mj(jobs,1)
  1027. igrdiu(2,1,iobs) = prodatqc%mi(jobs,1)
  1028. igrdju(2,1,iobs) = prodatqc%mj(jobs,1)-1
  1029. igrdiu(2,2,iobs) = prodatqc%mi(jobs,1)
  1030. igrdju(2,2,iobs) = prodatqc%mj(jobs,1)
  1031. igrdiv(1,1,iobs) = prodatqc%mi(jobs,2)-1
  1032. igrdjv(1,1,iobs) = prodatqc%mj(jobs,2)-1
  1033. igrdiv(1,2,iobs) = prodatqc%mi(jobs,2)-1
  1034. igrdjv(1,2,iobs) = prodatqc%mj(jobs,2)
  1035. igrdiv(2,1,iobs) = prodatqc%mi(jobs,2)
  1036. igrdjv(2,1,iobs) = prodatqc%mj(jobs,2)-1
  1037. igrdiv(2,2,iobs) = prodatqc%mi(jobs,2)
  1038. igrdjv(2,2,iobs) = prodatqc%mj(jobs,2)
  1039. END DO
  1040. CALL obs_int_comm_2d( 2, 2, ipro, igrdiu, igrdju, glamu, zglamu )
  1041. CALL obs_int_comm_2d( 2, 2, ipro, igrdiu, igrdju, gphiu, zgphiu )
  1042. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdiu, igrdju, pumask, zumask )
  1043. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdiu, igrdju, pun, zintu )
  1044. CALL obs_int_comm_2d( 2, 2, ipro, igrdiv, igrdjv, glamv, zglamv )
  1045. CALL obs_int_comm_2d( 2, 2, ipro, igrdiv, igrdjv, gphiv, zgphiv )
  1046. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdiv, igrdjv, pvmask, zvmask )
  1047. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdiv, igrdjv, pvn, zintv )
  1048. ! At the end of the day also get interpolated means
  1049. IF ( idayend == 0 ) THEN
  1050. ALLOCATE( &
  1051. & zinmu(2,2,kpk,ipro), &
  1052. & zinmv(2,2,kpk,ipro) &
  1053. & )
  1054. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdiu, igrdju, &
  1055. & prodatqc%vdmean(:,:,:,1), zinmu )
  1056. CALL obs_int_comm_3d( 2, 2, ipro, kpk, igrdiv, igrdjv, &
  1057. & prodatqc%vdmean(:,:,:,2), zinmv )
  1058. ENDIF
  1059. ! loop over observations
  1060. DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
  1061. iobs = jobs - prodatqc%nprofup
  1062. IF ( kt /= prodatqc%mstp(jobs) ) THEN
  1063. IF(lwp) THEN
  1064. WRITE(numout,*)
  1065. WRITE(numout,*) ' E R R O R : Observation', &
  1066. & ' time step is not consistent with the', &
  1067. & ' model time step'
  1068. WRITE(numout,*) ' ========='
  1069. WRITE(numout,*)
  1070. WRITE(numout,*) ' Record = ', jobs, &
  1071. & ' kt = ', kt, &
  1072. & ' mstp = ', prodatqc%mstp(jobs), &
  1073. & ' ntyp = ', prodatqc%ntyp(jobs)
  1074. ENDIF
  1075. CALL ctl_stop( 'obs_pro_opt', 'Inconsistent time' )
  1076. ENDIF
  1077. zlam = prodatqc%rlam(jobs)
  1078. zphi = prodatqc%rphi(jobs)
  1079. ! Initialize observation masks
  1080. zobsmasku(:) = 0.0
  1081. zobsmaskv(:) = 0.0
  1082. ! Horizontal weights and vertical mask
  1083. IF ( prodatqc%npvend(jobs,1) > 0 ) THEN
  1084. CALL obs_int_h2d_init( kpk, kpk, k2dint, zlam, zphi, &
  1085. & zglamu(:,:,iobs), zgphiu(:,:,iobs), &
  1086. & zumask(:,:,:,iobs), zweigu, zobsmasku )
  1087. ENDIF
  1088. IF ( prodatqc%npvend(jobs,2) > 0 ) THEN
  1089. CALL obs_int_h2d_init( kpk, kpk, k2dint, zlam, zphi, &
  1090. & zglamv(:,:,iobs), zgphiv(:,:,iobs), &
  1091. & zvmask(:,:,:,iobs), zweigv, zobsmasku )
  1092. ENDIF
  1093. ! Ensure that the vertical mask on u and v are consistent.
  1094. zobsmask(:) = MIN( zobsmasku(:), zobsmaskv(:) )
  1095. IF ( prodatqc%npvend(jobs,1) > 0 ) THEN
  1096. zobsk(:) = obfillflt
  1097. IF ( ld_dailyav ) THEN
  1098. IF ( idayend == 0 ) THEN
  1099. ! Daily averaged data
  1100. CALL obs_int_h2d( kpk, kpk, &
  1101. & zweigu, zinmu(:,:,:,iobs), zobsk )
  1102. ELSE
  1103. CALL ctl_stop( ' A nonzero' // &
  1104. & ' number of U profile data should' // &
  1105. & ' only occur at the end of a given day' )
  1106. ENDIF
  1107. ELSE
  1108. ! Point data
  1109. CALL obs_int_h2d( kpk, kpk, &
  1110. & zweigu, zintu(:,:,:,iobs), zobsk )
  1111. ENDIF
  1112. !-------------------------------------------------------------
  1113. ! Compute vertical second-derivative of the interpolating
  1114. ! polynomial at obs points
  1115. !-------------------------------------------------------------
  1116. IF ( k1dint == 1 ) THEN
  1117. CALL obs_int_z1d_spl( kpk, zobsk, zobs2k, &
  1118. & pgdept, zobsmask )
  1119. ENDIF
  1120. !-----------------------------------------------------------------
  1121. ! Vertical interpolation to the observation point
  1122. !-----------------------------------------------------------------
  1123. ista = prodatqc%npvsta(jobs,1)
  1124. iend = prodatqc%npvend(jobs,1)
  1125. CALL obs_int_z1d( kpk, &
  1126. & prodatqc%var(1)%mvk(ista:iend), &
  1127. & k1dint, iend - ista + 1, &
  1128. & prodatqc%var(1)%vdep(ista:iend), &
  1129. & zobsk, zobs2k, &
  1130. & prodatqc%var(1)%vmod(ista:iend), &
  1131. & pgdept, zobsmask )
  1132. ENDIF
  1133. IF ( prodatqc%npvend(jobs,2) > 0 ) THEN
  1134. zobsk(:) = obfillflt
  1135. IF ( ld_dailyav ) THEN
  1136. IF ( idayend == 0 ) THEN
  1137. ! Daily averaged data
  1138. CALL obs_int_h2d( kpk, kpk, &
  1139. & zweigv, zinmv(:,:,:,iobs), zobsk )
  1140. ELSE
  1141. CALL ctl_stop( ' A nonzero' // &
  1142. & ' number of V profile data should' // &
  1143. & ' only occur at the end of a given day' )
  1144. ENDIF
  1145. ELSE
  1146. ! Point data
  1147. CALL obs_int_h2d( kpk, kpk, &
  1148. & zweigv, zintv(:,:,:,iobs), zobsk )
  1149. ENDIF
  1150. !-------------------------------------------------------------
  1151. ! Compute vertical second-derivative of the interpolating
  1152. ! polynomial at obs points
  1153. !-------------------------------------------------------------
  1154. IF ( k1dint == 1 ) THEN
  1155. CALL obs_int_z1d_spl( kpk, zobsk, zobs2k, &
  1156. & pgdept, zobsmask )
  1157. ENDIF
  1158. !----------------------------------------------------------------
  1159. ! Vertical interpolation to the observation point
  1160. !----------------------------------------------------------------
  1161. ista = prodatqc%npvsta(jobs,2)
  1162. iend = prodatqc%npvend(jobs,2)
  1163. CALL obs_int_z1d( kpk, &
  1164. & prodatqc%var(2)%mvk(ista:iend),&
  1165. & k1dint, iend - ista + 1, &
  1166. & prodatqc%var(2)%vdep(ista:iend),&
  1167. & zobsk, zobs2k, &
  1168. & prodatqc%var(2)%vmod(ista:iend),&
  1169. & pgdept, zobsmask )
  1170. ENDIF
  1171. END DO
  1172. ! Deallocate the data for interpolation
  1173. DEALLOCATE( &
  1174. & igrdiu, &
  1175. & igrdju, &
  1176. & igrdiv, &
  1177. & igrdjv, &
  1178. & zglamu, zglamv, &
  1179. & zgphiu, zgphiv, &
  1180. & zumask, zvmask, &
  1181. & zintu, &
  1182. & zintv &
  1183. & )
  1184. ! At the end of the day also get interpolated means
  1185. IF ( idayend == 0 ) THEN
  1186. DEALLOCATE( &
  1187. & zinmu, &
  1188. & zinmv &
  1189. & )
  1190. ENDIF
  1191. prodatqc%nprofup = prodatqc%nprofup + ipro
  1192. END SUBROUTINE obs_vel_opt
  1193. END MODULE obs_oper