Simulation Core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Annulus_and_Openhole_Pressure_Distribution.f90 18 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. SUBROUTINE PressureAnnAndOHDistribution
  2. !! Record of revisions
  3. !! Date Programmer Discription of change
  4. !! ------ ------------ -----------------------
  5. !! 1396/07/30 Sheikh Original code
  6. !!
  7. USE FricPressDropVarsModule
  8. USE MudSystemVARIABLES
  9. use SimulationVariables !@@@
  10. use PressureDisplayVARIABLESModule
  11. USE GeoElements_FluidModule
  12. USE Fluid_Flow_Startup_Vars
  13. use KickVARIABLESModule
  14. USE CMudPropertiesVariables
  15. use SimulationVariables !@
  16. USE CReservoirVariables
  17. use MudSystemModule
  18. USE CHOKEVARIABLES
  19. use SimulationVariables !@
  20. use CChokeManifoldVariables
  21. use SimulationVariables
  22. use SimulationVariables
  23. USE CError
  24. USE , INTRINSIC :: IEEE_ARITHMETIC
  25. IMPLICIT NONE
  26. INTEGER :: i , j , k , l
  27. INTEGER :: ifric
  28. REAL :: Fraction
  29. data%State%FricPressDrop%KBOP = 0.0
  30. IF (WellHeadOpen .OR. NoGasPocket == 0) THEN !! (mud circulation is normal wellhead may be open or closed) OR (kick is in the well and well head is open)
  31. !!!!! Determining flow rate in each section
  32. i = data%State%FricPressDrop%AnnulusFirstEl
  33. j = data%State%FricPressDrop%OpenholeFirstEl - 1
  34. !!!!!!!!!!!!!!!!!!!!!!!!! flowrates due to external sources like pump and tripping
  35. FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = (ClingingFactor * FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%Area + FlowEl(data%State%FricPressDrop%StringFirstEl)%Area) * DrillStringSpeed * ConvMintoSec * Convft3toUSgal ! flowrate in annulus due to tripping
  36. FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate + REAL(data%State%MudSystem%MudVolume_InjectedToBH) * ConvMintoSec / dt ! flowrate in annulus due to pump
  37. IF (data%State%MudSystem%ShoeFractured) THEN ! reduction of flowrate due to formation fracture and lost circulation
  38. IF (ShoeFlowElNo > data%State%FricPressDrop%AnnulusLastEl) THEN ! shoe is in openhole
  39. FlowEl(ShoeFlowElNo : data%State%FricPressDrop%NumbEl)%FlowRate = - data%State%MudSystem%Qlost
  40. FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate - data%State%MudSystem%Qlost
  41. ELSE ! shoe is in annulus
  42. FlowEl(ShoeFlowElNo : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = FlowEl(ShoeFlowElNo : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate - data%State%MudSystem%Qlost
  43. END IF
  44. END IF
  45. !!!!!!!!!!!!!!!!!!!!!!!!!
  46. !!!!!!!!!!!!!!!!!!!!!!!!! initial guess flowrates for opening BOP or choke line
  47. IF (WellHeadWasOpen == .FALSE. .AND. NoGasPocket > 0 .AND. KickIteration == 1) THEN
  48. IF (ChokeKroneckerDelta == 1) THEN ! flow on choke line
  49. IF (data%State%FricPressDrop%TotalOpenChokeArea < 0.01 * data%State%Choke%ChokeAreaFullyOpen) THEN
  50. WRITE (*,*) 'density , TotalOpenChokeArea' , "data%Equipments%DownHole%Density", data%State%FricPressDrop%TotalOpenChokeArea
  51. data%State%FricPressDrop%TotalOpenChokeArea = 0.01 * data%State%Choke%ChokeAreaFullyOpen
  52. END IF
  53. data%State%FricPressDrop%Kchoke = (ChokeDensity / ((2.0 * 89158.0) * (0.26 * 0.61 * data%State%FricPressDrop%TotalOpenChokeArea)**2)) * 4.0 ! *4.d0: seyyed gofte
  54. GasPocketFlowInduced%Array(:) = MIN((0.6 / NoGasPocket * SQRT(data%State%PressureDisplay%PressureGauges(2) / data%State%FricPressDrop%Kchoke)) , (0.05 * GasPocketNewVol%Array(:) * ConvFt3toUSgal / 60 / dt))
  55. WRITE (*,*) ' PressureGauges(2) , Kchoke' , data%State%PressureDisplay%PressureGauges(2) , data%State%FricPressDrop%Kchoke
  56. WRITE (*,*) 'Initial guess after opening choke =', GasPocketFlowInduced%Array(1)
  57. WRITE (*,*) ' valve 49 ', data%state%manifold%Valve(49)%Status
  58. WRITE (*,*) ' valve 47 ', data%state%manifold%Valve(47)%Status
  59. WRITE (*,*) ' valve 26 ', data%state%manifold%Valve(26)%Status
  60. WRITE (*,*) ' valve 30 ', data%state%manifold%Valve(30)%Status
  61. WRITE (*,*) ' valve 34 ', data%state%manifold%Valve(34)%Status
  62. WRITE (*,*) ' valve 63 ', data%state%manifold%Valve(63)%Status
  63. WRITE (*,*) ' valve 28 ', data%state%manifold%Valve(28)%Status
  64. WRITE (*,*) ' valve 33 ', data%state%manifold%Valve(33)%Status
  65. WRITE (*,*) ' valve 62 ', data%state%manifold%Valve(62)%Status
  66. WRITE (*,*) ' valve 36 ', data%state%manifold%Valve(36)%Status
  67. WRITE (*,*) ' valve 38 ', data%state%manifold%Valve(38)%Status
  68. ELSE ! flow through bell nipple
  69. k = data%State%FricPressDrop%NoHorizontalEl + data%State%FricPressDrop%NoStringEl + data%State%FricPressDrop%NoAnnulusEl
  70. data%State%FricPressDrop%KBOP = FlowEl(data%State%FricPressDrop%AnnulusLastEl)%Density / ((2.0 * 89158.0) * (0.26 * 0.61 * data%State%ShearRAM%MinimumOpenArea_InBOP)**2)
  71. GasPocketFlowInduced%Array(:) = MIN((0.1 / NoGasPocket * SQRT(data%State%PressureDisplay%PressureGauges(6) / data%State%FricPressDrop%KBOP)) , (0.05 * GasPocketNewVol%Array(:) * ConvFt3toUSgal / 60 / dt))
  72. WRITE (*,*) 'PressureGauges(6), KBOP', data%State%PressureDisplay%PressureGauges(6), data%State%FricPressDrop%KBOP
  73. WRITE (*,*) 'Initial guess after opening BOP =', GasPocketFlowInduced%Array(1)
  74. END IF
  75. END IF
  76. !!!!!!!!!!!!!!!!!!!!!!!!!
  77. !!!!!!!!!!!!!!!!!!!!!!!!! flowrates due to expansion of gas pockets or kick influx
  78. !i = AnnulusFirstEl
  79. !j = OpenholeFirstEl - 1
  80. IF (NoGasPocket > 0) THEN
  81. DO l = 1 , NoGasPocket !GasPocketFlowEl
  82. k = GasPocketFlowEl(l , 1)
  83. !WRITE (*,*) 'GasPocketFlowEl(l , 1)', l, k, j
  84. IF (k == 0) CALL ERRORSTOP('GasPocketFlowEl(l , 1) == 0', l)
  85. IF (k >= data%State%FricPressDrop%OpenholeFirstEl) THEN ! gas pocket is in open hole only
  86. FlowEl(k : data%State%FricPressDrop%NumbEl)%FlowRate = FlowEl(k : data%State%FricPressDrop%NumbEl)%FlowRate + GasPocketFlowInduced%Array(l) ! openhole elements above pocket
  87. FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = FlowEl(data%State%FricPressDrop%AnnulusFirstEl : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate + GasPocketFlowInduced%Array(l) ! annulus and choke line elements
  88. ELSE IF (k < data%State%FricPressDrop%OpenholeFirstEl) THEN ! gas pocket is in annulus ond/or choke line only
  89. FlowEl(k : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = FlowEl(k : data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate + GasPocketFlowInduced%Array(l) ! annulus or choke line elements above pocket
  90. END IF
  91. END DO
  92. END IF
  93. !!!!!!!!!!!!!!!!!!!!!!!!!
  94. !!!!! END - Determining flow rate in each section
  95. !!!!!!!!!!!!!!!!!!!!!!!!! effect of surge and swab on frictional pressure drop direction
  96. DO l = data%State%FricPressDrop%AnnulusFirstEl , data%State%FricPressDrop%OpenholeFirstEl - 1
  97. IF (FlowEl(l)%FlowRate < 0.0) THEN
  98. FlowEl(l)%FrictionDirection = -1
  99. IF (FlowEl(l)%FlowRate > -1.0 * PressFlowrateTolerance .AND. ALLOCATED(GasPocketWeight%Array)) FlowEl(l)%FlowRate = - PressFlowrateTolerance
  100. ELSE
  101. FlowEl(l)%FrictionDirection = 1
  102. IF (FlowEl(l)%FlowRate < PressFlowrateTolerance .AND. ALLOCATED(GasPocketWeight%Array)) FlowEl(l)%FlowRate = PressFlowrateTolerance
  103. END IF
  104. END DO
  105. !!!!!!!!!!!!!!!!!!!!!!!!!
  106. !!!!!!!!!!!!!!!!!!!!!!!!! Calculating Back Pressure, in well to pit path back pressure = 0
  107. ! in well to choke manifold path back pressure is equal to pressure before choke not casing pressure
  108. IF (ChokeKroneckerDelta == 1) THEN
  109. IF (FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate < 0.0) THEN
  110. WRITE (*,*) ' Negative choke flowrate'
  111. FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate = MAX((REAL(data%State%MudSystem%MudVolume_InjectedToBH) * ConvMintoSec / dt) , 10.0)
  112. END IF
  113. data%State%MudSystem%deltaPchoke = (data%State%FricPressDrop%Kchoke * FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate * ABS(FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%FlowRate)) * 1.d0
  114. IF (data%State%MudSystem%deltaPchoke < 0.d0) data%State%MudSystem%deltaPchoke = 0.d0
  115. data%State%FricPressDrop%BackPressure = REAL(data%State%MudSystem%deltaPchoke)
  116. ELSE
  117. data%State%FricPressDrop%BackPressure = 0.0
  118. END IF
  119. IF (IEEE_IS_NaN(data%State%FricPressDrop%BackPressure)) CALL ErrorStop('NaN in calculating back pressure' , FlowEl(j)%FlowRate)
  120. !write(*,*) 'BackPressure=' , BackPressure
  121. !!!!!!!!!!!!!!!!!!!!!!!!! when flow passes through choke manifold, solution process may be unstable
  122. IF (ChokeKroneckerDelta == 1) THEN ! thus we should stabilize solution
  123. IF (data%State%FricPressDrop%TotalOpenChokeArea > 0.5 * data%State%Choke%ChokeAreaFullyOpen) THEN
  124. KickCorrectionUnderRelaxation = 0.6
  125. ELSE IF (data%State%FricPressDrop%TotalOpenChokeArea > 0.1 * data%State%Choke%ChokeAreaFullyOpen) THEN
  126. KickCorrectionUnderRelaxation = 0.5
  127. ELSE ! TotalOpenChokeArea < 0.1 * ChokeAreaFullyOpen
  128. KickCorrectionUnderRelaxation = 0.4
  129. END IF
  130. ELSE
  131. KickCorrectionUnderRelaxation = 0.6
  132. END IF
  133. !!!!!!!!!!!!!!!!!!!!!!!!!
  134. !!!!!!!!!!!!!!!!!!!!!!!!! calculating frictional pressure drop in annulus, chooke line and open hole elements
  135. DO ifric = data%State%FricPressDrop%AnnulusFirstEl , data%State%FricPressDrop%NumbEl
  136. CALL FricPressDrop(ifric)
  137. !WRITE (*,*) ' element No, FlowRate , Density, FricPressLoss', ifric, FlowEl(ifric)%FlowRate, FlowEl(ifric)%Density, FlowEl(ifric)%FricPressLoss
  138. IF (IEEE_IS_NaN(FlowEl(ifric)%FricPressLoss)) THEN
  139. WRITE (*,*) 'H, S, A, Ch, O', data%State%FricPressDrop%NoHorizontalEl , data%State%FricPressDrop%NoStringEl , data%State%FricPressDrop%NoAnnulusEl , data%State%FricPressDrop%NoWellToChokeEl , data%State%FricPressDrop%NoOpenHoleEl
  140. WRITE (*,*) 'Ann/Op start, end, density, Q, mu, Type' , FlowEl(ifric)%StartX, FlowEl(ifric)%EndX, FlowEl(ifric)%Density, FlowEl(ifric)%FlowRate, FlowEl(ifric)%mueff, FlowEl(ifric)%MaterialType
  141. CALL ErrorStop('NaN in calculating pressure drop' , ifric)
  142. END IF
  143. END DO
  144. !!!!!!!!!!!!!!!!!!!!!!!!! Pressure distribution in annulus
  145. j = data%State%FricPressDrop%OpenholeFirstEl - 1
  146. FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%EndPress = data%State%FricPressDrop%BackPressure
  147. FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%StartPress = FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%EndPress + FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%FricPressLoss + FlowEl(data%State%FricPressDrop%OpenholeFirstEl - 1)%StaticPressDiff
  148. DO l = data%State%FricPressDrop%OpenholeFirstEl - 2 , data%State%FricPressDrop%AnnulusFirstEl , -1
  149. !WRITE (*,*) '123'
  150. FlowEl(l)%EndPress = FlowEl(l + 1)%StartPress
  151. FlowEl(l)%StartPress = FlowEl(l)%EndPress + FlowEl(l)%FricPressLoss + FlowEl(l)%StaticPressDiff
  152. END DO
  153. !!!!!!!!!!!!!!!!! Pressure distribution in Open Hole
  154. FlowEl(data%State%FricPressDrop%NumbEl)%EndPress = FlowEl(data%State%FricPressDrop%AnnulusFirstEl)%StartPress
  155. FlowEl(data%State%FricPressDrop%NumbEl)%StartPress = FlowEl(data%State%FricPressDrop%NumbEl)%EndPress + FlowEl(data%State%FricPressDrop%NumbEl)%FricPressLoss + FlowEl(data%State%FricPressDrop%NumbEl)%StaticPressDiff
  156. DO l = data%State%FricPressDrop%NumbEl - 1 , data%State%FricPressDrop%OpenholeFirstEl , -1
  157. !WRITE(*,*) ' ope'
  158. FlowEl(l)%EndPress = FlowEl(l + 1)%StartPress
  159. FlowEl(l)%StartPress = FlowEl(l)%EndPress + FlowEl(l)%FricPressLoss + FlowEl(l)%StaticPressDiff
  160. !WRITE (*,*) ' Length, static, frictional open' , FlowEl(i)%Length, FlowEl(i)%StaticPressDiff, FlowEl(i)%FricPressLoss
  161. !END IF
  162. END DO
  163. ELSE ! wellhead is closed and kick is in the well
  164. !WRITE (*,*) ' well head is closed'
  165. k = GasPocketFlowEl(NoGasPocket , 1)
  166. !WRITE (*,*) 'k, Pocket Press', k, GasPocketOldPress%Array(NoGasPocket) - StandardPress
  167. i = data%State%FricPressDrop%AnnulusFirstEl
  168. j = data%State%FricPressDrop%OpenholeFirstEl - 1
  169. FlowEl(k)%StartPress = GasPocketOldPress%Array(NoGasPocket) - StandardPress
  170. FlowEl(k)%EndPress = GasPocketOldPress%Array(NoGasPocket) - StandardPress
  171. IF (k > data%State%FricPressDrop%OpenholeFirstEl - 1) THEN ! Top pocket StartX is in Open hole
  172. !WRITE (*,*) 'here 1'
  173. DO l = k - 1 , data%State%FricPressDrop%OpenholeFirstEl , -1 ! below elements in openhole
  174. !WRITE (*,*) 'here 1-1'
  175. FlowEl(l)%EndPress = FlowEl(l + 1)%StartPress
  176. FlowEl(l)%StartPress = FlowEl(l)%EndPress + FlowEl(l)%StaticPressDiff
  177. END DO
  178. DO l = k + 1 , data%State%FricPressDrop%NumbEl ! Above elements in openhole
  179. !WRITE (*,*) 'here 1-2'
  180. FlowEl(l)%StartPress = FlowEl(l - 1)%EndPress
  181. FlowEl(l)%EndPress = FlowEl(l)%StartPress - FlowEl(l)%StaticPressDiff
  182. END DO
  183. FlowEl(data%State%FricPressDrop%AnnulusFirstEl)%StartPress = FlowEl(data%State%FricPressDrop%NumbEl)%EndPress
  184. FlowEl(data%State%FricPressDrop%AnnulusFirstEl)%EndPress = FlowEl(data%State%FricPressDrop%AnnulusFirstEl)%StartPress - FlowEl(data%State%FricPressDrop%AnnulusFirstEl)%StaticPressDiff
  185. DO l = data%State%FricPressDrop%AnnulusFirstEl + 1 , data%State%FricPressDrop%OpenholeFirstEl - 1
  186. FlowEl(l)%StartPress = FlowEl(l - 1)%EndPress
  187. FlowEl(l)%EndPress = FlowEl(l)%StartPress - FlowEl(l)%StaticPressDiff
  188. END DO
  189. ELSE ! Top pocket StartX is in annulus or choke line
  190. DO l = k - 1 , data%State%FricPressDrop%AnnulusFirstEl , -1 ! below elements in annnulus
  191. FlowEl(l)%EndPress = FlowEl(l + 1)%StartPress
  192. FlowEl(l)%StartPress = FlowEl(l)%EndPress + FlowEl(l)%StaticPressDiff
  193. END DO
  194. DO l = k + 1 , data%State%FricPressDrop%OpenholeFirstEl - 1 ! Above elements in annulus
  195. FlowEl(l)%StartPress = FlowEl(l - 1)%EndPress
  196. FlowEl(l)%EndPress = FlowEl(l)%StartPress - FlowEl(l)%StaticPressDiff
  197. END DO
  198. FlowEl(data%State%FricPressDrop%NumbEl)%EndPress = FlowEl(data%State%FricPressDrop%AnnulusFirstEl)%StartPress
  199. FlowEl(data%State%FricPressDrop%NumbEl)%StartPress = FlowEl(data%State%FricPressDrop%NumbEl)%EndPress + FlowEl(data%State%FricPressDrop%NumbEl)%StaticPressDiff
  200. DO l = data%State%FricPressDrop%NumbEl - 1 , data%State%FricPressDrop%OpenholeFirstEl , -1
  201. FlowEl(l)%EndPress = FlowEl(l + 1)%StartPress
  202. FlowEl(l)%StartPress = FlowEl(l)%EndPress + FlowEl(l)%StaticPressDiff
  203. END DO
  204. END IF
  205. END IF
  206. !!!!!!!!!!!!!!!!!!!!!! checking pressure for preventing NaN in pressures
  207. DO l = data%State%FricPressDrop%OpenholeFirstEl - 1 , data%State%FricPressDrop%AnnulusFirstEl , -1 ! annulus or choke elements
  208. !WRITE (*,*) 'start, end' , FlowEl(i)%StartX, FlowEl(i)%EndX
  209. IF (IEEE_IS_NaN(FlowEl(l)%EndPress)) THEN
  210. WRITE (*,*) 'H, S, A, Ch, O', data%State%FricPressDrop%NoHorizontalEl , data%State%FricPressDrop%NoStringEl , data%State%FricPressDrop%NoAnnulusEl , data%State%FricPressDrop%NoWellToChokeEl , data%State%FricPressDrop%NoOpenHoleEl
  211. WRITE (*,*) 'Ann/Ch start, end, density, Q, mu' , FlowEl(l)%StartX, FlowEl(l)%EndX, FlowEl(l)%Density, FlowEl(l)%FlowRate, FlowEl(l)%mueff, FlowEl(l)%MaterialType
  212. CALL ERRORSTOP('NaN in EndPress', l)
  213. END IF
  214. END DO
  215. DO l = data%State%FricPressDrop%NumbEl , data%State%FricPressDrop%OpenholeFirstEl - 1 , -1 ! op elements
  216. !WRITE (*,*) 'start, end' , FlowEl(i)%StartX, FlowEl(i)%EndX
  217. IF (IEEE_IS_NaN(FlowEl(l)%EndPress)) THEN
  218. WRITE (*,*) 'H, S, A, Ch, O', data%State%FricPressDrop%NoHorizontalEl , data%State%FricPressDrop%NoStringEl , data%State%FricPressDrop%NoAnnulusEl , data%State%FricPressDrop%NoWellToChokeEl , data%State%FricPressDrop%NoOpenHoleEl
  219. WRITE (*,*) 'Op start, end, density, Q, mu' , FlowEl(l)%StartX, FlowEl(l)%EndX, FlowEl(l)%Density, FlowEl(l)%FlowRate, FlowEl(l)%mueff, FlowEl(l)%MaterialType
  220. CALL ERRORSTOP('NaN in EndPress', l)
  221. END IF
  222. END DO
  223. !!!!!!!!!!!!!!!!!!!!!!
  224. !!!!!!!!!!!!!!!!!!!!!!
  225. BottomHolePress = FlowEl(data%State%FricPressDrop%OpenholeFirstEl)%StartPress
  226. !!!!!!!!!!!!!!!!!!!!!!
  227. END SUBROUTINE