time | calls | line |
---|
| | 1 | function [Dfs, Dfs_bc, Dfs_bc_rhs] = Diffusion_Operator(stagr, Node, bcsD, bcsO, bcsN,...
|
| | 2 | dx, dy, nu_x, nu_y, Rm_Singularity)
|
| | 3 | % function [Dfs, Dfs_bc, Dfs_bc_rhs] = Diffusion_Operator(stagr, Node,...
|
| | 4 | % bcsD, bcsO, bcsN,dx, dy, nu_x, nu_y, Rm_Singularity)
|
| | 5 | % This function creates the discrete diffusion operator (matrix), its RHS vector
|
| | 6 | % and the matrix to generate this RHS vector from boundary conditions.
|
| | 7 | %
|
| | 8 | % Warning: Note that the diffusion operator here is meant to be
|
| | 9 | % - nu_x d^2/dx^2 - nu_y d^2/dy^2
|
| | 10 | % This is not simply a Laplace operator! Two things to keep in mind:
|
| | 11 | % 1. There is a negative sign.
|
| | 12 | % 2. The two diffusion coeffcients are included and can be different.
|
| | 13 | %
|
| | 14 | % To further clarify the usage, we consider the following Poisson equation about P
|
| | 15 | % (- nu_x d^2/dx^2 - nu_y d^2/dy^2)P = b
|
| | 16 | % where b is some arbitray forcing.
|
| | 17 | % With the boundary conditions specified as the input of this Matlab function,
|
| | 18 | % after the output is obtained, the discrete version of the Poisson equation is
|
| | 19 | % Dfs * P_hat = b_hat + Dfs_bc_rhs
|
| | 20 | % Solving this linear system gives the numerical solution of P:
|
| | 21 | % P_hat = (Dfs)^(-1) * (b_hat + Dfs_bc_rhs)
|
| | 22 | %
|
| | 23 | % INPUTS:
|
| | 24 | % stagr: String indicating which grid to use: 'P', 'u', or 'v'.
|
| | 25 | % Node: Node numbering matrix.
|
| | 26 | % NOTE: Node needs to include boundary conditions. In the case for
|
| | 27 | % periodic boundaries, the periodicity needs to be included. See NodePad.m
|
| | 28 | % bcsD: Vector containing the values of Dirichlet BCs.
|
| | 29 | % bcsO: Vector containing the IDs of Dirichelet BCs that are actually open BCs.
|
| | 30 | % bcsN: Vector containing the values of Neumann BCs.
|
| | 31 | % (eg. bcsN = g means du/dn = g on the boundary)
|
| | 32 | % dx: Mesh spacing in x direction
|
| | 33 | % dy: Mesh sapcing in y direction
|
| | 34 | % nu_x: Diffusion coeffcients in x direction
|
| | 35 | % nu_y: Diffusion coeffcients in y direction
|
| | 36 | %
|
| | 37 | % Rm_Singularity: (Optional) Logical variable indicating whether to remove
|
| | 38 | % the singularity of the operator matrix Dfs when no Dirichlet BCs are
|
| | 39 | % specified. The singularity is removed by changing the last equation to
|
| | 40 | % be one setting the last interior cell equal to 0.
|
| | 41 | %
|
| | 42 | % OUTPUTS:
|
| | 43 | % Dfs: The diffusion operator matrix
|
| | 44 | % Dfs_bc: The matrix used to create the right-hand-side vector
|
| | 45 | % Dfs_bc_rhs: The right-hand-side vector from BC contributions
|
| | 46 | %
|
| | 47 | % See also: NodePad.m
|
| | 48 | %
|
| | 49 | % Date: Dec. 2013
|
| | 50 | % Author: Jing Lin
|
| | 51 |
|
| | 52 |
|
| | 53 | %% Preliminaries
|
| | 54 |
|
| | 55 | % Nx: Number of cells in the x-direction (include boundaries)
|
| | 56 | % Ny: Number of cells in the y-direction (include boundaries)
|
| 4 | 57 | [Ny, Nx] = size(Node);
|
| | 58 |
|
| 4 | 59 | NbcsD = length(bcsD);
|
| 4 | 60 | NbcsO = length(bcsO);
|
| 4 | 61 | NbcsN = length(bcsN);
|
| 4 | 62 | Nbcs = NbcsD + NbcsN; % Number of all boundary conditions
|
| 4 | 63 | bcD_ID = 1 : NbcsD;
|
| 4 | 64 | bcN_ID = (NbcsD + 1) : Nbcs;
|
| 4 | 65 | Int_ID = (Nbcs + 1) : max(Node(:));
|
| 4 | 66 | Num_Cell = length(Int_ID); % Number of interior cells
|
| | 67 |
|
| | 68 | % Define the number clusters appearing in entries of diffusion operator matrix
|
| 4 | 69 | Cx = nu_x/dx^2;
|
| 4 | 70 | Cy = nu_y/dy^2;
|
| | 71 |
|
| | 72 |
|
| | 73 | %% Build a preliminary matrix A of size Num_Cell * (Num_Cell + Nbcs)
|
| | 74 |
|
| | 75 | %Create the indices for the entries of A
|
| 4 | 76 | idsx = 2 : (Nx - 1);
|
| 4 | 77 | idsy = 2 : (Ny - 1);
|
0.03 | 4 | 78 | I = repmat(Node(idsy, idsx) - Nbcs, 1, 5);
|
0.05 | 4 | 79 | J = [Node(idsy, idsx), Node(idsy, idsx - 1), Node(idsy, idsx + 1),...
|
| | 80 | Node(idsy + 1, idsx), Node(idsy - 1, idsx)];
|
0.14 | 4 | 81 | J(I <= 0) = []; I(I <= 0) = []; I = I(:); J = J(:);
|
| | 82 |
|
| | 83 | % Create the A matrix in sparse form
|
| 4 | 84 | One = ones(Num_Cell, 1);
|
0.13 | 4 | 85 | A = sparse(I, J, kron([2*(Cx+Cy);-Cx;-Cx;-Cy;-Cy], One),...
|
| | 86 | Num_Cell, Num_Cell + Nbcs, 5 * Num_Cell);
|
| | 87 |
|
| | 88 | % Break the A matrix into three parts corresponding to Dirichlet, Neumann boundary
|
| | 89 | % cells and interior cells
|
| 4 | 90 | A_Dbc = A(:,bcD_ID);
|
| 4 | 91 | A_Nbc = A(:,bcN_ID);
|
0.03 | 4 | 92 | A = A(:, Int_ID);
|
| | 93 |
|
| | 94 |
|
| | 95 | %% Construct an adjacency matrix Adj
|
| | 96 |
|
| | 97 | % Construct an adjacency matrix of the same size as A indicating in which direction
|
| | 98 | % the adjacent cells corresponding to entries of A lie.
|
| | 99 | % The mapping follows the rule:
|
| | 100 | % 1 : Center cell (i , j)
|
| | 101 | % 2 : West cell (i ,j-1)
|
| | 102 | % 3 : East cell (i ,j+1)
|
| | 103 | % 4 : South cell (i+1, j)
|
| | 104 | % 5 : North cell (i-1, j)
|
| | 105 | % 6 : Far west cell (i ,j-2)
|
| | 106 | % 7 : Far east cell (i ,j+2)
|
| | 107 | % 8 : Far south cell (i+2, j)
|
| | 108 | % 9 : Far north cell (i-2, j)
|
| | 109 |
|
| 4 | 110 | idsx2 = 2 : (Nx - 2);
|
| 4 | 111 | idsy2 = 2 : (Ny - 2);
|
0.13 | 4 | 112 | Adj = sparse(I, J, kron([1;2;3;4;5], One), Num_Cell, Num_Cell + Nbcs, 9 * Num_Cell);
|
| | 113 |
|
| | 114 | % Mark the far west cells.
|
| 4 | 115 | I = Node(idsy, idsx2+1) - Nbcs; J = Node(idsy, idsx2-1);
|
0.03 | 4 | 116 | J(I <= 0) = []; I(I <= 0) = []; I = I(:); J = J(:);
|
0.03 | 4 | 117 | Adj = Adj + sparse(I, J, 6*ones(length(I), 1), Num_Cell, Num_Cell + Nbcs);
|
| | 118 |
|
| | 119 | % Mark the far east cells.
|
< 0.01 | 4 | 120 | I = Node(idsy, idsx2) - Nbcs; J = Node(idsy, idsx2+2);
|
0.03 | 4 | 121 | J(I <= 0) = []; I(I <= 0) = []; I = I(:); J = J(:);
|
0.05 | 4 | 122 | Adj = Adj + sparse(I, J, 7*ones(length(I), 1), Num_Cell, Num_Cell + Nbcs);
|
| | 123 |
|
| | 124 | % Mark the far south cells.
|
0.01 | 4 | 125 | I = Node(idsy2, idsx) - Nbcs; J = Node(idsy2+2, idsx);
|
0.02 | 4 | 126 | J(I <= 0) = []; I(I <= 0) = []; I = I(:); J = J(:);
|
0.04 | 4 | 127 | Adj = Adj + sparse(I, J, 8*ones(length(I), 1), Num_Cell, Num_Cell + Nbcs);
|
| | 128 |
|
| | 129 | % Mark the far north cells.
|
0.01 | 4 | 130 | I = Node(idsy2+1, idsx) - Nbcs; J = Node(idsy2-1, idsx);
|
< 0.01 | 4 | 131 | J(I <= 0) = []; I(I <= 0) = []; I = I(:); J = J(:);
|
0.05 | 4 | 132 | Adj = Adj + sparse(I, J, 9*ones(length(I), 1), Num_Cell, Num_Cell + Nbcs);
|
| | 133 |
|
| | 134 | % Break the Adj matrix into three parts corresponding to Dirichlet, Neumann boundary
|
| | 135 | % cells and interior cells
|
| 4 | 136 | Adj_Dbc = Adj(:,bcD_ID);
|
| 4 | 137 | Adj_Nbc = Adj(:,bcN_ID);
|
0.02 | 4 | 138 | Adj = Adj(:, Int_ID);
|
| | 139 |
|
| | 140 |
|
| | 141 | %% Set up the Dirichlet, Neumann and open boundary conditions
|
| | 142 |
|
| 4 | 143 | if ~isempty(bcsD)
|
| | 144 |
|
| | 145 | % Dirichlet BC along x-direction
|
| 3 | 146 | if (stagr == 'P')||(stagr == 'v')
|
| 2 | 147 | Posi = (Adj_Dbc == 2)|(Adj_Dbc == 3);
|
< 0.01 | 2 | 148 | Cell_ID = find(sum(Posi, 2));
|
| | 149 | % Modify the boundary cell coeffcients
|
| 2 | 150 | A_Dbc(Posi) = A_Dbc(Posi) + (-(-1) + (-16/5))*Cx;
|
| | 151 | % Modify the center cell coefficients
|
| 2 | 152 | Temp_A = (Adj == 1);
|
| 2 | 153 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 2 | 154 | A(Cell_ID,:) = A(Cell_ID,:) + (-2 + 5)*Cx*Temp_A;
|
| | 155 | % Modify the inward interior cell coefficients
|
0.01 | 2 | 156 | Temp_A = (Adj == 2)|(Adj == 3);
|
| 2 | 157 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 2 | 158 | A(Cell_ID,:) = A(Cell_ID,:) + (-(-1) + (-2))*Cx*Temp_A;
|
| | 159 | % Modify the far inward interior cell coefficients
|
< 0.01 | 2 | 160 | Temp_A = (Adj == 6)|(Adj == 7);
|
| 2 | 161 | Temp_A = Temp_A(Cell_ID, :);
|
0.01 | 2 | 162 | A(Cell_ID,:) = A(Cell_ID,:) + (-0 + 1/5)*Cx*Temp_A;
|
| 2 | 163 | end;
|
| | 164 |
|
| | 165 | % Dirichlet BC along y-direction
|
| 3 | 166 | if (stagr == 'P')||(stagr == 'u')
|
| 2 | 167 | Posi = (Adj_Dbc == 4)|(Adj_Dbc == 5);
|
| 2 | 168 | Cell_ID = find(sum(Posi, 2));
|
| | 169 | % Modify the boundary cell coeffcients
|
| 2 | 170 | A_Dbc(Posi) = A_Dbc(Posi) + (-(-1) + (-16/5))*Cy;
|
| | 171 | % Modify the center cell coefficients
|
| 2 | 172 | Temp_A = (Adj == 1);
|
| 2 | 173 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 2 | 174 | A(Cell_ID,:) = A(Cell_ID,:) + (-2 + 5)*Cy*Temp_A;
|
| | 175 | % Modify the inward interior cell coefficients
|
< 0.01 | 2 | 176 | Temp_A = (Adj == 4)|(Adj == 5);
|
| 2 | 177 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 2 | 178 | A(Cell_ID,:) = A(Cell_ID,:) + (-(-1) + (-2))*Cy*Temp_A;
|
| | 179 | % Modify the far inward interior cell coefficients
|
< 0.01 | 2 | 180 | Temp_A = (Adj == 8)|(Adj == 9);
|
| 2 | 181 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 2 | 182 | A(Cell_ID,:) = A(Cell_ID,:) + (-0 + 1/5)*Cy*Temp_A;
|
| 2 | 183 | end;
|
| 3 | 184 | end;
|
| | 185 |
|
| 4 | 186 | if ~isempty(bcsN)
|
0.04 | 4 | 187 | A(Adj == 1) = A(Adj == 1) + sum(A_Nbc, 2);
|
| | 188 |
|
| | 189 | % Neumann BC along x-direction
|
| 4 | 190 | Posi = (Adj_Nbc == 2)|(Adj_Nbc == 3);
|
| 4 | 191 | if (stagr == 'P')||(stagr == 'v')
|
| | 192 | % Modify the boundary cell coeffcients
|
| 3 | 193 | A_Nbc(Posi) = A_Nbc(Posi) * dx;
|
| 1 | 194 | else
|
| 1 | 195 | Cell_ID = find(sum(Posi, 2));
|
| | 196 | % Modify the boundary cell coeffcients
|
| 1 | 197 | A_Nbc(Posi) = A_Nbc(Posi) + (-(-1)*Cx + (-6/11)*Cx*dx);
|
| | 198 | % Modify the center cell coefficients
|
< 0.01 | 1 | 199 | Temp_A = (Adj == 1);
|
| 1 | 200 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 1 | 201 | A(Cell_ID,:) = A(Cell_ID,:) + (-(2-1) + 4/11)*Cx*Temp_A;
|
| | 202 | % Modify the inward interior cell coefficients
|
| 1 | 203 | Temp_A = (Adj == 2)|(Adj == 3);
|
< 0.01 | 1 | 204 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 1 | 205 | A(Cell_ID,:) = A(Cell_ID,:) + (-(-1) + (-2/11))*Cx*Temp_A;
|
| | 206 | % Modify the far inward interior cell coefficients
|
| 1 | 207 | Temp_A = (Adj == 6)|(Adj == 7);
|
| 1 | 208 | Temp_A = Temp_A(Cell_ID, :);
|
0.01 | 1 | 209 | A(Cell_ID,:) = A(Cell_ID,:) + (-0 + (-2/11))*Cx*Temp_A;
|
| 1 | 210 | end;
|
| | 211 |
|
| | 212 | % Neumann BC along y-direction
|
| 4 | 213 | Posi = (Adj_Nbc == 4)|(Adj_Nbc == 5);
|
| 4 | 214 | if (stagr == 'P')||(stagr == 'u')
|
| | 215 | % Modify the boundary cell coeffcients
|
< 0.01 | 3 | 216 | A_Nbc(Posi) = A_Nbc(Posi) * dy;
|
| 1 | 217 | else
|
| 1 | 218 | Cell_ID = find(sum(Posi, 2));
|
| | 219 | % Modify the boundary cell coeffcients
|
| 1 | 220 | A_Nbc(Posi) = A_Nbc(Posi) + (-(-1)*Cy + (-6/11)*Cy*dy);
|
| | 221 | % Modify the center cell coefficients
|
| 1 | 222 | Temp_A = (Adj == 1);
|
| 1 | 223 | Temp_A = Temp_A(Cell_ID, :);
|
| 1 | 224 | A(Cell_ID,:) = A(Cell_ID,:) + (-(2-1) + 4/11)*Cy*Temp_A;
|
| | 225 | % Modify the inward interior cell coefficients
|
< 0.01 | 1 | 226 | Temp_A = (Adj == 4)|(Adj == 5);
|
| 1 | 227 | Temp_A = Temp_A(Cell_ID, :);
|
| 1 | 228 | A(Cell_ID,:) = A(Cell_ID,:) + (-(-1) + (-2/11))*Cy*Temp_A;
|
| | 229 | % Modify the far inward interior cell coefficients
|
< 0.01 | 1 | 230 | Temp_A = (Adj == 8)|(Adj == 9);
|
| 1 | 231 | Temp_A = Temp_A(Cell_ID, :);
|
| 1 | 232 | A(Cell_ID,:) = A(Cell_ID,:) + (-0 + (-2/11))*Cy*Temp_A;
|
| 1 | 233 | end;
|
| 4 | 234 | end;
|
| | 235 |
|
| 4 | 236 | if (stagr == 'P')&&(~isempty(bcsO))
|
| | 237 |
|
| | 238 | % Modify the boundary cell coeffcients
|
| 1 | 239 | A_Dbc(:, bcsO) = 0;
|
| | 240 |
|
| 1 | 241 | Adj_Obc = Adj_Dbc(:, bcsO);
|
| | 242 |
|
| | 243 | % Open BC along x-direction
|
| 1 | 244 | Posi = (Adj_Obc == 2)|(Adj_Obc == 3);
|
| 1 | 245 | Cell_ID = find(sum(Posi, 2));
|
| | 246 | % Modify the center cell coefficients
|
< 0.01 | 1 | 247 | Temp_A = (Adj == 1);
|
| 1 | 248 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 1 | 249 | A(Cell_ID,:) = A(Cell_ID,:) + (-5 + (-1/3))*Cx*Temp_A;
|
| | 250 | % Modify the inward interior cell coefficients
|
| 1 | 251 | Temp_A = (Adj == 2)|(Adj == 3);
|
| 1 | 252 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 1 | 253 | A(Cell_ID,:) = A(Cell_ID,:) + (-(-2) + 2/3)*Cx*Temp_A;
|
| | 254 | % Modify the far inward interior cell coefficients
|
< 0.01 | 1 | 255 | Temp_A = (Adj == 6)|(Adj == 7);
|
| 1 | 256 | Temp_A = Temp_A(Cell_ID, :);
|
< 0.01 | 1 | 257 | A(Cell_ID,:) = A(Cell_ID,:) + (-1/5 + (-1/3))*Cx*Temp_A;
|
| | 258 |
|
| | 259 | % Open BC along y-direction
|
| 1 | 260 | Posi = (Adj_Obc == 4)|(Adj_Obc == 5);
|
| 1 | 261 | Cell_ID = find(sum(Posi, 2));
|
| | 262 | % Modify the center cell coefficients
|
< 0.01 | 1 | 263 | Temp_A = (Adj == 1);
|
| 1 | 264 | Temp_A = Temp_A(Cell_ID, :);
|
| 1 | 265 | A(Cell_ID,:) = A(Cell_ID,:) + (-5 + (-1/3))*Cy*Temp_A;
|
| | 266 | % Modify the inward interior cell coefficients
|
< 0.01 | 1 | 267 | Temp_A = (Adj == 4)|(Adj == 5);
|
| 1 | 268 | Temp_A = Temp_A(Cell_ID, :);
|
| 1 | 269 | A(Cell_ID,:) = A(Cell_ID,:) + (-(-2) + 2/3)*Cy*Temp_A;
|
| | 270 | % Modify the far inward interior cell coefficients
|
< 0.01 | 1 | 271 | Temp_A = (Adj == 8)|(Adj == 9);
|
| 1 | 272 | Temp_A = Temp_A(Cell_ID, :);
|
| 1 | 273 | A(Cell_ID,:) = A(Cell_ID,:) + (-1/5 + (-1/3))*Cy*Temp_A;
|
| 1 | 274 | end;
|
| | 275 |
|
| | 276 | % Remove the singularity if no Dirichlet BCs are specified.
|
| 4 | 277 | if (nargin == 10)&&(Rm_Singularity)&&(NbcsD == NbcsO)&&(stagr == 'P')
|
< 0.01 | 1 | 278 | A(end, :) = 0; A(end, end) = 1;
|
| 1 | 279 | A_Dbc(end, :) = 0; A_Nbc(end, :) = 0;
|
| 1 | 280 | end;
|
| | 281 |
|
| | 282 |
|
| | 283 | %% Finally, distribute entries of A to outputs
|
| | 284 |
|
| 4 | 285 | Dfs = A;
|
| 4 | 286 | Dfs_bc = [A_Dbc, A_Nbc];
|
| 4 | 287 | Dfs_bc_rhs = -Dfs_bc * [bcsD; bcsN];
|