Advertisement
Guest User

Untitled

a guest
Nov 28th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Julia 23.24 KB | None | 0 0
  1. quad1DW = [0.2777777777777778, 0.4444444444444444, 0.2777777777777778];
  2.  
  3. quad1DX = [0.1127016653792583, 0.5, 0.8872983346207417];
  4.  
  5. #quadX = [[0.659027622374092,  0.231933368553031],
  6. #         [0.659027622374092,  0.109039009072877],
  7. #         [0.231933368553031,  0.659027622374092],
  8. #         [0.231933368553031,  0.109039009072877],
  9. #         [0.109039009072877,  0.659027622374092],
  10. #         [0.109039009072877,  0.231933368553031]];
  11.  
  12. #quadW = 1.0/12.0*ones(6,1);
  13.  
  14. quadX = [[1.88409405952072e-01,   7.87659461760847e-01],
  15.          [5.23979067720101e-01,   4.09466864440735e-01],
  16.          [8.08694385677670e-01,   8.85879595127039e-02],
  17.          [1.06170269119576e-01,   7.87659461760847e-01],
  18.          [2.95266567779633e-01,   4.09466864440735e-01],
  19.          [4.55706020243648e-01,   8.85879595127039e-02],
  20.          [2.39311322870805e-02,   7.87659461760847e-01],
  21.          [6.65540678391645e-02,   4.09466864440735e-01],
  22.          [1.02717654809626e-01,   8.85879595127039e-02]];
  23.  
  24. quadW = [1.93963833059595e-02,
  25.          6.36780850998851e-02,
  26.          5.58144204830443e-02,
  27.          3.10342132895352e-02,
  28.          1.01884936159816e-01,
  29.          8.93030727728709e-02,
  30.          1.93963833059595e-02,
  31.          6.36780850998851e-02,
  32.          5.58144204830443e-02];
  33.  
  34. PDESystem(;A=spzeros(0,0), b=[], bc=[], DI=Set{Int64}(), vec_ind=Set{Int64}(), qdim=1, Factors=[],
  35.           SystemMatrix=spzeros(0,0), B=spzeros(0,0), state=[], rhs=[]) =
  36. PDESystem(A, b, bc, DI, vec_ind, qdim, Factors, SystemMatrix, B, state, rhs)
  37.  
  38. function assembly(S::PDESystem)
  39.   if S.Factors == []
  40.     if S.DI != Set{Int64}()
  41.       vec_ind = Set{Int64}()
  42.       for d=1:S.qdim
  43.         union!(vec_ind, S.qdim*(collect(S.DI).-1).+d)
  44.       end
  45.       ii = length(vec_ind)
  46.       m,n = size(S.A)
  47.       S.B = getDirichletProjection(m, S.DI, qdim=S.qdim)
  48.  
  49.       S.SystemMatrix = [S.A            S.B';
  50.                        S.B  spzeros(ii,ii)]
  51.    else
  52.      S.SystemMatrix = S.A
  53.    end
  54.    S.Factors = lu(S.SystemMatrix)
  55.  end
  56. end
  57.  
  58. function refresh(S::PDESystem)
  59.  S.Factors = []
  60.  assembly(S)
  61. end
  62.  
  63. """
  64.    solve(S::PDESystem)
  65.  
  66. First tries to set up the system matrix with multipliers for Dirichlet conditions.
  67. If the system has already been used before, this step is skipped.
  68. This is determined depending on an existing factorization of the system matrix.
  69. If the stiffness matrix or Dirichlet conditions have changes, one should invole refresh() first.
  70.  
  71. Finally the system is solved via matrix factorization.
  72. """
  73. function solve(S::PDESystem)
  74.  assembly(S)
  75.  vec_ind = Set{Int64}()
  76.  for d=1:S.qdim
  77.    union!(vec_ind, S.qdim*(collect(S.DI).-1).+d)
  78.  end
  79.  S.rhs = [S.b;S.bc[collect(vec_ind)]]
  80.  S.state = (S.Factors\S.rhs)[1:length(S.b)]
  81. end
  82.  
  83. """
  84.    getDirichletProjection(nnodes::Int64, DI::Set{Int64};qdim=1)
  85.  
  86. Build the projection onto the Dirichlet nodes.
  87. """
  88.  
  89. function getDirichletProjection(nnodes::Int64, DI::Set{Int64};qdim=1)
  90.  vec_ind = Set{Int64}()
  91.  for d=1:qdim
  92.    union!(vec_ind, qdim*(collect(DI).-1).+d)
  93.  end
  94.  ii = length(vec_ind)
  95.  return sparse(1:ii,collect(vec_ind),ones(ii),ii,nnodes)
  96. end
  97.  
  98. """
  99.    evaluateMeshFunction(mesh::Mesh, f::Function; region=[], qdim=1)
  100.  
  101. Evaluate a given function object f on all nodes of the mesh. Or, if region is specified,
  102. it is assumed to be a set or vector of node indices, where f should be evaluated.
  103. """
  104. function evaluateMeshFunction(mesh::Mesh, f::Function; region=[], qdim=1)
  105.  v = zeros(Float64, qdim*mesh.nnodes)
  106.  nodes = 1:mesh.nnodes
  107.  if region != []
  108.    nodes = collect(region)
  109.  end
  110.  if(qdim==1)
  111.    for i in nodes
  112.      v[i] = f(mesh.Nodes[i])
  113.    end
  114.  else
  115.    for i in nodes
  116.      v[qdim*(i-1)+1:qdim*i] = f(mesh.Nodes[i])
  117.    end
  118.  end
  119.  return v
  120. end
  121.  
  122. function Phi(ii::Int64, x::AbstractVector)
  123.  if ii==1
  124.    return 1.0-x[1]-x[2]
  125.  elseif ii==2
  126.    return x[1]
  127.  elseif ii==3
  128.    return x[2]
  129.  end
  130. end
  131.  
  132. function PhiEdge(ii::Int64, x::Float64)
  133.  if ii==1
  134.    return 1.0-x
  135.  elseif ii==2
  136.    return x
  137.  end
  138. end
  139.  
  140. function gradPhi(ii::Int64)
  141.  grad = zeros(2,1)
  142.  if ii==1
  143.    grad = [-1.0; -1.0]
  144.  elseif ii==2
  145.    grad = [1.0; 0.0]
  146.  elseif ii==3
  147.    grad = [0.0; 1.0]
  148.  end
  149.  return grad
  150. end
  151.  
  152. """
  153.    function asmDirichletCondition(SM, DI::Set{Int64}, rhs=[], bc=[]; qdim=1, insert=1.0)
  154.  
  155. Modify a stiffness matrix and a right hand side according to the given Dirichlet conditions.
  156. DI has to be the set of node indices for which the condition should be active.
  157. For vector valued states either DI can be set to each component that should have a
  158. Dirichlet condtion or qdim is set, if all components should have the condition.
  159. The value insert is put as diagonal element. Usually you want a 1.0 here.
  160. """
  161. function asmDirichletCondition(SM, DI::Set{Int64}, rhs=[], bc=[]; qdim=1, insert=1.0)
  162.  if rhs != [] && bc != []
  163.    for i in DI
  164.      for d=1:qdim
  165.        ii = qdim*(i-1)+d
  166.        bcind = SM[:, ii].nzind
  167.        rhs[bcind] -= SM[bcind, ii]*bc[ii]
  168.      end
  169.    end
  170.    for i in DI
  171.      for d=1:qdim
  172.        ii = qdim*(i-1)+d
  173.        rhs[ii] = bc[ii]
  174.      end
  175.    end
  176.  end
  177.  for i in DI
  178.    for d=1:qdim
  179.      ii = qdim*(i-1)+d
  180.      SM[ii, SM[ii,:].nzind] *= 0.0;
  181.      SM[:, ii] *= 0.0;
  182.      SM[ii, ii] = insert;
  183.    end
  184.  end
  185. end
  186.  
  187. function asmSparseMatrix(D::Dict{Tuple{Int64,Int64}, Float64}; nrows=-1, ncols=-1)
  188.  nn = length(D)
  189.  II = zeros(Int64, nn)
  190.  JJ = zeros(Int64, nn)
  191.  AA = zeros(Float64, nn)
  192.  for (i, pair) in enumerate(D)
  193.    II[i] = pair[1][1]
  194.    JJ[i] = pair[1][2]
  195.    AA[i] = pair[2]
  196.  end
  197.  return sparse(II,JJ,AA, maximum([nrows,maximum(II)]), maximum([ncols,maximum(JJ)]))
  198. end
  199.  
  200.  
  201. """
  202.    asmLaplacian(mesh::Mesh)
  203.  
  204. Assemble the Laplacian stiffness matrix for all elements in the mesh.
  205. """
  206. function asmLaplacian(mesh::Mesh)
  207.  D = Dict{Tuple{Int64,Int64}, Float64}()
  208.  
  209.  for el=1:mesh.nelems
  210.    nodes = mesh.Triangles[el]
  211.    (detJ, J) = Jacobian(mesh, el)
  212.    elemMat = zeros(3,3)
  213.    for i=1:3
  214.      for j=1:3
  215.        elemMat[i,j] += (J*gradPhi(i))'*(J*gradPhi(j))
  216.       end
  217.     end
  218.     elemMat *= sum(quadW)*detJ
  219.  
  220.     for i=1:3
  221.       for j=1:3
  222.         if(in((nodes[i], nodes[j]), keys(D)))
  223.           D[(nodes[i], nodes[j])] += elemMat[i,j]
  224.         else
  225.           D[(nodes[i], nodes[j])] = elemMat[i,j]
  226.         end
  227.       end
  228.     end
  229.   end
  230.  
  231.   return asmSparseMatrix(D)
  232. end
  233.  
  234. """
  235.    asmMassMatrix(mesh::Mesh; qdim=1)
  236.  
  237. Assemble a mass matrix for all elements of the given mesh.
  238. """
  239. function asmMassMatrix(mesh::Mesh; qdim=1)
  240.   D = Dict{Tuple{Int64,Int64}, Float64}()
  241.  
  242.   for el=1:mesh.nelems
  243.     nodes = mesh.Triangles[el]
  244.     (detJ, J) = Jacobian(mesh, el)
  245.     elemMat = zeros(3,3)
  246.     for i=1:3
  247.       for j=1:3
  248.         for (q, x) in enumerate(quadX)
  249.           elemMat[i,j] += Phi(i, x) * Phi(j, x) * quadW[q] * detJ
  250.         end
  251.       end
  252.     end
  253.  
  254.     for d=1:qdim
  255.       for i=1:3
  256.         for j=1:3
  257.           ii = qdim*(nodes[i]-1)+d
  258.           jj = qdim*(nodes[j]-1)+d
  259.           if(in((ii, jj), keys(D)))
  260.             D[(ii, jj)] += elemMat[i,j]
  261.           else
  262.             D[(ii, jj)] = elemMat[i,j]
  263.           end
  264.         end
  265.       end
  266.     end
  267.   end
  268.  
  269.   return asmSparseMatrix(D)
  270. end
  271.  
  272.  
  273. """
  274.    asmBoundaryMassMatrix(mesh::Mesh, BoundaryEdges=Set{Int64}(-1); qdim=1)
  275.  
  276. Assemble a mass matrix for the given set of boundary edges.
  277. """
  278. function asmBoundaryMassMatrix(mesh::Mesh, BoundaryEdges=Set{Int64}(-1); qdim=1)
  279.   D = Dict{Tuple{Int64,Int64}, Float64}()
  280.  
  281.   if(in(-1, BoundaryEdges))
  282.     BoundaryEdges = 1:mesh.nedges
  283.   end
  284.  
  285.   for el in BoundaryEdges
  286.     edge = mesh.Edges[el]
  287.     detJ = EdgeJacobian(mesh, el)
  288.     elemMat = zeros(2,2)
  289.     for i=1:2
  290.       for j=1:2
  291.         for (q, x) in enumerate(quad1DX)
  292.           elemMat[i,j] += PhiEdge(i, x) * PhiEdge(j, x) * quad1DW[q] * detJ
  293.         end
  294.       end
  295.     end
  296.  
  297.     for d=1:qdim
  298.       for i=1:2
  299.         for j=1:2
  300.           ii = qdim*(edge[i]-1)+d
  301.           jj = qdim*(edge[j]-1)+d
  302.           if(in((ii, jj), keys(D)))
  303.             D[(ii, jj)] += elemMat[i,j]
  304.           else
  305.             D[(ii, jj)] = elemMat[i,j]
  306.           end
  307.         end
  308.       end
  309.     end
  310.   end
  311.  
  312.   return asmSparseMatrix(D,nrows=qdim*mesh.nnodes,ncols=qdim*mesh.nnodes)
  313. end
  314.  
  315.  
  316. """
  317.    asmBoundarySource(mesh::Mesh, S::Array{Float64,1}, BoundaryEdges=Set{Int64}(-1); qdim=1)
  318.  
  319. Assemble the source S on the given set of boundary edges.
  320. """
  321. function asmBoundarySource(mesh::Mesh, S::Array{Float64,1}, BoundaryEdges=Set{Int64}(-1); qdim=1)
  322.   V = zeros(mesh.nnodes)
  323.  
  324.   if(in(-1, BoundaryEdges))
  325.     BoundaryEdges = 1:mesh.nedges
  326.   end
  327.  
  328.   for el in BoundaryEdges
  329.     edge = mesh.Edges[el]
  330.     detJ = EdgeJacobian(mesh, el)
  331.     for i=1:2
  332.       for j=1:2
  333.         for (q, x) in enumerate(quad1DX)
  334.           V[edge[i]] += S[edge[j]]*PhiEdge(j, x) * PhiEdge(i, x) * quad1DW[q] * detJ
  335.         end
  336.       end
  337.     end
  338.   end
  339.  
  340.   return V
  341. end
  342.  
  343. """
  344.    L2norm(mesh::Mesh, Mass::SparseMatrixCSC{Float64,Int64}, v::AbstractVector; qdim=1)
  345.  
  346. Computes the L2 norm of a vector v according to the mass matrix Mass.
  347. """
  348. function L2norm(Mass::SparseMatrixCSC{Float64,Int64}, v::AbstractVector; qdim=1)
  349.   return sqrt(v'*Mass*v)
  350. end
  351.  
  352. """
  353.    asmCubicTerm(mesh::Mesh, y::AbstractVector)
  354.  
  355. The cubic term of the standard semilinear parabolic equation.
  356. """
  357. function asmCubicTerm(mesh::Mesh, y::AbstractVector)
  358.  V = zeros(mesh.nnodes)
  359.  for el=1:mesh.nelems
  360.    nodes = mesh.Triangles[el]
  361.    (detJ, J) = Jacobian(mesh, el)
  362.    y_cubic = zeros(length(quadW))
  363.    for (q, x) in enumerate(quadX)
  364.      y_quad = 0
  365.      for i=1:3
  366.        y_quad += y[nodes[i]]*Phi(i, x)
  367.      end
  368.      y_cubic[q] = y_quad^3
  369.    end
  370.  
  371.    for i=1:3
  372.      for (q, x) in enumerate(quadX)
  373.        V[nodes[i]] += y_cubic[q] * Phi(i, x) * quadW[q] * detJ
  374.      end
  375.    end
  376.  
  377.  end
  378.  
  379.  return V
  380. end
  381.  
  382. """
  383.    asmCubicDerivativeMatrix(mesh::Mesh, y::AbstractVector)
  384.  
  385. Assembly of the linearization of the cubic term of the standard semilinear elliptic equation.
  386. """
  387. function asmCubicDerivativeMatrix(mesh::Mesh, y::AbstractVector)
  388.  D = Dict{Tuple{Int64,Int64}, Float64}()
  389.  
  390.  for el=1:mesh.nelems
  391.    nodes = mesh.Triangles[el]
  392.    y_quadratic = zeros(length(quadW))
  393.    for (q, x) in enumerate(quadX)
  394.      y_quad = 0
  395.      for i=1:3
  396.        y_quad += y[nodes[i]]*Phi(i, x)
  397.      end
  398.      y_quadratic[q] = y_quad^2
  399.    end
  400.  
  401.    (detJ, J) = Jacobian(mesh, el)
  402.    elemMat = zeros(3,3)
  403.    for i=1:3
  404.      for j=1:3
  405.        for (q, x) in enumerate(quadX)
  406.          elemMat[i,j] += 3.0* y_quadratic[q] * Phi(i, x) * Phi(j, x) * quadW[q] * detJ
  407.        end
  408.      end
  409.    end
  410.  
  411.    for i=1:3
  412.      for j=1:3
  413.        if(in((nodes[i], nodes[j]), keys(D)))
  414.          D[(nodes[i], nodes[j])] += elemMat[i,j]
  415.        else
  416.          D[(nodes[i], nodes[j])] = elemMat[i,j]
  417.        end
  418.      end
  419.    end
  420.  end
  421.  
  422.  return asmSparseMatrix(D)
  423. end
  424.  
  425. """
  426.    asmCubicSecondDerivativeMatrix(mesh::Mesh, y::AbstractVector, p::AbstractVector)
  427.  
  428. Assembly of the second derivative of the cubic term of the standard semilinear elliptic equation
  429. around the state y.
  430. """
  431. function asmCubicSecondDerivativeMatrix(mesh::Mesh, y::AbstractVector, p::AbstractVector)
  432.  D = Dict{Tuple{Int64,Int64}, Float64}()
  433.  
  434.  for el=1:mesh.nelems
  435.    nodes = mesh.Triangles[el]
  436.    y_quad = zeros(length(quadW))
  437.    p_quad = zeros(length(quadW))
  438.    for i=1:3
  439.      for (q, x) in enumerate(quadX)
  440.        y_quad[q] += y[nodes[i]]*Phi(i, x)
  441.        p_quad[q] += p[nodes[i]]*Phi(i, x)
  442.      end
  443.    end
  444.  
  445.    (detJ, J) = Jacobian(mesh, el)
  446.    elemMat = zeros(3,3)
  447.    for i=1:3
  448.      for j=1:3
  449.        for (q, x) in enumerate(quadX)
  450.          elemMat[i,j] += 6.0 * y_quad[q] * p_quad[q] * Phi(i, x) * Phi(j, x) * quadW[q] * detJ
  451.        end
  452.      end
  453.    end
  454.  
  455.    for i=1:3
  456.      for j=1:3
  457.        if(in((nodes[i], nodes[j]), keys(D)))
  458.          D[(nodes[i], nodes[j])] += elemMat[i,j]
  459.        else
  460.          D[(nodes[i], nodes[j])] = elemMat[i,j]
  461.        end
  462.      end
  463.    end
  464.  end
  465.  
  466.  return asmSparseMatrix(D)
  467. end
  468.  
  469. """
  470.    strainTensor(grad::AbstractMatrix)
  471.  
  472. Strain tensor for linear elasticity with gradient as argument.
  473. """
  474. function strainTensor(grad::AbstractMatrix)
  475.  return 0.5*(grad + grad')
  476. end
  477.  
  478. """
  479.    stressTensor(grad::AbstractMatrix, lambda::Float64, mu::Float64)
  480.  
  481. Strain tensor for linear elasticity with gradient as argument.
  482. """
  483. function stressTensor(grad::AbstractMatrix, lambda::Float64, mu::Float64)
  484.   epsilon = strainTensor(grad)
  485.   return lambda * tr(epsilon) * [1.0 0.0;0.0 1.0] + 2.0 * mu * epsilon
  486. end
  487.  
  488. """
  489.    asmElasticity(mesh::Mesh, lambda::Float64, mu::Float64)
  490.  
  491. Assembly of the linear elasticity stiffness matrix for constant coefficients lambda and mu.
  492. """
  493. function asmElasticity(mesh::Mesh, lambda::Float64, mu::Float64)
  494.   D = Dict{Tuple{Int64,Int64}, Float64}()
  495.  
  496.   qdim = 2
  497.  
  498.   for el=1:mesh.nelems
  499.     nodes = mesh.Triangles[el]
  500.     (detJ, J) = Jacobian(mesh, el)
  501.     elemMat = zeros(qdim*3,qdim*3)
  502.     for i=1:3
  503.       for j=1:3
  504.         for ic=1:qdim
  505.           for jc=1:qdim
  506.             grad_i = zeros(2,2)
  507.             grad_i[:,ic] = J*gradPhi(i)
  508.             grad_j = zeros(2,2)
  509.             grad_j[:,jc] = J*gradPhi(j)
  510.             elemMat[qdim*(i-1)+ic,qdim*(j-1)+jc] += dot(stressTensor(grad_j,lambda,mu), strainTensor(grad_i))
  511.           end
  512.         end
  513.       end
  514.     end
  515.     elemMat *= sum(quadW)*detJ
  516.  
  517.     for i=1:3
  518.       for j=1:3
  519.         for ic=1:qdim
  520.           for jc=1:qdim
  521.             ii = qdim*(nodes[i]-1)+ic
  522.             jj = qdim*(nodes[j]-1)+jc
  523.             if(in((ii, jj), keys(D)))
  524.               D[(ii, jj)] += elemMat[qdim*(i-1)+ic,qdim*(j-1)+jc]
  525.             else
  526.               D[(ii, jj)] = elemMat[qdim*(i-1)+ic,qdim*(j-1)+jc]
  527.             end
  528.           end
  529.         end
  530.       end
  531.     end
  532.   end
  533.  
  534.   return asmSparseMatrix(D)
  535. end
  536.  
  537. """
  538.    computeGradient(mesh::Mesh, y::AbstractVector; qdim=1)
  539.  
  540. Compute the gradient of a state y on a given mesh.
  541. """
  542. function computeGradient(mesh::Mesh, y::AbstractVector; qdim=1)
  543.   grad = zeros(2*qdim*mesh.nelems)
  544.   for el=1:mesh.nelems
  545.     nodes = mesh.Triangles[el]
  546.     (detJ, J) = Jacobian(mesh, el)
  547.    
  548.     for q=1:qdim
  549.       g = view(grad, (1:2).+(2*qdim*(el-1) + 2*(q-1)))
  550.       for i=1:3
  551.         g[:] += y[qdim*(nodes[i]-1)+q]*(J*gradPhi(i))
  552.       end
  553.     end
  554.   end
  555.   return grad
  556. end
  557.  
  558. """
  559.    asmGradient(mesh::Mesh; qdim=1)
  560.  
  561. Assembles the linear mapping from a state on the given mesh to the gradient.
  562. """
  563. function asmGradient(mesh::Mesh; qdim=1)
  564.   D = Dict{Tuple{Int64,Int64}, Float64}()
  565.  
  566.   for el=1:mesh.nelems
  567.     G = zeros(2*qdim, 3*qdim)
  568.  
  569.     nodes = mesh.Triangles[el]
  570.     (detJ, J) = Jacobian(mesh, el)
  571.    
  572.     for q=1:qdim
  573.       for i=1:3
  574.         g = view(G, [2*(q-1)+1, 2*(q-1)+2], qdim*(i-1)+q)
  575.         g[:] += J*gradPhi(i)
  576.       end
  577.     end
  578.  
  579.     for i=1:2
  580.       for j=1:3
  581.         for ic=1:qdim
  582.           for jc=1:qdim
  583.             ii = 2*qdim*(el-1)+qdim*(i-1)+ic
  584.             jj = qdim*(nodes[j]-1)+jc
  585.             if(in((ii, jj), keys(D)))
  586.               D[(ii, jj)] += G[qdim*(i-1)+ic,qdim*(j-1)+jc]
  587.             else
  588.               D[(ii, jj)] = G[qdim*(i-1)+ic,qdim*(j-1)+jc]
  589.             end
  590.           end
  591.         end
  592.       end
  593.     end
  594.   end
  595.  
  596.   return asmSparseMatrix(D)
  597. end
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605. """
  606.    Boundary
  607.  
  608. Structure holding sets of node and edge indices for one particular physical boundary.
  609. """
  610. mutable struct Boundary
  611.   Nodes::Set{Int64}
  612.   Edges::Set{Int64}
  613. end
  614.  
  615. """
  616.    Mesh
  617.  
  618. Structure for a triangular finite element mesh with volume and boundary markers.
  619. """
  620. mutable struct Mesh
  621.   "number of nodes"
  622.   nnodes::Int64
  623.  
  624.   "number of triangles"
  625.   nelems::Int64
  626.  
  627.   "number of physical (marked) edges"
  628.   nedges::Int64
  629.  
  630.   "list of node coordinates"
  631.   Nodes::Array{Array{Float64,1},1}
  632.  
  633.   "list of triangle node indices"
  634.   Triangles::Array{Array{Int64,1},1}
  635.  
  636.   "list of physical edges"
  637.   Edges::Array{Array{Int64,1},1}
  638.  
  639.   "dictionary of marked boundaries"
  640.   Boundaries::Dict{Int64,Boundary}
  641.  
  642.   "dictionary of marked volume regions"
  643.   Volumes::Dict{Int64,Set{Int64}}
  644. end
  645.  
  646. """
  647.  PDESystem
  648.  
  649. Structure holding all information to describe simple PDEs with Dirichlet realized
  650. resolved by multipliers.
  651. """
  652. mutable struct PDESystem
  653.   "stiffness matrix"
  654.   A::SparseMatrixCSC{Float64,Int64}
  655.  
  656.   "load vector"
  657.   b::Vector{Float64}
  658.  
  659.   "Dirichlet boundary values"
  660.   bc::Vector{Float64}
  661.  
  662.   "Dirichlet nodes"
  663.   DI::Set{Int64}
  664.  
  665.   "Dirichlet indices, in case of qdim!=1"
  666.   vec_ind::Set{Int64}
  667.  
  668.   "dimension of vector-valued state"
  669.   qdim::Int64
  670.  
  671.   "system matrix factorization"
  672.   Factors
  673.  
  674.   "system of stiffness matrix and Dirichlet conditinons"
  675.   SystemMatrix::SparseMatrixCSC{Float64,Int64}
  676.  
  677.   "Dirichlet projection matrix"
  678.   B::SparseMatrixCSC{Float64,Int64}
  679.  
  680.   "solution vector"
  681.   state::Vector{Float64}
  682.  
  683.   "rhs vector with source term and dirichlet conditions"
  684.   rhs::Vector{Float64}
  685.  
  686. end
  687.  
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694. function import_mesh(file_name::String)
  695.   f = open(file_name)
  696.  
  697.   while(!eof(f) && (l=readline(f)) != "\$MeshFormat")
  698.   end
  699.   l=readline(f)
  700.   if(parse(Int, l[1]) == 2)
  701.     mesh = import_mesh2(f)
  702.   end
  703.   if(parse(Int, l[1]) == 4)
  704.     mesh = import_mesh4(f)
  705.   end
  706.   close(f)
  707.   return mesh
  708. end
  709.  
  710. function import_mesh2(f::IOStream)
  711.  
  712.   while(!eof(f) && (l=readline(f)) != "\$Nodes")
  713.   end
  714.   l=readline(f)
  715.   nnodes = parse(Int64, l)
  716.   Nodes = zeros(nnodes)
  717.   Nodes = Array{Array{Float64, 1}, 1}(undef, nnodes)
  718.  
  719.   for i=1:nnodes
  720.     l = readline(f)
  721.     a = split(l, " ")
  722.     Nodes[i] = [parse(Float64, a[2]), parse(Float64, a[3])]
  723.   end
  724.   while(!eof(f) && (l=readline(f)) != "\$Elements")
  725.   end
  726.   l=readline(f)
  727.   nelems = parse(Int64, l)
  728.  
  729.   Triangles = Set(Array{Int64}[])
  730.   Edges = Set(Array{Int64}[])
  731.   for i=1:nelems
  732.     l = readline(f)
  733.     a = split(l, " ")
  734.     if(parse(Int64, a[2]) == 1)
  735.       push!(Edges, [parse(Int64, a[4]), parse(Int64, a[6]),
  736.                     parse(Int64, a[7])])
  737.     else
  738.       push!(Triangles, [parse(Int64, a[4]), parse(Int64, a[6]),
  739.                         parse(Int64, a[7]), parse(Int64, a[8])])
  740.     end
  741.    
  742.   end
  743.  
  744.   _Triangles = Array{Array{Int64,1},1}(undef,length(Triangles))
  745.   _Edges = Array{Array{Int64,1},1}(undef,length(Edges))
  746.  
  747.   Volumes = Dict{Int64,Set{Int64}}()
  748.   for (i,t) in enumerate(Triangles)
  749.     _Triangles[i] = copy(t[2:end])
  750.     if( !in(t[1],keys(Volumes)) )
  751.       Volumes[t[1]] = Set{Int64}()
  752.     end
  753.     push!(Volumes[t[1]], i)
  754.   end
  755.  
  756.   Boundaries = Dict{Int64, Boundary}()
  757.   for (i,el) in enumerate(Edges)
  758.     _Edges[i] = copy(el[2:end])
  759.     if( !in(el[1],keys(Boundaries)) )
  760.       Boundaries[el[1]] = Boundary(Set{Int64}(), Set{Int64}())
  761.     end
  762.     push!(Boundaries[el[1]].Edges, i)
  763.     push!(Boundaries[el[1]].Nodes, el[2])
  764.     push!(Boundaries[el[1]].Nodes, el[3])
  765.   end
  766.  
  767.   return Mesh(nnodes, length(Triangles), length(Edges), Nodes, _Triangles, _Edges, Boundaries, Volumes)
  768. end
  769.  
  770. function import_mesh4(f::IOStream)
  771.  
  772.   # 0,1,2,3 dimensional entity tags
  773.   tags = [Dict{Int64,Int64}(), Dict{Int64,Int64}(),
  774.           Dict{Int64,Int64}(), Dict{Int64,Int64}()]
  775.   while(!eof(f) && (l=readline(f)) != "\$Entities")
  776.   end
  777.   l=readline(f)
  778.   a=split(l, " ")
  779.   numTags = [parse(Int64, a[1]), parse(Int64, a[2]),
  780.              parse(Int64, a[3]), parse(Int64, a[4])]
  781.  
  782.   for i=1:4
  783.     for j=1:numTags[i]
  784.       l=readline(f)
  785.       a=split(l, " ")
  786.       if(parse(Int64, a[8])!=0)
  787.         tags[i][parse(Int64, a[1])] = parse(Int64, a[9])
  788.       end
  789.     end
  790.   end
  791.  
  792.   while(!eof(f) && (l=readline(f)) != "\$Nodes")
  793.   end
  794.   l=readline(f)
  795.   a=split(l, " ")
  796.   blocks = parse(Int64, a[1])
  797.   nnodes = parse(Int64, a[2])
  798.  
  799.   Nodes = Array{Array{Float64, 1}, 1}(undef, nnodes)
  800.   NodeNumbering = Dict{Int64, Int64}()
  801.   n=1
  802.   for i=1:blocks
  803.     l = readline(f)
  804.     a = split(l, " ")
  805.     nodesInBlock = parse(Int64, a[4])
  806.     for j=1:nodesInBlock
  807.       l = readline(f)
  808.       a = split(l, " ")
  809.       Nodes[n] = [parse(Float64, a[2]), parse(Float64, a[3])]
  810.       NodeNumbering[parse(Int64, a[1])] = n
  811.       n+=1
  812.     end
  813.   end
  814.  
  815.   while(!eof(f) && (l=readline(f)) != "\$Elements")
  816.   end
  817.  
  818.   l=readline(f)
  819.   a=split(l, " ")
  820.   blocks = parse(Int64, a[1])
  821.  
  822.   Triangles = Set(Array{Int64}[])
  823.   Edges = Set(Array{Int64}[])
  824.   for i=1:blocks
  825.     l = readline(f)
  826.     a = split(l, " ")
  827.     elemEntitiy = parse(Int64, a[1])
  828.     elemDim = parse(Int64, a[2])
  829.     elemType = parse(Int64, a[3])
  830.     elemsInBlock = parse(Int64, a[4])
  831.     for j=1:elemsInBlock
  832.       l = readline(f)
  833.       a = split(l, " ")
  834.       if(elemType == 1)
  835.         push!(Edges, [tags[elemDim+1][elemEntitiy], parse(Int64, a[2]),
  836.                       parse(Int64, a[3])])
  837.       elseif(elemType == 2)
  838.         push!(Triangles, [tags[elemDim+1][elemEntitiy], parse(Int64, a[2]),
  839.                           parse(Int64, a[3]), parse(Int64, a[4])])
  840.       else
  841.         println("Not supported element tpye", elemType)
  842.       end
  843.     end
  844.   end
  845.  
  846.   _Triangles = Array{Array{Int64,1},1}(undef,length(Triangles))
  847.   _Edges = Array{Array{Int64,1},1}(undef,length(Edges))
  848.  
  849.   Volumes = Dict{Int64,Set{Int64}}()
  850.   for (i,t) in enumerate(Triangles)
  851.     _Triangles[i] = [NodeNumbering[n] for n in t[2:end]]
  852.     if( !in(t[1],keys(Volumes)) )
  853.       Volumes[t[1]] = Set{Int64}()
  854.     end
  855.     push!(Volumes[t[1]], i)
  856.   end
  857.  
  858.   Boundaries = Dict{Int64, Boundary}()
  859.   for (i,el) in enumerate(Edges)
  860.     _Edges[i] = [NodeNumbering[n] for n in el[2:end]]
  861.     if( !in(el[1],keys(Boundaries)) )
  862.       Boundaries[el[1]] = Boundary(Set{Int64}(), Set{Int64}())
  863.     end
  864.     push!(Boundaries[el[1]].Edges, i)
  865.     push!(Boundaries[el[1]].Nodes, NodeNumbering[el[2]])
  866.     push!(Boundaries[el[1]].Nodes, NodeNumbering[el[3]])
  867.   end
  868.  
  869.   return Mesh(nnodes, length(Triangles), length(Edges), Nodes, _Triangles, _Edges, Boundaries, Volumes)
  870. end
  871.  
  872. function write_vtk_mesh(mesh::Mesh, file_name::String)
  873.   points = zeros(Float64, length(mesh.Nodes[1]), length(mesh.Nodes))
  874.   for (i,p) in enumerate(mesh.Nodes)
  875.     points[:,i] = copy(p)
  876.   end
  877.  
  878.   cells = Array{MeshCell,1}(undef, mesh.nelems)
  879.   for (i,t) in enumerate(mesh.Triangles)
  880.     cells[i] = MeshCell(VTKCellTypes.VTK_TRIANGLE, t)
  881.   end
  882.  
  883.   return vtk_grid(file_name, points, cells)
  884. end
  885.  
  886. function Jacobian(v1::Array{Float64,1}, v2::Array{Float64,1}, v3::Array{Float64,1})
  887.   J = inv([v2-v1 v3-v1]')
  888.  return 1.0/det(J), J
  889. end
  890.  
  891. function Jacobian(mesh::Mesh, elem::Int64)
  892.  t = mesh.Triangles[elem]
  893.  return Jacobian(mesh.Nodes[t[1]], mesh.Nodes[t[2]], mesh.Nodes[t[3]])
  894. end
  895.  
  896. function EdgeJacobian(mesh::Mesh, elem::Int64)
  897.  el = mesh.Edges[elem]
  898.  return norm(mesh.Nodes[el[1]] - mesh.Nodes[el[2]])
  899. end
  900.  
  901. function GetBoundaryNodes(mesh::Mesh, marker::Int64)
  902.  return collect(mesh.Boundaries[marker].Nodes)
  903. end
  904.  
  905.  
  906.  
  907.  
  908. module MinFEM
  909.  
  910. using SparseArrays, LinearAlgebra, WriteVTK
  911.  
  912. export PDESystem,
  913.       solve,
  914.       refresh,
  915.       evaluateMeshFunction,
  916.       asmBoundarySource,
  917.       getDirichletProjection,
  918.       asmLaplacian,
  919.       asmMassMatrix,
  920.       asmBoundaryMassMatrix,
  921.       asmCubicSecondDerivativeMatrix,
  922.       asmCubicDerivativeMatrix,
  923.       asmCubicTerm,
  924.       asmElasticity,
  925.       asmDirichletCondition,
  926.       L2norm,
  927.       asmGradient,
  928.       computeGradient,
  929.       Mesh,
  930.       import_mesh,
  931.       write_vtk_mesh
  932.  
  933. include("fe_types.jl")
  934. include("mesh_methods.jl")
  935. include("fe_methods.jl")
  936.  
  937. end # module
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement