MAmfGet.F90 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. ! First include the set of model-wide compiler flags
  2. #include "tm5.inc"
  3. ! #ifdef TROPNLL2DP
  4. ! #define IF_NOTOK_RETURN(notok_string) call fortranlog(notok_string,len(notok_string),2); status=1; return
  5. ! #define WRITE_WARNING(notok_string) call fortranlog(notok_string,len(notok_string),2)
  6. ! #else
  7. #define IF_NOTOK_RETURN(notok_string) write (*,'(a)') notok_string; status=1; return
  8. #define WRITE_WARNING(notok_string) write (*,'(a)') notok_string
  9. ! #endif
  10. module MAmfGet
  11. !
  12. ! Module to return the height-dependent air-mass factor for a given geometry
  13. !
  14. ! Henk Eskes, KNMI, sept 2015
  15. !
  16. use physconstants, only : pi
  17. ! --- Error message codes ---
  18. use pqf_module
  19. implicit none
  20. private
  21. public :: GetAmf, GetAmfGeo, GetAmf_vectorised
  22. public :: FitWindowCentre
  23. ! --------------------------------------------------------------
  24. ! FitWindowCentre: central wavelength of fit window
  25. ! --------------------------------------------------------------
  26. real, parameter :: FitWindowCentre = 437.5 ! nm, used in DOMINO-1 & 2
  27. ! real, parameter :: FitWindowCentre = 440.0 ! nm
  28. ! for error messages
  29. character(256) :: errmessage
  30. contains
  31. subroutine GetAmfGeo ( cos_vza, cos_sza, amfGeo )
  32. !=======================================================================
  33. !
  34. ! GetAmfGeo: Return simple geometric AMF
  35. !
  36. ! input:
  37. ! cos_vza : cos viewing angle (degrees) [-60..60]
  38. ! cos_sza : cos solar zenith angle (degrees) [-90..90]
  39. ! amfGeo : geometrical air mass factor
  40. !
  41. ! geometrical air mass factor
  42. !
  43. ! Henk Eskes, KNMI, aug 2016
  44. !=======================================================================
  45. implicit none
  46. ! in/out
  47. real, intent(in) :: cos_vza, cos_sza
  48. real, intent(out) :: amfGeo
  49. ! local
  50. amfGeo = 1.0 / cos_vza + 1.0 / cos_sza
  51. end subroutine GetAmfGeo
  52. subroutine GetAmfGeo_Leue ( cos_vza, cos_sza, amfGeo )
  53. !=======================================================================
  54. !
  55. ! GetAmfGeo_Leue: Return geometric AMF
  56. !
  57. ! input:
  58. ! cos_vza : cos viewing angle (degrees) [-60..60]
  59. ! cos_sza : cos solar zenith angle (degrees) [-90..90]
  60. ! amfGeo : geometrical air mass factor
  61. !
  62. ! geometrical air mass factor, based on a
  63. ! simple form with corrections for large SZAs,
  64. ! from Carsten Leue, thesis
  65. !
  66. ! Henk Eskes, KNMI, sept 2015
  67. !=======================================================================
  68. use physconstants, only : Earth_rad ! pdiff2moleccm2
  69. implicit none
  70. ! in/out
  71. real, intent(in) :: cos_vza, cos_sza
  72. real, intent(out) :: amfGeo
  73. ! local
  74. real, parameter :: htopatm = 60.0 ! (km) height of top of atmosphere
  75. real, parameter :: eps = htopatm*1000.0/Earth_rad
  76. real :: xh
  77. xh = sqrt( cos_sza*cos_sza + eps*eps + 2.*eps )
  78. amfGeo = 1.0/cos_vza + ( xh - cos_sza ) / eps
  79. end subroutine GetAmfGeo_Leue
  80. subroutine GetAmfFactors ( amfLutValue, amfLutArray, iLoc, fFactor )
  81. !==========================================================================
  82. !
  83. ! GetAmfIncreasing: Interpolate in increasing array
  84. !
  85. ! input:
  86. ! amfLutValue : value for which interpolation factors are determined
  87. ! amfLutArray : interpolation array
  88. !
  89. ! input:
  90. ! iLoc : index in amfLutArray where value just below amfLutValue
  91. ! fFactor : interpolation factors
  92. !
  93. ! bug fix: bordeline cases, e.g. azi == 0 (feb 2016)
  94. !
  95. ! Martien de Haan, KNMI, feb 2016
  96. !==========================================================================
  97. implicit none
  98. ! in/out
  99. real, intent(in) :: amfLutValue
  100. real, dimension(:), intent(in) :: amfLutArray
  101. integer, intent(out) :: iLoc
  102. real, dimension(2), intent(out) :: fFactor
  103. integer :: dum(1)
  104. ! --> Determine whether amfLutArray is increasing or decreasing
  105. if (amfLutArray(2) > amfLutArray(1)) then
  106. ! --> Increasing
  107. dum = maxloc ( amfLutArray, amfLutArray < amfLutValue )
  108. else
  109. dum = minloc ( amfLutArray, amfLutArray >= amfLutValue )
  110. end if
  111. iLoc = dum(1)
  112. ! --> Border case: amfLutValue is lowest value in array. Set to first index
  113. if (iLoc == 0) iLoc = 1
  114. ! --> Set interpolation factors
  115. fFactor(1) = ( amfLutArray(iLoc+1) - amfLutValue ) / ( amfLutArray(iLoc+1) - amfLutArray(iLoc) )
  116. fFactor(2) = 1.0 - fFactor(1)
  117. end subroutine GetAmfFactors
  118. subroutine GetAmf ( pres, azi1, view, sza, albedo, spres, amfLut, amf, status )
  119. !=======================================================================
  120. !
  121. ! GetAmf: Return AMF (divided by the geometrical AMF)
  122. ! interpolated from the lookup table
  123. ! input:
  124. ! pres : model pressure level in hPa
  125. ! azi1 : azimuth angle (degrees) [-360..360]
  126. ! view : viewing angle (degrees) [-60..60]
  127. ! sza : solar zenith angle (degrees) [-90..90]
  128. ! albedo : ground albedo el. [0..1]
  129. ! spres : surface pressure in hPa
  130. ! amfLut : a structure containing the AMF array and description of the axis
  131. ! status : 0 = OK, > 0 is error
  132. !
  133. ! Henk Eskes, KNMI, nov 1999 - sept 2015
  134. !=======================================================================
  135. use MTAmf, only : TAmfLut
  136. implicit none
  137. ! in/out
  138. real,intent(in) :: pres, azi1, view, sza, albedo, spres
  139. type(TAmfLut), intent(in) :: amfLut
  140. real,intent(out) :: amf
  141. integer, intent(out) :: status
  142. ! local
  143. character(*), parameter :: rname = "GetAmf"
  144. real :: pres_tmp, spres_tmp
  145. integer :: imu, imu0, iazi, ipres, ispres, ialbedo
  146. integer :: i1, i2, i3, i4, i5, i6
  147. integer :: dum(1)
  148. real,dimension(2) :: xmu, xmu0, xazi, xpres, xspres, xalbedo
  149. real :: azi, mu, mu0
  150. !
  151. ! if ( pres > spres ) write(*,'(a,f,2x,f)')'WARNING GetAmf: pressure > surface pressure ',pres,spres
  152. status = 0
  153. ! the routine assumes the input varaibles have been range checked
  154. ! Azimuth fix (Ronald van der A), azi = abs(180.0-azi1)
  155. ! For the new AMF lookup table (August 2015, Alba Lorente) this fix is no longer needed (Henk Eskes)
  156. azi = abs(azi1)
  157. if ( azi > 180.0 ) azi = abs( 360.0 - azi )
  158. mu = cos(pi*view*(1./180.0))
  159. mu0 = cos(pi*sza*(1./180.0))
  160. ! Additional range checks: is the point inside the LUT domain ?
  161. if ( (mu < amfLut%mu(1)) .or. (mu > amfLut%mu(amfLut%mmu)) ) then
  162. write ( errmessage, * ) 'WARNING GetAmf: cos(vza) out of range, value = ',mu
  163. IF_NOTOK_RETURN( trim(errmessage) )
  164. end if
  165. if ( (mu0 < amfLut%mu0(1)) .or. (mu0 > amfLut%mu0(amfLut%mmu0)) ) then
  166. write ( errmessage, * ) 'WARNING GetAmf: cos(sza) out of range, value = ',mu0
  167. IF_NOTOK_RETURN( trim(errmessage) )
  168. end if
  169. if ( (azi < amfLut%azi(1)) .or. (azi > amfLut%azi(amfLut%mazi)) ) then
  170. write ( errmessage, * ) 'WARNING GetAmf: azi out of range, value = ',azi
  171. IF_NOTOK_RETURN( trim(errmessage) )
  172. end if
  173. if ( (albedo < amfLut%albedo(1)) .or. (albedo > amfLut%albedo(amfLut%malbedo)) ) then
  174. write ( errmessage, * ) 'WARNING GetAmf: albedo out of range, value = ',albedo
  175. IF_NOTOK_RETURN( trim(errmessage) )
  176. end if
  177. ! force surface pressure to be within the LUT range
  178. spres_tmp = spres
  179. if( (spres_tmp < amfLut%spres(amfLut%mspres)) ) then
  180. ! code die clipt, RuudDirksen 14 juni 2009
  181. ! write ( errmessage,'(a,f8.2,a,f8.2)') 'WARNING: overwrite input surface pressure ',spres,' with first AMF surface pressure ',amfLut%spres(amfLut%mspres)
  182. ! WRITE_WARNING( trim(errmessage) )
  183. spres_tmp = 1.00001 * amfLut%spres(amfLut%mspres)
  184. end if
  185. if ( spres_tmp > amfLut%spres(1) ) then
  186. spres_tmp = 0.99999 * amfLut%spres(1)
  187. !write ( errmessage, * ) 'WARNING: Overwriting surface pressure ', spres, &
  188. ! ' with AMF first surf p level ', amfLut%spres(1)
  189. !WRITE_WARNING( trim(errmessage) )
  190. end if
  191. ! force pressure to be within range
  192. pres_tmp = pres
  193. if ( pres < amfLut%pres(amfLut%mpres) ) then
  194. pres_tmp = 1.00001 * amfLut%pres(amfLut%mpres)
  195. end if
  196. if ( pres > amfLut%pres(1) ) then
  197. pres_tmp = 0.99999 * amfLut%pres(1)
  198. write ( errmessage, * ) 'WARNING: Overwriting Model pressure ', pres, &
  199. ' with AMF first pressure level ', amfLut%pres(1)
  200. WRITE_WARNING( trim(errmessage) )
  201. end if
  202. !
  203. ! Determine reference index (imu,imu0,iazi,ipres,ispres,ialbedo)
  204. !
  205. ! --> Cos viewing angle mu: (increasing)
  206. call GetAmfFactors(mu, amfLut%mu, imu, xmu)
  207. ! --> Cos solar zenith angle: (increasing)
  208. call GetAmfFactors(mu0, amfLut%mu0, imu0, xmu0)
  209. ! --> Azimuth angle: (increasing)
  210. call GetAmfFactors(azi, amfLut%azi, iazi, xazi)
  211. ! --> Pressure: (decreasing)
  212. call GetAmfFactors(pres_tmp, amfLut%pres, ipres, xpres)
  213. ! --> Surface pressure: (decreasing)
  214. call GetAmfFactors(spres_tmp, amfLut%spres, ispres, xspres)
  215. ! --> Ground albedo: (increasing)
  216. call GetAmfFactors(albedo, amfLut%albedo, ialbedo, xalbedo)
  217. ! Linear interpolation
  218. amf = 0.0
  219. do i1 = 1, 2
  220. do i2 = 1, 2
  221. do i3 = 1, 2
  222. do i4 = 1, 2
  223. do i5 = 1, 2
  224. do i6 = 1, 2
  225. amf = amf + xmu(i1)*xmu0(i2)*xazi(i3)*xpres(i4)*xspres(i5)*xalbedo(i6)* &
  226. amfLut%amf ( imu+i1-1, imu0+i2-1, iazi+i3-1, ipres+i4-1, ispres+i5-1, ialbedo+i6-1 )
  227. end do
  228. end do
  229. end do
  230. end do
  231. end do
  232. end do
  233. !
  234. end subroutine GetAmf
  235. subroutine GetAmf_vectorised ( nObs, lm, pres1, azi1, view1, sza1, albedo, spres1, amfLut, amf, flag, debug )
  236. !=======================================================================
  237. !
  238. ! GetAmf_vectorised: Return AMF (divided by the geometrical AMF)
  239. ! interpolated from the lookup table
  240. ! for all observations at the same time
  241. !
  242. ! call GetAMF_vectorised(phybrid(:,:),aza(:),vza(:),sza(:),albclear(:),surfpres(:),amfclearrel(:,:))
  243. !
  244. ! input:
  245. ! nObs : number of observations
  246. ! lm : number of vertical layers
  247. ! pres1 : model pressure level in hPa, dimension: (nObs,lm)
  248. ! azi1 : azimuth angle (degrees) [-360..360]
  249. ! view1 : viewing angle (degrees) [-60..60]
  250. ! sza1 : solar zenith angle (degrees) [-90..90]
  251. ! albedo : ground albedo el. [0..1]
  252. ! spres1 : surface pressure in hPa
  253. ! amfLut : a structure containing the AMF array and description of the axis
  254. ! flag : error flags for the individual observations
  255. ! debug : provide debug info to screen
  256. !
  257. ! output:
  258. ! amf : air mass factor for all observations and on all layers
  259. ! flag : error flags for the individual observations
  260. !
  261. ! note: all these quantities are arrays of size (nr of observations) or
  262. ! (nr of observations, nr of levels)
  263. !
  264. ! Henk Eskes, KNMI, nov 1999 - sept 2015
  265. ! Vectorized version by Ruud Dirksen 27 nov 2007
  266. !=======================================================================
  267. use MTAmf, only : TAmfLut
  268. implicit none
  269. ! in/out
  270. integer, intent(in) :: nObs, lm
  271. real, dimension(:,:), intent(in) :: pres1
  272. real, dimension(:), intent(in) :: spres1, view1, azi1, sza1, albedo
  273. type(TAmfLut), intent(in) :: amfLut
  274. real, dimension(:,:), intent(out) :: amf
  275. integer, dimension(:), intent(inout) :: flag
  276. logical, intent(in) :: debug
  277. ! local
  278. character(*), parameter :: rname = "GetAmf_vectorised"
  279. real,dimension(:),allocatable :: azi, mu, mu0, spres
  280. real,dimension(:,:),allocatable :: pres
  281. integer :: i1, i2, i3, i4, i5, i6
  282. integer :: dum(1), iObs, l
  283. integer :: ipres, ispres, imu, iazi, imu0, ialbedo
  284. real,dimension(2) :: xpres, xspres, xmu, xazi, xmu0, xalbedo
  285. ! start code
  286. if ( debug ) then
  287. print *, ' '
  288. print *, 'AMF LUT axes'
  289. print '(a,24f6.3)', ' amf cvza ',amfLut%mu
  290. print '(a,24f6.3)', ' amf csza ',amfLut%mu0
  291. print '(a,24f5.0)', ' amf azi ',amfLut%azi
  292. print '(a,240f6.0)', ' amf pres ',amfLut%pres
  293. print '(a,24f6.0)', ' amf spres ',amfLut%spres
  294. print '(a,50f6.3)', ' amf albedo ',amfLut%albedo
  295. end if
  296. ! initialise AMF
  297. amf(:,:) = 0.0
  298. ! helper arrays
  299. allocate ( azi(nObs) )
  300. allocate ( mu(nObs) )
  301. allocate ( mu0(nObs) )
  302. allocate ( spres(nObs) )
  303. allocate ( pres(nObs,lm) )
  304. ! make copies of the surface pressure and level pressures
  305. spres(:) = spres1(1:nObs)
  306. pres(:,:) = pres1(1:nObs,1:lm)
  307. ! if ( pres > spres ) write(*,*)'WARNING GetAmf: pressure > surface pressure'
  308. ! routine assumes the ranges of the input values have been checked
  309. ! Azimuth fix (Ronald van der A), azi = abs(180.0-azi1)
  310. ! For the new AMF lookup table (August 2015, Alba Lorente) this fix is no longer needed (Henk Eskes)
  311. do iObs = 1, nObs
  312. azi(iObs) = abs(azi1(iObs))
  313. if ( azi(iObs) .gt. 180.0 ) azi(iObs) = abs(360.0 - azi(iObs))
  314. end do
  315. do iObs = 1, nObs
  316. mu(iObs) = cos(pi*view1(iObs)*(1./180.0))
  317. mu0(iObs) = cos(pi*sza1(iObs)*(1./180.0))
  318. end do
  319. !$OMP parallel do private(xazi,xview,xmu0,xalbedo,xspres,xpres) schedule(static)
  320. observationLoop: do iObs = 1, nObs
  321. ! skip to next iObs if (flag = error), accept warnings
  322. if ( iand(flag(iObs), 255) /= 0 ) cycle
  323. ! Make sure the inputs are inside the LUT domain,
  324. ! write warning and set error flag
  325. if ( (mu(iObs) < amfLut%mu(1)) .or. (mu(iObs) > amfLut%mu(amfLut%mmu)) ) then
  326. write ( errmessage, * ) 'WARNING GetAmf_vectorised: cos(vza) out of range, value = ',mu(iObs),' iObs = ',iObs
  327. WRITE_WARNING( trim(errmessage) )
  328. flag(iObs) = PQF_E_LUT_RANGE_ERROR
  329. end if
  330. if ( (mu0(iObs) < amfLut%mu0(1)) .or. (mu0(iObs) > amfLut%mu0(amfLut%mmu0)) ) then
  331. write ( errmessage, * ) 'WARNING GetAmf_vectorised: cos(sza) out of range, value = ',mu0(iObs),' iObs = ',iObs
  332. WRITE_WARNING( trim(errmessage) )
  333. flag(iObs) = PQF_E_LUT_RANGE_ERROR
  334. end if
  335. if ( (azi(iObs) < amfLut%azi(1)) .or. (azi(iObs) > amfLut%azi(amfLut%mazi)) ) then
  336. write ( errmessage, * ) 'WARNING GetAmf_vectorised: azi out of range, value = ',azi(iObs),' iObs = ',iObs
  337. WRITE_WARNING( trim(errmessage) )
  338. flag(iObs) = PQF_E_LUT_RANGE_ERROR
  339. end if
  340. if ( (albedo(iObs) < amfLut%albedo(1)) .or. (albedo(iObs) > amfLut%albedo(amfLut%malbedo)) ) then
  341. write ( errmessage, * ) 'WARNING GetAmf_vectorised: albedo out of range, value = ',albedo(iObs),' iObs = ',iObs
  342. WRITE_WARNING( trim(errmessage) )
  343. flag(iObs) = PQF_E_LUT_RANGE_ERROR
  344. end if
  345. if ( spres(iObs) < amfLut%spres(amfLut%mspres) ) then
  346. write ( errmessage, * ) 'WARNING GetAmf_vectorised: surface pressure out of range, value = ',spres(iObs),' iObs = ',iObs
  347. WRITE_WARNING( trim(errmessage) )
  348. spres(iObs) = 1.00001 * amfLut%spres(amfLut%mspres)
  349. end if
  350. if ( spres(iObs) > amfLut%spres(1) ) then
  351. write ( errmessage, * ) 'WARNING GetAmf_vectorised: surface pressure out of range, value = ',spres(iObs),' iObs = ',iObs
  352. WRITE_WARNING( trim(errmessage) )
  353. spres(iObs) = 0.99999 * amfLut%spres(1)
  354. end if
  355. if ( maxval(pres(iObs,:)) > amfLut%pres(1) ) then
  356. write ( errmessage, * ) 'WARNING GetAmf_vectorised: pressure out of range, value = ',maxval(pres1(iObs,:)),' iObs = ',iObs
  357. WRITE_WARNING( trim(errmessage) )
  358. end if
  359. ! skip to next iObs if (flag = error), accept warnings
  360. if ( iand(flag(iObs), 255) /= 0 ) cycle
  361. ! force surface pressure to be within the LUT range
  362. ! spres = spres1
  363. ! where ( spres < amfLut%spres(amfLut%mspres) ) spres = 1.00001 * amfLut%spres(amfLut%mspres)
  364. ! where ( spres > amfLut%spres(1) ) spres = 0.99999 * amfLut%spres(1)
  365. ! force pressure to be within the LUT range
  366. where ( pres(iObs,:) < amfLut%pres(amfLut%mpres) ) pres(iObs,:) = 1.00001 * amfLut%pres(amfLut%mpres)
  367. where ( pres(iObs,:) > amfLut%pres(1) ) pres(iObs,:) = 0.99999 * amfLut%pres(1)
  368. ! Determine reference index (ipres,iview,iazi,imu0,ialbedo)
  369. ! --> Cos viewing angle mu: (increasing)
  370. call GetAmfFactors(mu(iObs), amfLut%mu, imu, xmu)
  371. ! --> Cos solar zenith angle: (increasing)
  372. call GetAmfFactors(mu0(iObs), amfLut%mu0, imu0, xmu0)
  373. ! --> Azimuth angle: (increasing)
  374. call GetAmfFactors(azi(iObs), amfLut%azi, iazi, xazi)
  375. ! --> Surface pressure: (decreasing)
  376. call GetAmfFactors(spres(iObs), amfLut%spres, ispres, xspres)
  377. ! --> Ground albedo: (increasing)
  378. call GetAmfFactors(albedo(iObs), amfLut%albedo, ialbedo, xalbedo)
  379. ! now loop over vertical levels
  380. levelLoop: do l = 1, lm
  381. ! Pressure: (decreasing)
  382. call GetAmfFactors(pres(iObs,l), amfLut%pres, ipres, xpres)
  383. ! Linear interpolation
  384. do i1 = 1, 2
  385. do i2 = 1, 2
  386. do i3 = 1, 2
  387. do i4 = 1, 2
  388. do i5 = 1, 2
  389. do i6 = 1, 2
  390. amf(iObs,l) = amf(iObs,l) + xmu(i1)*xmu0(i2)*xazi(i3)*xpres(i4)*xspres(i5)*xalbedo(i6)* &
  391. amfLut%amf ( imu+i1-1, imu0+i2-1, iazi+i3-1, ipres+i4-1, ispres+i5-1, ialbedo+i6-1 )
  392. end do
  393. end do
  394. end do
  395. end do
  396. end do
  397. end do
  398. end do levelLoop ! l
  399. if ( debug .and. (iObs == max(nObs/2,1)) ) then
  400. print '(a)', ' '
  401. print '(a,i6)', 'iobs = ',iObs
  402. print '(a,3f8.2)', ' vza,sza,aza1 = ',view1(iObs),sza1(iObs),azi1(iObs)
  403. print '(a,3f8.2)', ' cvza,csza,aza = ',mu(iObs),mu0(iObs),azi(iObs)
  404. print '(a,3f8.2)', ' spres1,spres,albclear = ',spres1(iObs),spres(iObs),albedo(iObs)
  405. print '(a,3i4,a,2i4)', 'imu, imu0, iazi, x, ispres, ialbedo = ', imu, imu0, iazi, ' X ', ispres, ialbedo
  406. print '(a,200f6.0)', ' amfpres = ',amfLut%pres
  407. print '(a,500f6.3)', ' amflut1 = ',amflut%amf(imu, imu0, iazi, :,ispres, ialbedo )
  408. print '(a,500f6.3)', ' amflut2 = ',amflut%amf(imu+1,imu0+1,iazi+1,:,ispres+1,ialbedo+1)
  409. print '(a,50f6.0)', ' phybrid = ',pres(iObs,:)
  410. print '(a,50f6.3)', ' amf = ',amf(iObs,:)
  411. print '(a)', ' '
  412. end if
  413. end do observationLoop ! iObs
  414. !$OMP end parallel do
  415. if ( allocated(azi) ) deallocate ( azi )
  416. if ( allocated(mu) ) deallocate ( mu )
  417. if ( allocated(mu0) ) deallocate ( mu0 )
  418. if ( allocated(pres) ) deallocate ( pres )
  419. if ( allocated(spres) ) deallocate ( spres )
  420. end subroutine GetAmf_vectorised
  421. end module MAmfGet