common.jl 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. """
  2. lexicographic(II, n)
  3. Returns the index of type `Int` corresponding to the 1D view of a `n × n` array at the CartesianIndex `II`.
  4. """
  5. @inline lexicographic(II, n) = muladd(n, II[2]-1, II[1])
  6. @inline within_bounds(i, grid) = 1 <= i <= grid.nx*grid.ny
  7. @inline within_bounds(i::CartesianIndex, grid) = 1 <= i[1] <= grid.ny && 1 <= i[2] <= grid.nx
  8. const newaxis = [CartesianIndex()]
  9. @inline δy⁺(II) = CartesianIndex(II[1]+1, II[2])
  10. @inline δy⁻(II) = CartesianIndex(II[1]-1, II[2])
  11. @inline δx⁺(II) = CartesianIndex(II[1], II[2]+1)
  12. @inline δx⁻(II) = CartesianIndex(II[1], II[2]-1)
  13. @inline δy⁺(II, ny, per) = per && II[1]==ny ? CartesianIndex(1, II[2]) : δy⁺(II)
  14. @inline δy⁻(II, ny, per) = per && II[1]==1 ? CartesianIndex(ny, II[2]) : δy⁻(II)
  15. @inline δx⁺(II, nx, per) = per && II[2]==nx ? CartesianIndex(II[1], 1) : δx⁺(II)
  16. @inline δx⁻(II, nx, per) = per && II[2]==1 ? CartesianIndex(II[1], nx) : δx⁻(II)
  17. @inline zeros(g::Grid) = zeros(g.ny, g.nx)
  18. @inline zeros(a::Integer, g::Grid) = zeros(a, g.ny, g.nx)
  19. @inline zeros(g::Grid, a::Integer) = zeros(g.ny, g.nx, a)
  20. @inline fzeros(g::Grid) = zeros(g.ny * g.nx)
  21. @inline fzeros(a::Integer, g::Grid) = zeros(a, g.ny * g.nx)
  22. @inline fzeros(g::Grid, a::Integer) = zeros(g.ny * g.nx, a)
  23. @inline f2zeros(g::Grid) = zeros(2 * g.ny * g.nx)
  24. @inline f2zeros(a::Integer, g::Grid) = zeros(a, 2 * g.ny * g.nx)
  25. @inline f2zeros(g::Grid, a::Integer) = zeros(2 * g.ny * g.nx, a)
  26. @inline f3zeros(g::Grid) = zeros(2 * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  27. @inline f3zeros(a::Integer, g::Grid) = zeros(a, 2 * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  28. @inline f3zeros(g::Grid, a::Integer) = zeros(2 * g.ny * g.nx + 2 * g.nx + 2 * g.ny, a)
  29. @inline fnzeros(g::Grid, n::Numerical) = zeros((n.nLS + 1) * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  30. @inline fnzeros(a::Integer, g::Grid, n::Numerical) = zeros(a, (n.nLS + 1) * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  31. @inline fnzeros(g::Grid, n::Numerical, a::Integer) = zeros((n.nLS + 1) * g.ny * g.nx + 2 * g.nx + 2 * g.ny, a)
  32. @inline ones(g::Grid) = ones(g.ny, g.nx)
  33. @inline ones(a::Integer, g::Grid) = ones(a, g.ny, g.nx)
  34. @inline ones(g::Grid, a::Integer) = ones(g.ny, g.nx,a)
  35. @inline fones(g::Grid) = ones(g.ny * g.nx)
  36. @inline fones(a::Integer, g::Grid) = ones(a, g.ny * g.nx)
  37. @inline fones(g::Grid, a::Integer) = ones(g.ny * g.nx, a)
  38. @inline f2ones(g::Grid) = ones(2 * g.ny * g.nx)
  39. @inline f2ones(a::Integer, g::Grid) = ones(a, 2 * g.ny * g.nx)
  40. @inline f2ones(g::Grid, a::Integer) = ones(2 * g.ny * g.nx, a)
  41. @inline f3ones(g::Grid) = ones(2 * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  42. @inline f3ones(a::Integer, g::Grid) = ones(a, 2 * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  43. @inline f3ones(g::Grid, a::Integer) = ones(2 * g.ny * g.nx + 2 * g.nx + 2 * g.ny, a)
  44. @inline fnones(g::Grid, n::Numerical) = ones((n.nLS + 1) * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  45. @inline fnones(a::Integer, g::Grid, n::Numerical) = ones(a, (n.nLS + 1) * g.ny * g.nx + 2 * g.nx + 2 * g.ny)
  46. @inline fnones(g::Grid, n::Numerical, a::Integer) = ones((n.nLS + 1) * g.ny * g.nx + 2 * g.nx + 2 * g.ny, a)
  47. @inline reshape(a, g::Grid) = reshape(a, (g.ny, g.nx))
  48. # Temporary function to get a certain field from a vector with
  49. # multiple fields. To be removed when working with decomposed
  50. # vectors directly
  51. """
  52. Access bulk (p=1) or interfacial value (from Levelset)
  53. """
  54. veci(a, g::G, p::Integer = 1) where {G<:Grid} = @view a[g.ny*g.nx*(p-1)+1:g.ny*g.nx*p]
  55. """
  56. Access bulk value
  57. """
  58. vec1(a, g::G) where {G<:Grid} = @view a[1:g.ny*g.nx]
  59. """
  60. Access interfacial value from Levelset 1
  61. """
  62. vec2(a, g::G) where {G<:Grid} = @view a[g.ny*g.nx+1:g.ny*g.nx*2]
  63. """
  64. Access interfacial value from Levelset 2
  65. """
  66. vec3(a, g::G) where {G<:Grid} = @view a[g.ny*g.nx*2+1:g.ny*g.nx*3]
  67. """
  68. Access border value
  69. """
  70. vecb(a, g::G) where {G<:Grid} = @view a[end-2*g.ny-2*g.nx+1:end]
  71. """
  72. Access border value: left
  73. """
  74. vecb_L(a,g::G) where {G<:Grid} = @view vecb(a, g)[1:g.ny]
  75. """
  76. Access border value: bottom
  77. """
  78. vecb_B(a,g::G) where {G<:Grid} = @view vecb(a, g)[g.ny+1:g.ny+g.nx]
  79. """
  80. Access border value: right
  81. """
  82. vecb_R(a,g::G) where {G<:Grid} = @view vecb(a, g)[g.ny+g.nx+1:2*g.ny+g.nx]
  83. """
  84. Access border value: top
  85. """
  86. vecb_T(a,g::G) where {G<:Grid} = @view vecb(a, g)[2*g.ny+g.nx+1:2*g.ny+2*g.nx]
  87. """
  88. Access border value: left (border part already extracted, for op.opC_pL.Gx_b for ex)
  89. """
  90. left_border_view(a,g::G) where {G<:Grid} = @view a[1:g.ny]
  91. """
  92. Access border value: bottom (border part already extracted, for op.opC_pL.Gx_b for ex)
  93. """
  94. bottom_border_view(a,g::G) where {G<:Grid} = @view a[g.ny+1:g.ny+g.nx]
  95. """
  96. Access border value: right (border part already extracted, for op.opC_pL.Gx_b for ex)
  97. """
  98. right_border_view(a,g::G) where {G<:Grid} = @view a[g.ny+g.nx+1:2*g.ny+g.nx]
  99. """
  100. Access border value: top (border part already extracted, for op.opC_pL.Gx_b for ex)
  101. """
  102. top_border_view(a,g::G) where {G<:Grid} = @view a[2*g.ny+g.nx+1:2*g.ny+2*g.nx]
  103. function veci(a, g::Vector{G}, p::Integer) where {G<:Grid}
  104. c0 = 1
  105. c1 = g[1].ny * g[1].nx
  106. for i = 2:p
  107. ii = (p - 1) ÷ 2 + 1
  108. c0 += g[ii].ny * g[ii].nx
  109. c1 += g[ii].ny * g[ii].nx
  110. end
  111. return @view a[c0:c1]
  112. end
  113. """
  114. volume(geo::GeometricInfo)
  115. Compute the volume of a phase.
  116. """
  117. @inline volume(geo::GeometricInfo) = sum(geo.dcap[:,:,5])
  118. @inline volume(geo::GeometricInfo, id::AbstractMatrix) = sum(geo.dcap[id,5])
  119. @inline opposite(α) = ifelse(α >= 0. ,α - π, α + π)
  120. @inline distance(A::Point, B::Point, dx=1.0, dy=1.0) =
  121. sqrt(((A.x-B.x)*dx)^2 + ((A.y-B.y)*dy)^2)
  122. @inline distance(xp, yp, θ, xl, yl) = abs(cos(θ) * (yl - yp) - sin(θ) * (xl - xp))
  123. @inline midpoint(A::Point, B::Point) = Point((A.x + B.x)/2 - 0.5, (A.y + B.y)/2 - 0.5)
  124. @inline indomain(A::Point{T}, x::Vector{T}, y::Vector{T}) where {T} =
  125. ifelse(A.x >= x[1] && A.x <= x[end] &&
  126. A.y >= y[1] && A.y <= y[end], true, false)
  127. @inline <(A::Point{T}, L::T) where {T} = ifelse(abs(A.x) <= L/2 && abs(A.y) <= L/2, true, false)
  128. @inline isnan(A::Point{T}) where {T} = ifelse(isnan(A.x) || isnan(A.y), true, false)
  129. @inline +(A::Point{T}, B::Point{T}) where {T} = Point(A.x + B.x, A.y + B.y)
  130. @inline -(A::Point{T}, B::Point{T}) where {T} = Point(A.x - B.x, A.y - B.y)
  131. @inline *(A::Point{T}, m::N) where {T, N} = Point(m*A.x, m*A.y)
  132. @inline *(m::N, A::Point{T}) where {T, N} = Point(m*A.x, m*A.y)
  133. @inline *(A::Point{T}, B::Point{T}) where {T} = Point(A.x*B.x, A.y*B.y)
  134. @inline abs(A::Point) = Point(abs(A.x), abs(A.y))
  135. @inline mysign(a,b) = a/sqrt(a^2 + b^2)
  136. @inline mysign(a) = ifelse(a >= 0, 1, -1)
  137. @inline ⁺(a) = max(a,0)
  138. @inline ⁻(a) = min(a,0)
  139. @inline c∇x(u, II) = @inbounds u[δx⁺(II)] - u[δx⁻(II)]
  140. @inline c∇y(u, II) = @inbounds u[δy⁺(II)] - u[δy⁻(II)]
  141. @inline c∇x(u, II, nx, per) = @inbounds u[δx⁺(II, nx, per)] - u[δx⁻(II, nx, per)]
  142. @inline c∇y(u, II, ny, per) = @inbounds u[δy⁺(II, ny, per)] - u[δy⁻(II, ny, per)]
  143. @inline c∇x(u, II, h) = @inbounds (u[δx⁺(II)] - u[δx⁻(II)])/2h
  144. @inline c∇y(u, II, h) = @inbounds (u[δy⁺(II)] - u[δy⁻(II)])/2h
  145. @inline c∇x(u, II, h, nx, per) = @inbounds (u[δx⁺(II, nx, per)] - u[δx⁻(II, nx, per)])/h
  146. @inline c∇y(u, II, h, ny, per) = @inbounds (u[δy⁺(II, ny, per)] - u[δy⁻(II, ny, per)])/h
  147. @inline ∇x⁺(u, II) = @inbounds u[δx⁺(II)] - u[II]
  148. @inline ∇y⁺(u, II) = @inbounds u[δy⁺(II)] - u[II]
  149. @inline ∇x⁻(u, II) = @inbounds u[δx⁻(II)] - u[II]
  150. @inline ∇y⁻(u, II) = @inbounds u[δy⁻(II)] - u[II]
  151. @inline ∇x⁺(u, II, nx, per) = @inbounds u[δx⁺(II, nx, per)] - u[II]
  152. @inline ∇y⁺(u, II, ny, per) = @inbounds u[δy⁺(II, ny, per)] - u[II]
  153. @inline ∇x⁻(u, II, nx, per) = @inbounds u[δx⁻(II, nx, per)] - u[II]
  154. @inline ∇y⁻(u, II, ny, per) = @inbounds u[δy⁻(II, ny, per)] - u[II]
  155. @inline ∇x⁺(u, II, nx, h, per) = @inbounds (u[δx⁺(II, nx, per)] - u[II]) / h[II]
  156. @inline ∇y⁺(u, II, ny, h, per) = @inbounds (u[δy⁺(II, ny, per)] - u[II]) / h[II]
  157. @inline ∇x⁻(u, II, nx, h, per) = @inbounds (u[II] - u[δx⁻(II, nx, per)]) / h[II]
  158. @inline ∇y⁻(u, II, ny, h, per) = @inbounds (u[II] - u[δy⁻(II, ny, per)]) / h[II]
  159. @inline normal(u, II) = @SVector [mysign(c∇x(u, II), c∇y(u, II)), mysign(c∇y(u, II), c∇x(u, II))]
  160. @inline minmod(a, b) = ifelse(a*b <= 0, 0.0, myabs(a,b))
  161. @inline myabs(a, b) = ifelse(abs(a) < abs(b), a, b)
  162. @inline Dxx(u, II, dx) = @inbounds (2.0 * (u[δx⁺(II)] - u[II]) / (dx[δx⁺(II)] + dx[II]) -
  163. 2.0 * (u[II] - u[δx⁻(II)]) / (dx[δx⁻(II)] + dx[II])) / dx[II]
  164. @inline Dyy(u, II, dy) = @inbounds (2.0 * (u[δy⁺(II)] - u[II]) / (dy[δy⁺(II)] + dy[II]) -
  165. 2.0 * (u[II] - u[δy⁻(II)]) / (dy[δy⁻(II)] + dy[II])) / dy[II]
  166. @inline Dxx(u, II, dx, nx, per) = @inbounds (2.0 * (u[δx⁺(II, nx, per)] - u[II]) / (dx[δx⁺(II, nx, per)] + dx[II]) -
  167. 2.0 * (u[II] - u[δx⁻(II, nx, per)]) / (dx[δx⁻(II, nx, per)] + dx[II])) / dx[II]
  168. @inline Dxx_l(u, II, dx, nx, per) = @inbounds (2.0 * (u[δx⁺(δx⁺(II))] - u[δx⁺(II)]) / (dx[δx⁺(δx⁺(II))] + dx[δx⁺(II)]) -
  169. 2.0 * (u[δx⁺(II)] - u[II]) / (dx[δx⁺(II)] + dx[II])) / dx[δx⁺(II)]
  170. @inline Dxx_r(u, II, dx, nx, per) = @inbounds (2.0 * (u[II] - u[δx⁻(II)]) / (dx[II] + dx[δx⁻(II)]) -
  171. 2.0 * (u[δx⁻(II)] - u[δx⁻(δx⁻(II))]) / (dx[δx⁻(II)] + dx[δx⁻(δx⁻(II))])) / dx[δx⁻(II)]
  172. @inline Dyy(u, II, dy, ny, per) = @inbounds (2.0 * (u[δy⁺(II, ny, per)] - u[II]) / (dy[δy⁺(II, ny, per)] + dy[II]) -
  173. 2.0 * (u[II] - u[δy⁻(II, ny, per)]) / (dy[δy⁻(II, ny, per)] + dy[II])) / dy[II]
  174. @inline Dyy_b(u, II, dy, ny, per) = @inbounds (2.0 * (u[δy⁺(δy⁺(II))] - u[δy⁺(II)]) / (dy[δy⁺(δy⁺(II))] + dy[δy⁺(II)]) -
  175. 2.0 * (u[δy⁺(II)] - u[II]) / (dy[δy⁺(II)] + dy[II])) / dy[δy⁺(II)]
  176. @inline Dyy_t(u, II, dy, ny, per) = @inbounds (2.0 * (u[II] - u[δy⁻(II)]) / (dy[II] + dy[δy⁻(II)]) -
  177. 2.0 * (u[δy⁻(II)] - u[δy⁻(δy⁻(II))]) / (dy[δy⁻(II)] + dy[δy⁻(δy⁻(II))])) / dy[δy⁻(II)]
  178. @inline Dxx(u, II) = @inbounds u[δx⁺(II)] - 2u[II] + u[δx⁻(II)]
  179. @inline Dyy(u, II) = @inbounds u[δy⁺(II)] - 2u[II] + u[δy⁻(II)]
  180. @inline Dxx(u, II, nx, per) = @inbounds u[δx⁺(II, nx, per)] - 2u[II] + u[δx⁻(II, nx, per)]
  181. @inline Dxx_l(u, II, nx, per) = @inbounds ifelse(per, u[δx⁺(II, nx, per)] - 2u[II] + u[δx⁻(II, nx, per)],
  182. u[δx⁺(δx⁺(II))] - 2*u[δx⁺(II)] + u[II])
  183. @inline Dxx_r(u, II, nx, per) = @inbounds ifelse(per, u[δx⁺(II, nx, per)] - 2u[II] + u[δx⁻(II, nx, per)],
  184. u[δx⁻(δx⁻(II))] - 2*u[δx⁻(II)] + u[II])
  185. @inline Dyy(u, II, ny, per) = @inbounds u[δy⁺(II, ny, per)] - 2u[II] + u[δy⁻(II, ny, per)]
  186. @inline Dyy_b(u, II, ny, per) = @inbounds ifelse(per, u[δy⁺(II, ny, per)] - 2u[II] + u[δy⁻(II, ny, per)],
  187. u[δy⁺(δy⁺(II))] - 2*u[δy⁺(II)] + u[II])
  188. @inline Dyy_t(u, II, ny, per) = @inbounds ifelse(per, u[δy⁺(II, ny, per)] - 2u[II] + u[δy⁻(II, ny, per)],
  189. u[δy⁻(δy⁻(II))] - 2*u[δy⁻(II)] + u[II])
  190. @inline Dxy(u, II, h) = @inbounds (u[δx⁻(δy⁻(II))] + u[δx⁺(δy⁺(II))] - u[δx⁻(δy⁺(II))] - u[δx⁺(δy⁻(II))])/4h^2
  191. function smekerka_curvature(u, II, h)
  192. gx = c∇x(u, II, h)
  193. gy = c∇y(u, II, h)
  194. gxx = Dxx(u, II, h)
  195. gyy = Dyy(u, II, h)
  196. gxy = Dxy(u, II, h)
  197. k = (gxx + gyy)/(gx^2 + gy^2)^0.5
  198. return k
  199. end
  200. @inline in_bounds(a, n) = ifelse(a > 2 && a < n-1, true, false)
  201. @inline in_bounds(a, n, per) = per ? ifelse(a > 1 && a < n, true, false) : in_bounds(a, n)
  202. """
  203. Compute a 3x3 stencil around the given CartesianIndex `II` in the 2D array `a`.
  204. This function takes a 2D array `a` and a `CartesianIndex` `II`, and returns a 3x3 stencil centered around the element at `II`.
  205. The stencil is computed by extracting the values from the array `a` at the relative positions around `II`.
  206. # Arguments
  207. - `a`: A 2D array (matrix) of type `SA_F64` (assumed to be a subtype of `AbstractArray`).
  208. - `II`: A `CartesianIndex` specifying the position in the 2D array `a` around which the stencil is computed.
  209. # Returns
  210. - A 3x3 matrix of type `SA_F64` representing the stencil.
  211. """
  212. @inline function static_stencil(a, II::CartesianIndex)
  213. return @inbounds SA_F64[a[II.I[1]-1, II.I[2]-1] a[II.I[1]-1, II.I[2]] a[II.I[1]-1, II.I[2]+1];
  214. a[II.I[1], II.I[2]-1] a[II.I[1], II.I[2]] a[II.I[1], II.I[2]+1];
  215. a[II.I[1]+1, II.I[2]-1] a[II.I[1]+1, II.I[2]] a[II.I[1]+1, II.I[2]+1]]
  216. end
  217. """
  218. Compute a 3x3 stencil around the given CartesianIndex `II` in the 2D array `a` with peiodicity information.
  219. This function takes a 2D array `a` and a `CartesianIndex` `II`, and returns a 3x3 stencil centered around the element at `II`.
  220. The stencil is computed by extracting the values from the array `a` at the relative positions around `II`.
  221. # Arguments
  222. - `a`: A 2D array (matrix) of type `SA_F64` (assumed to be a subtype of `AbstractArray`).
  223. - `II`: A `CartesianIndex` specifying the position in the 2D array `a` around which the stencil is computed.
  224. # Returns
  225. - A 3x3 matrix of type `SA_F64` representing the stencil.
  226. """
  227. @inline function static_stencil(a, II::CartesianIndex, nx, ny, per_x, per_y)
  228. return @inbounds SA_F64[a[δx⁻(δy⁻(II, ny, per_y), nx, per_x)] a[δy⁻(II, ny, per_y)] a[δx⁺(δy⁻(II, ny, per_y), nx, per_x)];
  229. a[δx⁻(II, nx, per_x)] a[II] a[δx⁺(II, nx, per_x)];
  230. a[δx⁻(δy⁺(II, ny, per_y), nx, per_x)] a[δy⁺(II, ny, per_y)] a[δx⁺(δy⁺(II, ny, per_y), nx, per_x)]]
  231. end
  232. function debug_val(test)
  233. print("\n test ",string(test)," ",typeof(test)," ",test)
  234. end
  235. @inline function static_stencil_debug(a, II::CartesianIndex, nx, ny, per_x, per_y)
  236. print("\n a ",typeof(a))
  237. test = II
  238. print("\n II ",test," ",typeof(test))
  239. test = nx
  240. print("\n test ",test," ",typeof(test))
  241. test = ny
  242. print("\n test ",test," ",typeof(test))
  243. debug_val(per_x)
  244. debug_val(per_y)
  245. debug_val(δy⁻(II, ny, per_y))
  246. debug_val(δx⁻(δy⁻(II, ny, per_y), nx, per_x))
  247. debug_val(δx⁺(δy⁻(II, ny, per_y), nx, per_x))
  248. debug_val(δx⁻(II, nx, per_x))
  249. debug_val(δx⁺(II, nx, per_x))
  250. debug_val(δy⁺(II, ny, per_y))
  251. debug_val(δx⁻(δy⁺(II, ny, per_y), nx, per_x))
  252. debug_val(δx⁺(δy⁺(II, ny, per_y), nx, per_x))
  253. # print("\n per_x ",typeof(per_x))
  254. # print("\n per_y ",typeof(per_y))
  255. # print("\n dy- ",typeof(δy⁻(II, ny, per_y)))
  256. # print("\n d ",typeof(δx⁻(δy⁻(II, ny, per_y), nx, per_x)))
  257. # print("\n d ",typeof(δx⁺(δy⁻(II, ny, per_y), nx, per_x)))
  258. # print("\n d ",typeof(δx⁻(II, nx, per_x)))
  259. # print("\n d ",typeof(δx⁺(II, nx, per_x)))
  260. # print("\n d ",typeof(δy⁺(II, ny, per_y)))
  261. # print("\n d ",typeof(δx⁻(δy⁺(II, ny, per_y), nx, per_x)))
  262. # print("\n d ",typeof(δx⁺(δy⁺(II, ny, per_y), nx, per_x)))
  263. return @inbounds SA_F64[a[δx⁻(δy⁻(II, ny, per_y), nx, per_x)] a[δy⁻(II, ny, per_y)] a[δx⁺(δy⁻(II, ny, per_y), nx, per_x)];
  264. a[δx⁻(II, nx, per_x)] a[II] a[δx⁺(II, nx, per_x)];
  265. a[δx⁻(δy⁺(II, ny, per_y), nx, per_x)] a[δy⁺(II, ny, per_y)] a[δx⁺(δy⁺(II, ny, per_y), nx, per_x)]]
  266. end
  267. """
  268. 2.3.2.2 Biquadratic interpolation of the level-set ? or here f function
  269. """
  270. @inline function B_BT(II, x, y, f=x->x)
  271. B = inv((@SMatrix [((x[f(δx⁻(II))]-x[II])/(x[f(δx⁺(II))] - x[f(δx⁻(II))]))^2 (x[f(δx⁻(II))]-x[II])/(x[f(δx⁺(II))] - x[f(δx⁻(II))]) 1.0;
  272. ((x[f(II)]-x[II])/(x[f(δx⁺(II))] - x[f(δx⁻(II))]))^2 (x[f(II)]-x[II])/(x[f(δx⁺(II))] - x[f(δx⁻(II))]) 1.0;
  273. ((x[f(δx⁺(II))]-x[II])/(x[f(δx⁺(II))] - x[f(δx⁻(II))]))^2 (x[f(δx⁺(II))]-x[II])/(x[f(δx⁺(II))] - x[f(δx⁻(II))]) 1.0]))
  274. BT = inv((@SMatrix [((y[f(δy⁻(II))]-y[II])/(y[f(δy⁺(II))] - y[f(δy⁻(II))]))^2 ((y[f(II)]-y[II])/(y[f(δy⁺(II))] - y[f(δy⁻(II))]))^2 ((y[f(δy⁺(II))]-y[II])/(y[f(δy⁺(II))] - y[f(δy⁻(II))]))^2;
  275. (y[f(δy⁻(II))]-y[II])/(y[f(δy⁺(II))] - y[f(δy⁻(II))]) (y[f(II)]-y[II])/(y[f(δy⁺(II))] - y[f(δy⁻(II))]) (y[f(δy⁺(II))]-y[II])/(y[f(δy⁺(II))] - y[f(δy⁻(II))]);
  276. 1.0 1.0 1.0]))
  277. return B, BT
  278. end
  279. """
  280. 2.3.2.2 Biquadratic interpolation of the level-set ?
  281. """
  282. @inline function B_BT(II::CartesianIndex, grid::G, per_x, per_y) where {G<:Grid}
  283. @unpack x, y, nx, ny, dx, dy = grid
  284. _dx = dx[II]
  285. _dy = dy[II]
  286. dx⁺ = 0.5 * (dx[II] + dx[δx⁺(II, nx, per_x)])
  287. dx⁻ = 0.5 * (dx[δx⁻(II, nx, per_x)] + dx[II])
  288. dy⁺ = 0.5 * (dy[II] + dy[δy⁺(II, ny, per_y)])
  289. dy⁻ = 0.5 * (dy[δy⁻(II, ny, per_y)] + dy[II])
  290. B = inv((@SMatrix [(dx⁻/_dx)^2 -dx⁻/_dx 1.0;
  291. 0.0 0.0 1.0;
  292. (dx⁺/_dx)^2 dx⁺/_dx 1.0]))
  293. BT = inv((@SMatrix [(dy⁻/_dy)^2 0.0 (dy⁺/_dy)^2;
  294. -dy⁻/_dy 0.0 dy⁺/_dy;
  295. 1.0 1.0 1.0]))
  296. return B, BT
  297. end
  298. """
  299. 2.3.2.2 Biquadratic interpolation of the level-set ?
  300. """
  301. @inline function B_BT(II::CartesianIndex, grid::G) where {G<:Grid}
  302. B = inv(@SMatrix [0.25 -0.5 1.0;
  303. 0.0 0.0 1.0;
  304. 0.25 0.5 1.0])
  305. BT = inv(@SMatrix [0.25 -0.5 1.0;
  306. 0.0 0.0 1.0;
  307. 0.25 0.5 1.0])
  308. return B, BT
  309. end
  310. @inline big_static_stencil(a, II::CartesianIndex) = @inbounds @SMatrix [a[II.I[1]-2, II.I[2]-2] a[II.I[1]-2, II.I[2]-1] a[II.I[1]-2, II.I[2]] a[II.I[1]-2, II.I[2]+1] a[II.I[1]-2, II.I[2]+2];
  311. a[II.I[1]-1, II.I[2]-2] a[II.I[1]-1, II.I[2]-1] a[II.I[1]-1, II.I[2]] a[II.I[1]-1, II.I[2]+1] a[II.I[1]-1, II.I[2]+2];
  312. a[II.I[1], II.I[2]-2] a[II.I[1], II.I[2]-1] a[II.I[1], II.I[2]] a[II.I[1], II.I[2]+1] a[II.I[1], II.I[2]+2];
  313. a[II.I[1]+1, II.I[2]-2] a[II.I[1]+1, II.I[2]-1] a[II.I[1]+1, II.I[2]] a[II.I[1]+1, II.I[2]+1] a[II.I[1]+1, II.I[2]+2];
  314. a[II.I[1]+2, II.I[2]-2] a[II.I[1]+2, II.I[2]-1] a[II.I[1]+2, II.I[2]] a[II.I[1]+2, II.I[2]+1] a[II.I[1]+2, II.I[2]+2]]
  315. @inline function mean_curvature(a::StaticArray, h)
  316. f = @SVector [(a[2,3]-a[2,1])/2h, (a[3,2]-a[1,2])/2h]
  317. s = @SVector [(a[2,3]-2a[2,2]+a[2,1])/h^2, (a[3,2]-2a[2,2]+a[1,2])/h^2]
  318. m = @SVector [(a[3,3]-a[1,3]-a[3,1]+a[1,1])/4h^2]
  319. return (s[1]*(f[2])^2 - 2*f[1]*f[2]*m[1] + s[2]*(f[1])^2)/(f[1]^2 + f[2]^2)^1.5
  320. end
  321. @inline function mean_curvature_indices(a, II, nx, ny, dx, dy, per_x, per_y)
  322. f = @SVector [(a[δx⁺(II,nx,per_x)]-a[δx⁻(II,nx,per_x)])/2dx, (a[δy⁺(II,ny,per_y)]-a[δy⁻(II,ny,per_y)])/2dy]
  323. s = @SVector [(a[δx⁻(II,nx,per_x)]-2a[II]+a[δx⁺(II,nx,per_x)])/dx^2, (a[δy⁻(II,ny,per_y)]-2a[II]+a[δy⁺(II,ny,per_y)])/dy^2]
  324. m = (
  325. a[δx⁻(δy⁻(II,ny,per_y),nx,per_x)]+
  326. a[δx⁺(δy⁺(II,ny,per_y),nx,per_x)]-
  327. a[δx⁻(δy⁺(II,ny,per_y),nx,per_x)]-
  328. a[δx⁺(δy⁻(II,ny,per_y),nx,per_x)]
  329. )/(4*(dx*dy)^2)
  330. return (s[1]*(f[2])^2 - 2*f[1]*f[2]*m[1] + s[2]*(f[1])^2)/(1e-10 + f[1]^2 + f[2]^2)^1.5
  331. end
  332. function mean_curvature_interpolated(u, II, h, B, BT, mid)
  333. tmp = zeros(3,3)
  334. @threads for i in -1:1
  335. for j in -1:1
  336. JJ = CartesianIndex(II[1]+i, II[2]+j)
  337. st = static_stencil(u, JJ)
  338. tmp[2+i, 2+j] = mean_curvature(st, h)
  339. end
  340. end
  341. itp = B*tmp*BT
  342. a = biquadratic(itp, mid.x, mid.y)
  343. return min(max(mean(tmp),-1/h), 1/h)
  344. end
  345. function interpolated_curvature(grid, II, per_x, per_y)
  346. @unpack nx, ny, u, mid_point, ind = grid
  347. dx = grid.dx[II]
  348. dy = grid.dy[II]
  349. ii = [δy⁻, (x,n,p)->x, δy⁺]
  350. jj = [δx⁻, (x,n,p)->x, δx⁺]
  351. tmp = zeros(3,3)
  352. for i in -1:1
  353. for j in -1:1
  354. JJ = ii[i+2](jj[j+2](II, nx, per_x), ny, per_y)
  355. if !per_x && !per_y
  356. if JJ in ind.inside
  357. JJ_0 = JJ
  358. elseif JJ in ind.b_left[1][2:end-1]
  359. JJ_0 = δx⁺(JJ)
  360. elseif JJ in ind.b_bottom[1][2:end-1]
  361. JJ_0 = δy⁺(JJ)
  362. elseif JJ in ind.b_right[1][2:end-1]
  363. JJ_0 = δx⁻(JJ)
  364. elseif JJ in ind.b_top[1][2:end-1]
  365. JJ_0 = δy⁻(JJ)
  366. elseif JJ == ind.b_left[1][1]
  367. JJ_0 = δy⁺(δx⁺(JJ))
  368. elseif JJ == ind.b_left[1][end]
  369. JJ_0 = δy⁻(δx⁺(JJ))
  370. elseif JJ == ind.b_right[1][1]
  371. JJ_0 = δy⁺(δx⁻(JJ))
  372. elseif JJ == ind.b_right[1][end]
  373. JJ_0 = δy⁻(δx⁻(JJ))
  374. end
  375. elseif per_x && !per_y
  376. if JJ in ind.inside || JJ in ind.b_left[1][2:end-1] || JJ in ind.b_right[1][2:end-1]
  377. JJ_0 = JJ
  378. elseif JJ in ind.b_bottom[1]
  379. JJ_0 = δy⁺(JJ)
  380. elseif JJ in ind.b_top[1]
  381. JJ_0 = δy⁻(JJ)
  382. end
  383. else
  384. if JJ in ind.inside || JJ in ind.b_bottom[1][2:end-1] || JJ in ind.b_top[1][2:end-1]
  385. JJ_0 = JJ
  386. elseif JJ in ind.b_left[1]
  387. JJ_0 = δx⁺(JJ)
  388. elseif JJ in ind.b_right[1]
  389. JJ_0 = δx⁻(JJ)
  390. end
  391. end
  392. tmp[2+i, 2+j] = mean_curvature_indices(u, JJ_0, nx, ny, dx, dy, per_x, per_y)
  393. end
  394. end
  395. B, BT = B_BT(II, grid, per_x, per_y)
  396. itp = B*tmp*BT
  397. κ = biquadratic(itp, mid_point[II].x, mid_point[II].y)
  398. return κ
  399. end
  400. @inline parabola_fit_curvature(itp, mid_point, dx, dy) =
  401. @inbounds 2*itp[1,3]/((1+(2*itp[1,3]*mid_point.x/dx + itp[2,3])^2)^1.5)/(dx)^2 +
  402. 2*itp[3,1]/((1+(2*itp[3,1]*mid_point.y/dy + itp[3,2])^2)^1.5)/(dy)^2
  403. @inline function linear_fit(a, b, x)
  404. a = (a - b)/sign(x+eps(0.1))
  405. return a*x + b
  406. end
  407. @inline @. parabola_fit(x, p) = p[1]*x^2 + p[2]*x + p[3]
  408. function get_NB_width_indices_base(n)
  409. x = [CartesianIndex(i,0) for i in -n:n]
  410. y = [CartesianIndex(0,j) for j in -n:n]
  411. return vcat(x,y)
  412. end
  413. function get_NB_width_indices_base1(n)
  414. return vcat([[CartesianIndex(i,j) for i in -n:n] for j in -n:n]...)
  415. end
  416. @inline function normf(field, pos, cap, h)
  417. AVG = 0.
  418. RMS = 0.
  419. VOLUME = 0.
  420. MAX = 0.
  421. dv = 0.
  422. @inbounds for II in pos
  423. v = abs(field[II])
  424. dv = cap[II]*h^2
  425. if dv > 0.
  426. VOLUME += dv
  427. AVG += dv*v
  428. RMS += dv*v^2
  429. if (v > MAX) MAX = v end
  430. end
  431. end
  432. return AVG/VOLUME, sqrt(RMS/VOLUME), MAX
  433. end
  434. @inline function normf(field, pos, h)
  435. AVG = 0.
  436. RMS = 0.
  437. VOLUME = 0.
  438. MAX = 0.
  439. @inbounds for II in pos
  440. v = abs(field[II])
  441. VOLUME += h^2
  442. AVG += (h^2)*v
  443. RMS += (h^2)*v^2
  444. if (v > MAX) MAX = v end
  445. end
  446. return AVG/VOLUME, sqrt(RMS/VOLUME), MAX
  447. end
  448. @inline function norma(field, pos, cap, h)
  449. AVG = 0.
  450. RMS = 0.
  451. VOLUME = 0.
  452. MAX = 0.
  453. dv = 0.
  454. @inbounds for II in pos
  455. v = abs(field[II])
  456. dv = cap[II]*h^2
  457. # dv = h^2
  458. if dv > 0.
  459. VOLUME += dv
  460. AVG += dv*v
  461. RMS += dv*v^2
  462. if (v > MAX) MAX = v end
  463. end
  464. end
  465. return AVG/VOLUME, sqrt(RMS), MAX
  466. end
  467. @inline function Richardson_extrapolation(e, r)
  468. p = log(abs(e[end-2] - e[end-1])/abs(e[end-1] - e[end]))/log(r)
  469. ext = e[end] + (e[end] - e[end-1])/(2^p - 1)
  470. return abs.(e .- ext)
  471. end
  472. function fit_order(x, y)
  473. coeffs = fit(log.(x), log.(y), 1).coeffs
  474. return exp(coeffs[1]), -coeffs[2]
  475. end
  476. @inline function arc_length2(POS, ind)
  477. d_tot = 0.
  478. d_ = 0.
  479. ind_ = copy(ind)
  480. for i in length(ind):-1:1
  481. d = 1e300
  482. pop!(ind_)
  483. for j in axes(ind_,1)
  484. d_ = distance(abs(POS[ind[i]].pos), abs(POS[ind_[j]].pos))
  485. if d_ < d
  486. d = d_
  487. end
  488. end
  489. d_tot += d_
  490. end
  491. return d_tot
  492. end
  493. function find_2closest_points(POS, ind, II)
  494. closest_indices = Vector{Int64}(undef, 2)
  495. closest_cartesian_indices = Vector{CartesianIndex{2}}(undef, 2)
  496. all_indices = copy(ind)
  497. for i = 1:2
  498. d = 1e300
  499. for JJ in axes(all_indices,1)
  500. d_ = distance(POS[II].pos, POS[all_indices[JJ]].pos)
  501. if 0. < d_ < d
  502. d = d_
  503. closest_indices[i] = JJ
  504. end
  505. end
  506. closest_cartesian_indices[i] = all_indices[closest_indices[i]]
  507. if i == 1 deleteat!(all_indices, closest_indices[1]) end
  508. end
  509. return closest_cartesian_indices
  510. end
  511. function monitor(header, history, it)
  512. println("****** ", header, " ******")
  513. if it > 0
  514. println("res[0] = ", first(history))
  515. println("res[", it, "] = ", history[it+1])
  516. else
  517. println("x0 is a solution")
  518. end
  519. end
  520. function within_cell(p::Point)
  521. if p.x >= -0.5 && p.x <= 0.5 && p.y >= -0.5 && p.y <= 0.5
  522. return true
  523. else
  524. return false
  525. end
  526. end
  527. function points2polygon(points)
  528. str = "POLYGON(("
  529. str *= "$(points[1].x) $(points[1].y)"
  530. for p in points[2:end]
  531. str *= ",$(p.x) $(p.y)"
  532. end
  533. str *= "))"
  534. return readgeom(str)
  535. end
  536. @inline is_weno(::WENO5) = true
  537. @inline is_weno(::LevelsetDiscretization) = false
  538. @inline is_eno(::ENO2) = true
  539. @inline is_eno(::LevelsetDiscretization) = false
  540. const weno5 = WENO5()
  541. const eno2 = ENO2()
  542. @inline is_Forward_Euler(char::String) = (char == "FE" || char == "Forward_Euler")
  543. @inline is_Crank_Nicolson(char::String) = (char == "CN" || char == "Crank_Nicolson")
  544. @inline is_Forward_Euler(::ForwardEuler) = true
  545. @inline is_Forward_Euler(::TemporalIntegration) = false
  546. @inline is_Crank_Nicolson(::CrankNicolson) = true
  547. @inline is_Crank_Nicolson(::TemporalIntegration) = false
  548. const FE = ForwardEuler()
  549. const CN = CrankNicolson()
  550. isCC(::Mesh{GridCC ,T,N}) where {T,N} = true
  551. isCC(::Mesh{GridFCx,T,N}) where {T,N} = false
  552. isCC(::Mesh{GridFCy,T,N}) where {T,N} = false
  553. isCC(::Mesh) = false
  554. isFCx(::Mesh{GridFCx,T,N}) where {T,N} = true
  555. isFCx(::Mesh{GridCC ,T,N}) where {T,N} = false
  556. isFCx(::Mesh{GridFCy,T,N}) where {T,N} = false
  557. isFCx(::Mesh) = false
  558. isFCy(::Mesh{GridFCy,T,N}) where {T,N} = true
  559. isFCy(::Mesh{GridFCx,T,N}) where {T,N} = false
  560. isFCy(::Mesh{GridCC ,T,N}) where {T,N} = false
  561. isFCy(::Mesh) = false
  562. @inline is_dirichlet(::Dirichlet) = true
  563. @inline is_dirichlet(::BoundaryCondition) = false
  564. @inline is_neumann(::Neumann) = true
  565. @inline is_neumann(::BoundaryCondition) = false
  566. @inline is_neumann_cl(::Neumann_cl) = true
  567. @inline is_neumann_cl(::BoundaryCondition) = false
  568. @inline is_neumann_inh(::Neumann_inh) = true
  569. @inline is_neumann_inh(::BoundaryCondition) = false
  570. @inline is_robin(::Robin) = true
  571. @inline is_robin(::BoundaryCondition) = false
  572. @inline is_periodic(::Periodic) = true
  573. @inline is_periodic(::BoundaryCondition) = false
  574. @inline is_navier(::Navier) = true
  575. @inline is_navier(::BoundaryCondition) = false
  576. @inline is_navier_cl(::Navier_cl) = true
  577. @inline is_navier_cl(::BoundaryCondition) = false
  578. @inline is_gnbc(::GNBC) = true
  579. @inline is_gnbc(::BoundaryCondition) = false
  580. @inline is_stefan(::Stefan) = true
  581. @inline is_stefan(::BoundaryCondition) = false
  582. @inline is_fs(::FreeSurface) = true
  583. @inline is_fs(::BoundaryCondition) = false
  584. @inline is_wall_no_slip(::WallNoSlip) = true
  585. @inline is_wall_no_slip(::BoundaryCondition) = false
  586. @inline is_wall(::WallNoSlip) = true
  587. @inline is_wall(::Navier) = true
  588. @inline is_wall(::Navier_cl) = true
  589. @inline is_wall(::BoundaryCondition) = false
  590. const neu = Neumann()
  591. const neu_cl = Neumann_cl()
  592. const neu_inh = Neumann_inh()
  593. const dir = Dirichlet()
  594. const per = Periodic()
  595. const rob = Robin()
  596. const nav = Navier()
  597. const nav_cl = Navier_cl()
  598. const fs = FreeSurface()
  599. function get_fresh_cells!(grid, geo, Mm1, indices)
  600. @inbounds @threads for II in indices
  601. pII = lexicographic(II, grid.ny)
  602. if Mm1.diag[pII]/(grid.dx[II]*grid.dy[II]) < 1e-8 && geo.cap[II,5] > 1e-8
  603. geo.fresh[II] = true
  604. end
  605. end
  606. return nothing
  607. end
  608. #TODO distinguish between border and bulk cells
  609. function kill_dead_cells!(T::Matrix, grid, geo)
  610. @unpack ind = grid
  611. @inbounds @threads for II in ind.all_indices
  612. if geo.cap[II,5] < 1e-12
  613. T[II] = 0.
  614. end
  615. end
  616. end
  617. function kill_dead_cells!(T::Vector, grid, geo)
  618. @unpack ny, ind = grid
  619. @inbounds @threads for II in ind.all_indices
  620. pII = lexicographic(II, ny)
  621. if geo.cap[II,5] < 1e-12
  622. T[pII] = 0.
  623. end
  624. end
  625. end
  626. function kill_dead_cells!(S::SubArray{T,N,P,I,L}, grid, geo) where {T,N,P<:Vector{T},I,L}
  627. @unpack ny, ind = grid
  628. @inbounds @threads for II in ind.all_indices
  629. pII = lexicographic(II, ny)
  630. if geo.cap[II,5] < 1e-12
  631. S[pII] = 0.
  632. end
  633. end
  634. end
  635. function kill_dead_cells!(S::SubArray{T,N,P,I,L}, grid, geo) where {T,N,P<:Array{T,3},I,L}
  636. @unpack ind = grid
  637. # print("kill dead cells mat")
  638. @inbounds @threads for II in ind.all_indices
  639. if geo.cap[II,5] < 1e-12
  640. # print(II, S[II])
  641. S[II] = 0.
  642. # print("v2",S[II])
  643. end
  644. end
  645. end
  646. function init_borders!(T, grid, BC, val=0.0)
  647. if is_dirichlet(BC.left)
  648. vecb_L(T, grid) .= BC.left.val
  649. elseif is_periodic(BC.left)
  650. vecb_L(T, grid) .= val
  651. else
  652. vecb_L(T, grid) .= val
  653. end
  654. if is_dirichlet(BC.bottom)
  655. vecb_B(T, grid) .= BC.bottom.val
  656. elseif is_periodic(BC.bottom)
  657. vecb_B(T, grid) .= val
  658. else
  659. vecb_B(T, grid) .= val
  660. end
  661. if is_dirichlet(BC.right)
  662. vecb_R(T, grid) .= BC.right.val
  663. elseif is_periodic(BC.right)
  664. vecb_R(T, grid) .= val
  665. else
  666. vecb_R(T, grid) .= val
  667. end
  668. if is_dirichlet(BC.top)
  669. vecb_T(T, grid) .= BC.top.val
  670. elseif is_periodic(BC.top)
  671. vecb_T(T, grid) .= val
  672. else
  673. vecb_T(T, grid) .= val
  674. end
  675. end
  676. @inline function star0(grid, val=0.0)
  677. spdiagm(0 => val.*ones(grid.ny*grid.nx))
  678. end
  679. @inline function star1(g, val=0.0)
  680. spdiagm(0 => val.*ones(g.ny*g.nx), # i,j
  681. -g.ny => val.*ones(g.ny*(g.nx-1)), # i-1,j
  682. -1 => val.*ones(g.ny*g.nx-1), # i,j-1
  683. g.ny => val.*ones(g.ny*(g.nx-1)), # i+1,j
  684. 1 => val.*ones(g.ny*g.nx-1), # i,j+1
  685. )
  686. end
  687. @inline function star2(g, val=0.0)
  688. spdiagm(0 => val.*ones(g.ny*g.nx), # i,j
  689. -g.ny => val.*ones(g.ny*(g.nx-1)), # i-1,j
  690. -1 => val.*ones(g.ny*g.nx-1), # i,j-1
  691. g.ny => val.*ones(g.ny*(g.nx-1)), # i+1,j
  692. 1 => val.*ones(g.ny*g.nx-1), # i,j+1
  693. -2g.ny => val.*ones(g.ny*(g.nx-2)), # i-2,j
  694. -2 => val.*ones(g.ny*g.nx-2), # i,j-2
  695. 2g.ny => val.*ones(g.ny*(g.nx-2)), # i+2,j
  696. 2 => val.*ones(g.ny*g.nx-2), # i,j+2
  697. -g.ny-1 => val.*ones(g.ny*(g.nx-1)-1), # i-1,j-1
  698. g.ny-1 => val.*ones(g.ny*(g.nx-1)+1), # i+1,j-1
  699. g.ny+1 => val.*ones(g.ny*(g.nx-1)-1), # i+1,j+1
  700. -g.ny+1 => val.*ones(g.ny*(g.nx-1)+1), # i-1,j+1
  701. )
  702. end
  703. @inline function star3(g, val=0.0)
  704. spdiagm(0 => val.*ones(g.ny*g.nx), # i,j
  705. -g.ny => val.*ones(g.ny*(g.nx-1)), # i-1,j
  706. -1 => val.*ones(g.ny*g.nx-1), # i,j-1
  707. g.ny => val.*ones(g.ny*(g.nx-1)), # i+1,j
  708. 1 => val.*ones(g.ny*g.nx-1), # i,j+1
  709. -2g.ny => val.*ones(g.ny*(g.nx-2)), # i-2,j
  710. -2 => val.*ones(g.ny*g.nx-2), # i,j-2
  711. 2g.ny => val.*ones(g.ny*(g.nx-2)), # i+2,j
  712. 2 => val.*ones(g.ny*g.nx-2), # i,j+2
  713. -g.ny-1 => val.*ones(g.ny*(g.nx-1)-1), # i-1,j-1
  714. g.ny-1 => val.*ones(g.ny*(g.nx-1)+1), # i+1,j-1
  715. g.ny+1 => val.*ones(g.ny*(g.nx-1)-1), # i+1,j+1
  716. -g.ny+1 => val.*ones(g.ny*(g.nx-1)+1), # i-1,j+1
  717. -3g.ny => val.*ones(g.ny*(g.nx-3)), # i-3,j
  718. -3 => val.*ones(g.ny*g.nx-3), # i,j-3
  719. 3g.ny => val.*ones(g.ny*(g.nx-3)), # i+3,j
  720. 3 => val.*ones(g.ny*g.nx-3), # i,j+3
  721. -g.ny-2 => val.*ones(g.ny*(g.nx-1)-2), # i-1,j-2
  722. g.ny-2 => val.*ones(g.ny*(g.nx-1)+2), # i+1,j-2
  723. g.ny+2 => val.*ones(g.ny*(g.nx-1)-2), # i+1,j+2
  724. -g.ny+2 => val.*ones(g.ny*(g.nx-1)+2), # i-1,j+2
  725. -2g.ny-1 => val.*ones(g.ny*(g.nx-2)-1), # i-2,j-1
  726. 2g.ny-1 => val.*ones(g.ny*(g.nx-2)+1), # i+2,j-1
  727. 2g.ny+1 => val.*ones(g.ny*(g.nx-2)-1), # i+2,j+1
  728. -2g.ny+1 => val.*ones(g.ny*(g.nx-2)+1), # i-2,j+1
  729. )
  730. end
  731. Base.copy(x::T) where T = T([getfield(x, k) for k ∈ fieldnames(T)]...)
  732. """
  733. export_all()
  734. Exports every function of an included file.
  735. * @args Noting : nothing
  736. ## Notes
  737. Do not use this, use `@export` instead!
  738. """
  739. function export_all()
  740. for n in names(@__MODULE__; all=true)
  741. if Base.isidentifier(n) && n ∉ (Symbol(@__MODULE__), :eval, :include)
  742. @eval export $n
  743. end
  744. end
  745. end
  746. """
  747. Here rows = rowvals(mat2)
  748. """
  749. function mat_assign!(mat1, mat2)
  750. mat1.nzval .= 0.
  751. rows = rowvals(mat2)
  752. m, n = size(mat2)
  753. @inbounds @threads for j = 1:n
  754. for i in nzrange(mat2, j)
  755. @inbounds row = rows[i]
  756. mat1[row,j] = mat2[row,j]
  757. end
  758. end
  759. return nothing
  760. end
  761. """
  762. Here rows = rowvals(mat1)
  763. """
  764. function mat_assign_T!(mat1, mat2)
  765. mat1.nzval .= 0.
  766. rows = rowvals(mat1)
  767. m, n = size(mat1)
  768. @inbounds @threads for j = 1:n
  769. for i in nzrange(mat1, j)
  770. @inbounds row = rows[i]
  771. mat1[row,j] = mat2[row,j]
  772. end
  773. end
  774. return nothing
  775. end
  776. function mat_op!(mat1, mat2, op)
  777. mat1.nzval .= 0.
  778. rows = rowvals(mat2)
  779. vals = nonzeros(mat2)
  780. m, n = size(mat2)
  781. @inbounds @threads for j = 1:n
  782. for i in nzrange(mat2, j)
  783. @inbounds row = rows[i]
  784. @inbounds val = vals[i]
  785. @inbounds mat1[row,j] = op(val)
  786. end
  787. end
  788. return nothing
  789. end
  790. function mat_T_op!(mat1, mat2, op)
  791. mat1.nzval .= 0.
  792. rows = rowvals(mat2)
  793. vals = nonzeros(mat2)
  794. m, n = size(mat2)
  795. @inbounds @threads for j = 1:n
  796. for i in nzrange(mat2, j)
  797. @inbounds row = rows[i]
  798. @inbounds val = vals[i]
  799. @inbounds mat1[j,row] = op(val)
  800. end
  801. end
  802. return nothing
  803. end
  804. # Operations on sparse arrays that can be parallelized
  805. for op ∈ (:*, :+, :-)
  806. @eval begin
  807. function $op(A::AbstractSparseMatrix{Tv,Ti}, B::Tv) where {Tv<:Number,Ti}
  808. C = SparseMatrixCSC{Tv,Ti}(A.m, A.n, A.colptr, A.rowval, zeros(length(A.nzval)))
  809. @inbounds @threads for col in 1:size(A, 2)
  810. for j in nzrange(A, col)
  811. C.nzval[j] = $op(A.nzval[j], B)
  812. end
  813. end
  814. C
  815. end
  816. function $op(B::Tv, A::AbstractSparseMatrix{Tv,Ti}) where {Tv<:Number,Ti}
  817. C = SparseMatrixCSC{Tv,Ti}(A.m, A.n, A.colptr, A.rowval, zeros(length(A.nzval)))
  818. @inbounds @threads for col in 1:size(A, 2)
  819. for j in nzrange(A, col)
  820. C.nzval[j] = $op(B, A.nzval[j])
  821. end
  822. end
  823. C
  824. end
  825. # function $op(A::AbstractSparseMatrix{Tv,Ti}, B::AbstractSparseMatrix{Tv,Ti}) where {Tv<:Number,Ti}
  826. # C = SparseMatrixCSC{Tv,Ti}(A.m, A.n, A.colptr, A.rowval, zeros(length(A.nzval)))
  827. # @inbounds @threads for col in 1:size(A, 2)
  828. # for j in nzrange(A, col)
  829. # C.nzval[j] = $op(A.nzval[j], B.nzval[j])
  830. # end
  831. # end
  832. # C
  833. # end
  834. # function $op(A::AbstractSparseMatrix{Tv,Ti}, B::Diagonal{Tv,Vector{Tv}}) where {Tv<:Number,Ti}
  835. # C = SparseMatrixCSC{Tv,Ti}(A.m, A.n, A.colptr, A.rowval, copy(A.nzval))
  836. # b = B.diag
  837. # nzv = nonzeros(A)
  838. # rv = rowvals(A)
  839. # @inbounds @threads for col in 1:size(A, 2)
  840. # nz = nzrange(A, col)
  841. # j = nz[findfirst(x->rv[x]==col, collect(nz))]
  842. # C.nzval[j] = $op(A.nzval[j], b[col])
  843. # end
  844. # C
  845. # end
  846. end
  847. end
  848. function (-)(B::Diagonal{Tv,Vector{Tv}}, A::AbstractSparseMatrix{Tv,Ti}) where {Tv<:Number,Ti}
  849. C = SparseMatrixCSC{Tv,Ti}(A.m, A.n, A.colptr, A.rowval, -A.nzval)
  850. b = B.diag
  851. nzv = nonzeros(A)
  852. rv = rowvals(A)
  853. @inbounds @threads for col in 1:size(A, 2)
  854. nz = nzrange(A, col)
  855. j = nz[findfirst(x->rv[x]==col, collect(nz))]
  856. C.nzval[j] += b[col]
  857. end
  858. C
  859. end
  860. function mytime_print(elapsedtime, gctime=0)
  861. timestr = Base.Ryu.writefixed(Float64(elapsedtime/1e9), 6)
  862. str = sprint() do io
  863. print(io, length(timestr) < 10 ? (" "^(10 - length(timestr))) : "")
  864. print(io, timestr, " seconds")
  865. parens = gctime > 0
  866. parens && print(io, " (")
  867. if gctime > 0
  868. print(io, Base.Ryu.writefixed(Float64(gctime/1e9), 6), " gc time")
  869. end
  870. parens && print(io, " )")
  871. end
  872. println(str)
  873. nothing
  874. end
  875. # macro that computes time removing the
  876. # garbage collector time
  877. macro mytime(ex)
  878. quote
  879. Base.Experimental.@force_compile
  880. local stats = Base.gc_num()
  881. local elapsedtime = Base.time_ns()
  882. local val = $(esc(ex))
  883. elapsedtime = Base.time_ns() - elapsedtime
  884. local diff = Base.GC_Diff(Base.gc_num(), stats)
  885. local t = elapsedtime - diff.total_time
  886. mytime_print(t, diff.total_time)
  887. (time=t/1e9, gctime=diff.total_time/1e9)
  888. end
  889. end