├── .gitignore ├── .gitattributes ├── src ├── finite_differencers │ ├── dfdxFiniteDifferencePeriodic.m │ ├── dfdxFiniteDifference.m │ ├── d2fdx2FiniteDifferencePeriodic.m │ ├── d2fdx2FiniteDifference.m │ ├── dfdxFiniteDifferenceNonUniform.m │ ├── d2fdx2FiniteDifferenceNonUniform.m │ ├── dfdxFiniteDifferenceMatrix.m │ ├── d2fdx2FiniteDifferenceMatrix.m │ ├── dfdxFiniteDifferenceNonUniformMatrix.m │ ├── d2fdx2FiniteDifferenceNonUniformMatrix.m │ ├── dfdxFiniteDifferencePeriodicMatrix.m │ └── d2fdx2FiniteDifferencePeriodicMatrix.m └── DNS_cylindrical_axisymmetric_finiteDifference │ ├── DNScylAxiFDcalcVelocity.m │ ├── private │ ├── DNScylAxiFDmakePoissonCoefficientMatrix.m │ ├── DNScylAxiFDtimeDerivative.m │ └── DNScylAxiFDdoTimeStep.m │ ├── DNScylAxiFDapplyBoundaryConditions.m │ └── DNScylAxiFDsimulation.m └── COPYING.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Autosaves 2 | *.m~ 3 | *.asv 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.m text 7 | *.txt text 8 | -------------------------------------------------------------------------------- /src/finite_differencers/dfdxFiniteDifferencePeriodic.m: -------------------------------------------------------------------------------- 1 | function DfDx = dfdxFiniteDifferencePeriodic(f,h,dim) 2 | %DFDXFINITEDIFFERENCEPERIODIC does first finite difference on a periodic uniform grid. 3 | % DFDX = DFDXFINITEDIFFERENCEPERIODIC(F, H, DIM) 4 | % Does the first centered finite difference on a periodic uniform grid 5 | % of F along direction DIM (1 is row, 2 is column, and 3 is page) where H 6 | % is the grid spacing. The formula is, for a one dimensional F (extends to 7 | % two and three dimensions by just re-application of it to each 8 | % row/col/page/whatever), given by 9 | % 10 | % Df_i/Dx = (f_(i+1) - f_(i-1)) / h 11 | % 12 | % 13 | % 14 | % Copyright 2012 Freja Nordsiek 15 | % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); 17 | % you may not use this file except in compliance with the License. 18 | % You may obtain a copy of the License at 19 | % 20 | % http://www.apache.org/licenses/LICENSE-2.0 21 | % 22 | % Unless required by applicable law or agreed to in writing, software 23 | % distributed under the License is distributed on an "AS IS" BASIS, 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | % See the License for the specific language governing permissions and 26 | % limitations under the License. 27 | 28 | % All we have to do is simply add a grid points on each that are the grid 29 | % points on the other side and just pass it onto the function that handles 30 | % the non-periodic case. 31 | 32 | switch dim 33 | case 1 34 | DfDx = dfdxFiniteDifference(cat(1,f(end,:,:),f,f(1,:,:)),h,dim); 35 | case 2 36 | DfDx = dfdxFiniteDifference(cat(2,f(:,end,:),f,f(:,1,:)),h,dim); 37 | case 3 38 | DfDx = dfdxFiniteDifference(cat(3,f(:,:,end),f,f(:,:,1)),h,dim); 39 | otherwise 40 | error('DIM can only be 1, 2, or 3.'); 41 | end 42 | -------------------------------------------------------------------------------- /src/finite_differencers/dfdxFiniteDifference.m: -------------------------------------------------------------------------------- 1 | function DfDx = dfdxFiniteDifference(f,h,dim) 2 | %DFDXFINITEDIFFERENCE does first finite difference on a -uniform grid. 3 | % DFDX = DFDXFINITEDIFFERENCE(F, H, DIM) 4 | % Does the first centered finite difference on a uniform grid of F 5 | % along direction DIM (1 is row, 2 is column, and 3 is page) where H is the 6 | % grid spacing. The formula is, for a one dimensional F (extends to two and 7 | % three dimensions by just re-application of it to each 8 | % row/col/page/whatever), given by 9 | % 10 | % Df_i/Dx = (f_(i+1) - f_(i-1)) / 2*h 11 | % 12 | % 13 | % 14 | % Copyright 2012 Freja Nordsiek 15 | % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); 17 | % you may not use this file except in compliance with the License. 18 | % You may obtain a copy of the License at 19 | % 20 | % http://www.apache.org/licenses/LICENSE-2.0 21 | % 22 | % Unless required by applicable law or agreed to in writing, software 23 | % distributed under the License is distributed on an "AS IS" BASIS, 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | % See the License for the specific language governing permissions and 26 | % limitations under the License. 27 | 28 | % f_plus and f_minus (i+1 and i-1 respectively) are contructed in the 29 | % appropriate directions. 30 | 31 | switch dim 32 | case 1 33 | f_plus = f(3:end,:,:); 34 | f_minus = f(1:(end-2),:,:); 35 | case 2 36 | f_plus = f(:,3:end,:); 37 | f_minus = f(:,1:(end-2),:); 38 | case 3 39 | f_plus = f(:,:,3:end); 40 | f_minus = f(:,:,1:(end-2)); 41 | otherwise 42 | error('DIM can only be 1, 2, or 3.'); 43 | end 44 | 45 | % Now, calculate DfDx, which already has the appropriate direction stuff 46 | % handled. 47 | 48 | DfDx = (f_plus - f_minus)*(1/(2*h)); 49 | -------------------------------------------------------------------------------- /src/finite_differencers/d2fdx2FiniteDifferencePeriodic.m: -------------------------------------------------------------------------------- 1 | function D2fDx2 = d2fdx2FiniteDifferencePeriodic(f,h,dim) 2 | %D2FDX2FINITEDIFFERENCEPERIODIC does second finite difference on a periodic uniform grid. 3 | % D2FDX2 = D2FDX2FINITEDIFFERENCEPERIODIC(F, H, DIM) 4 | % Does the second centered finite difference on a periodic uniform grid 5 | % of F along direction DIM (1 is row, 2 is column, and 3 is page) where H 6 | % is the grid spacing. The formula is, for a one dimensional F (extends to 7 | % two and three dimensions by just re-application of it to each 8 | % row/col/page/whatever), given by 9 | % 10 | % D2f_i/Dx2 = (f_(i+1) - 2*f_i + f_(i-1)) / h^2 11 | % 12 | % 13 | % 14 | % Copyright 2012 Freja Nordsiek 15 | % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); 17 | % you may not use this file except in compliance with the License. 18 | % You may obtain a copy of the License at 19 | % 20 | % http://www.apache.org/licenses/LICENSE-2.0 21 | % 22 | % Unless required by applicable law or agreed to in writing, software 23 | % distributed under the License is distributed on an "AS IS" BASIS, 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | % See the License for the specific language governing permissions and 26 | % limitations under the License. 27 | 28 | % All we have to do is simply add a grid points on each that are the grid 29 | % points on the other side and just pass it onto the function that handles 30 | % the non-periodic case. 31 | 32 | switch dim 33 | case 1 34 | D2fDx2 = d2fdx2FiniteDifference(cat(1,f(end,:,:),f,f(1,:,:)),h,dim); 35 | case 2 36 | D2fDx2 = d2fdx2FiniteDifference(cat(2,f(:,end,:),f,f(:,1,:)),h,dim); 37 | case 3 38 | D2fDx2 = d2fdx2FiniteDifference(cat(3,f(:,:,end),f,f(:,:,1)),h,dim); 39 | otherwise 40 | error('DIM can only be 1, 2, or 3.'); 41 | end 42 | -------------------------------------------------------------------------------- /src/finite_differencers/d2fdx2FiniteDifference.m: -------------------------------------------------------------------------------- 1 | function D2fDx2 = d2fdx2FiniteDifference(f,h,dim) 2 | %D2FDX2FINITEDIFFERENCE does second finite difference on a uniform grid. 3 | % D2FDX2 = D2FDX2FINITEDIFFERENCE(F, H, DIM) 4 | % Does the second centered finite difference on a uniform grid of F 5 | % along direction DIM (1 is row, 2 is column, and 3 is page) where H is the 6 | % grid spacing. The formula is, for a one dimensional F (extends to two and 7 | % three dimensions by just re-application of it to each 8 | % row/col/page/whatever), given by 9 | % 10 | % D2f_i/Dx2 = (f_(i+1) - 2*f_i + f_(i-1)) / h^2 11 | % 12 | % 13 | % 14 | % Copyright 2012 Freja Nordsiek 15 | % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); 17 | % you may not use this file except in compliance with the License. 18 | % You may obtain a copy of the License at 19 | % 20 | % http://www.apache.org/licenses/LICENSE-2.0 21 | % 22 | % Unless required by applicable law or agreed to in writing, software 23 | % distributed under the License is distributed on an "AS IS" BASIS, 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | % See the License for the specific language governing permissions and 26 | % limitations under the License. 27 | 28 | % f_plus, f_0, and f_minus (i+1, i, and i-1 respectively) are contructed in 29 | % the appropriate directions. 30 | 31 | switch dim 32 | case 1 33 | f_plus = f(3:end,:,:); 34 | f_0 = f(2:(end-1),:,:); 35 | f_minus = f(1:(end-2),:,:); 36 | case 2 37 | f_plus = f(:,3:end,:); 38 | f_0 = f(:,2:(end-1),:); 39 | f_minus = f(:,1:(end-2),:); 40 | case 3 41 | f_plus = f(:,:,3:end); 42 | f_0 = f(:,:,2:(end-1)); 43 | f_minus = f(:,:,1:(end-2)); 44 | otherwise 45 | error('DIM can only be 1, 2, or 3.'); 46 | end 47 | 48 | % Now, calculate DfDx, which already has the appropriate direction stuff 49 | % handled. 50 | 51 | D2fDx2 = (f_plus - 2*f_0 + f_minus)*(1/h^2); 52 | -------------------------------------------------------------------------------- /src/finite_differencers/dfdxFiniteDifferenceNonUniform.m: -------------------------------------------------------------------------------- 1 | function DfDx = dfdxFiniteDifferenceNonUniform(f,x,dim) 2 | %DFDXFINITEDIFFERENCENONUNIFORM does first finite difference on a non-uniform grid. 3 | % DFDX = DFDXFINITEDIFFERENCENONUNIFORM(F, X, DIM) 4 | % Does the first centered finite difference on a non-uniform grid of F 5 | % along direction DIM (1 is row, 2 is column, and 3 is page) where X is the 6 | % vector containing the grid point positions in that direction. The formula 7 | % is, for a one dimensional F (extends to two and three dimensions by just 8 | % re-application of it to each row/col/page/whatever), given by 9 | % 10 | % Df_i/Dx = (f_(i+1) - f_(i-1)) / (x_(i+1) - x_(i-1)) 11 | % 12 | % 13 | % 14 | % Copyright 2012 Freja Nordsiek 15 | % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); 17 | % you may not use this file except in compliance with the License. 18 | % You may obtain a copy of the License at 19 | % 20 | % http://www.apache.org/licenses/LICENSE-2.0 21 | % 22 | % Unless required by applicable law or agreed to in writing, software 23 | % distributed under the License is distributed on an "AS IS" BASIS, 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | % See the License for the specific language governing permissions and 26 | % limitations under the License. 27 | 28 | % We have to get the x_(i+1), x_(i-1), f_(i+1), and f(i-1) in the proper 29 | % direction. To do this, x is first reshaped into a vector along the 30 | % dimension dim and then repmatted to be the same size as f. Then x_plus 31 | % and x_minus (i+1 and i-1 respectively) are constructed in the appropriate 32 | % directions. Then f_plus and f_minus are contructed in the appropriate 33 | % directions. 34 | 35 | switch dim 36 | case 1 37 | 38 | if length(x) == numel(x) 39 | x = repmat(reshape(x,[numel(x),1,1]),[1,size(f,2),size(f,3)]); 40 | end 41 | 42 | x_plus = x(3:end,:,:); 43 | x_minus = x(1:(end-2),:,:); 44 | 45 | f_plus = f(3:end,:,:); 46 | f_minus = f(1:(end-2),:,:); 47 | 48 | case 2 49 | 50 | if length(x) == numel(x) 51 | x = repmat(reshape(x,[1,numel(x),1]),[size(f,1),1,size(f,3)]); 52 | end 53 | 54 | x_plus = x(:,3:end,:); 55 | x_minus = x(:,1:(end-2),:); 56 | 57 | f_plus = f(:,3:end,:); 58 | f_minus = f(:,1:(end-2),:); 59 | 60 | case 3 61 | 62 | if length(x) == numel(x) 63 | x = repmat(reshape(x,[1,1,numel(x)]),[size(f,1),size(f,2),1]); 64 | end 65 | 66 | x_plus = x(:,:,3:end); 67 | x_minus = x(:,:,1:(end-2)); 68 | 69 | f_plus = f(:,:,3:end); 70 | f_minus = f(:,:,1:(end-2)); 71 | 72 | otherwise 73 | error('DIM can only be 1, 2, or 3.'); 74 | end 75 | 76 | % Now, calculate DfDx, which already has the appropriate direction stuff 77 | % handled. 78 | 79 | DfDx = (f_plus - f_minus)./(x_plus - x_minus); 80 | -------------------------------------------------------------------------------- /src/finite_differencers/d2fdx2FiniteDifferenceNonUniform.m: -------------------------------------------------------------------------------- 1 | function D2fDx2 = d2fdx2FiniteDifferenceNonUniform(f,x,dim) 2 | %D2FDX2FINITEDIFFERENCENONUNIFORM does second finite difference on a non-uniform grid. 3 | % D2FDX2 = D2FDX2FINITEDIFFERENCENONUNIFORM(F, X, DIM) 4 | % Does the cecond centered finite difference on a non-uniform grid of F 5 | % along direction DIM (1 is row, 2 is column, and 3 is page) where X is the 6 | % vector containing the grid point positions in that direction. The formula 7 | % is, for a one dimensional F (extends to two and three dimensions by just 8 | % re-application of it to each row/col/page/whatever), given by 9 | % 10 | % D2f_i/Dx2 = [2/(x_(i+1) - x_(i-1))] * [(y_(i+1) - y_i)/(x_(i+1) - x_i) - (y_i - y_(i-1))/(x_i - x_(i-1))] 11 | % 12 | % 13 | % 14 | % Copyright 2012 Freja Nordsiek 15 | % 16 | % Licensed under the Apache License, Version 2.0 (the "License"); 17 | % you may not use this file except in compliance with the License. 18 | % You may obtain a copy of the License at 19 | % 20 | % http://www.apache.org/licenses/LICENSE-2.0 21 | % 22 | % Unless required by applicable law or agreed to in writing, software 23 | % distributed under the License is distributed on an "AS IS" BASIS, 24 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | % See the License for the specific language governing permissions and 26 | % limitations under the License. 27 | 28 | % We have to get the x_(i+1), x_i, x_(i-1), f_(i+1), f_i, and f(i-1) in the 29 | % proper direction. To do this, x is first reshaped into a vector along the 30 | % dimension dim and then repmatted to be the same size as f. Then x_plus, 31 | % x_0, and x_minus (i+1, i, and i-1 respectively) are constructed in the 32 | % appropriate directions. Then f_plus, f_0, and f_minus are contructed in 33 | % the appropriate directions. 34 | 35 | switch dim 36 | case 1 37 | 38 | if length(x) == numel(x) 39 | x = repmat(reshape(x,[numel(x),1,1]),[1,size(f,2),size(f,3)]); 40 | end 41 | 42 | x_plus = x(3:end,:,:); 43 | x_0 = x(2:(end-1),:,:); 44 | x_minus = x(1:(end-2),:,:); 45 | 46 | f_plus = f(3:end,:,:); 47 | f_0 = f(2:(end-1),:,:); 48 | f_minus = f(1:(end-2),:,:); 49 | 50 | case 2 51 | 52 | if length(x) == numel(x) 53 | x = repmat(reshape(x,[1,numel(x),1]),[size(f,1),1,size(f,3)]); 54 | end 55 | 56 | x_plus = x(:,3:end,:); 57 | x_0 = x(:,2:(end-1),:); 58 | x_minus = x(:,1:(end-2),:); 59 | 60 | f_plus = f(:,3:end,:); 61 | f_0 = f(:,2:(end-1),:); 62 | f_minus = f(:,1:(end-2),:); 63 | 64 | case 3 65 | 66 | if length(x) == numel(x) 67 | x = repmat(reshape(x,[1,1,numel(x)]),[size(f,1),size(f,2),1]); 68 | end 69 | 70 | x_plus = x(:,:,3:end); 71 | x_0 = x(:,:,2:(end-1)); 72 | x_minus = x(:,:,1:(end-2)); 73 | 74 | f_plus = f(:,:,3:end); 75 | f_0 = f(:,:,2:(end-1)); 76 | f_minus = f(:,:,1:(end-2)); 77 | 78 | otherwise 79 | error('DIM can only be 1, 2, or 3.'); 80 | end 81 | 82 | % Now, calculate D2fDx2, which already has the appropriate direction stuff 83 | % handled. 84 | 85 | D2fDx2 = 2*((f_plus - f_0)./(x_plus - x_0) - (f_0 - f_minus)./(x_0 - x_minus))./(x_plus - x_minus); 86 | -------------------------------------------------------------------------------- /src/DNS_cylindrical_axisymmetric_finiteDifference/DNScylAxiFDcalcVelocity.m: -------------------------------------------------------------------------------- 1 | function [u v w xsi eta zeta] = DNScylAxiFDcalcVelocity(R,Z,Gamma,eta,psi,periodicZ) 2 | %NSCYLAXIFDCALCVELOCITY calculates the velocity and vorticity from the (Gamma,eta,psi) in the axisymmetric cylindrical NSE. 3 | % [U V W XSI ETA ZETA] = NSCYLAXIFDCALCVELOCITY(R,Z,GAMMA,ETA,PSI,PERIODICZ) 4 | % Calculates the fluid velocity (U,V,W) and vorticity (XSI,ETA,ZETA) fields 5 | % (r,theta,z order) from the GAMMA, ETA, PSI fields (angular velocity, 6 | % theta component of vorticity, and the 2D streamfunction respectively) at 7 | % all the points on the (z,r) grid specified by the coordinate matrices R 8 | % and Z (produced by meshgrid). The r-mesh can be non-uniformly spaced. The 9 | % z-mesh can either be non-uniformly spaced or be periodic uniformly 10 | % spaced. PERIODICZ indicates hether the system is axially periodic (true) 11 | % or not (false) 12 | % 13 | % References: 14 | % 1) JM Lopez and J Shen. An Efficient Spectral-Projection Method for 15 | % the Navier-Stokes Equations in Cylindrical Geometries - Part I - 16 | % Axisymmetric Cases. Journal of Computational Physics. 139, 308-326 17 | % (1998) 18 | % DOI: 10.1006/jcph.1997.5872 19 | % 20 | % 21 | % 22 | % Copyright 2012 Freja Nordsiek 23 | % 24 | % Licensed under the Apache License, Version 2.0 (the "License"); 25 | % you may not use this file except in compliance with the License. 26 | % You may obtain a copy of the License at 27 | % 28 | % http://www.apache.org/licenses/LICENSE-2.0 29 | % 30 | % Unless required by applicable law or agreed to in writing, software 31 | % distributed under the License is distributed on an "AS IS" BASIS, 32 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 33 | % See the License for the specific language governing permissions and 34 | % limitations under the License. 35 | 36 | % Calculate the various r-derivatives. 37 | 38 | Gamma_r = dfdxFiniteDifferenceNonUniform(Gamma,R,2); 39 | psi_r = dfdxFiniteDifferenceNonUniform(psi,R,2); 40 | psi_rr = d2fdx2FiniteDifferenceNonUniform(psi,R,2); 41 | 42 | % Calculate the various z-derivatives. The method of doing so depends on 43 | % whether the system is periodic or not. 44 | 45 | if periodicZ 46 | dz = diff(Z(1:2,1)); 47 | Gamma_z = dfdxFiniteDifferencePeriodic(Gamma,dz,1); 48 | psi_z = dfdxFiniteDifferencePeriodic(psi,dz,1); 49 | psi_zz = d2fdx2FiniteDifferencePeriodic(psi,dz,1); 50 | else 51 | Gamma_z = dfdxFiniteDifferenceNonUniform(Gamma,Z,1); 52 | psi_z = dfdxFiniteDifferenceNonUniform(psi,Z,1); 53 | psi_zz = d2fdx2FiniteDifferenceNonUniform(psi,Z,1); 54 | end 55 | 56 | % We want all the derivative matrices to be the same size as Gamma, eta, 57 | % and psi; so we have to zero pad in a column of zeros before and after for 58 | % all the r-derivative matrices since the finite difference codes only give 59 | % the derivatives for the interior r-values. 60 | 61 | pad = zeros(size(R,1),1); 62 | Gamma_r = [pad,Gamma_r,pad]; 63 | psi_r = [pad,psi_r,pad]; 64 | psi_rr = [pad,psi_rr,pad]; 65 | 66 | % If we are not axially periodic, then we need to pad a row of zeros before 67 | % and after the z-derivative matrices (the finite difference codes only 68 | % give derivatives for interior z-values) and zero out the top and bottom 69 | % rows of the r-derivatives so as to not effect the boundary points. 70 | 71 | if ~periodicZ 72 | 73 | pad = zeros(1,size(Z,2)); 74 | Gamma_z = [pad;Gamma_z;pad]; 75 | psi_z = [pad;psi_z;pad]; 76 | psi_zz = [pad;psi_zz;pad]; 77 | 78 | Gamma_r([1 end],:) = 0; 79 | psi_r([1 end],:) = 0; 80 | psi_rr([1 end],:) = 0; 81 | 82 | end 83 | 84 | % Calculate the velocity and vorticity fields. 85 | 86 | u = -psi_z./R; 87 | v = Gamma./R; 88 | w = psi_r./R; 89 | 90 | xsi = -Gamma_z./R; 91 | eta = -(psi_rr - psi_r./R + psi_zz)./R; 92 | zeta = Gamma_r./R; 93 | -------------------------------------------------------------------------------- /src/DNS_cylindrical_axisymmetric_finiteDifference/private/DNScylAxiFDmakePoissonCoefficientMatrix.m: -------------------------------------------------------------------------------- 1 | function PoissonCoefficientMatrix = DNScylAxiFDmakePoissonCoefficientMatrix(R,Z,periodicZ) 2 | %NSCYLAXIFDMAKEPOISSONCOEFFICIENTMATRIX makes the coefficient matrix to do the poisson equation in equation A.6. 3 | % POISSONCOEFFICIENTMATRIX = NSCYLAXIFDMAKEPOISSONCOEFFICIENTMATRIX(R,Z,PERIODICZ) 4 | % Makes the coefficient matrix, POISSONCOEFFICIENTMATRIX, to do the poisson 5 | % equation for Gamma in equation A.6 in Appendix Z (Lopez and Shen 1998) 6 | % that relates it to eta and R. R and Z are the coordinate matrices (made 7 | % by meshgrid) where coordinates are in (z,r) order. PERIODICZ is a flag 8 | % indicating whether the axial boundary condition is periodic (true) or not 9 | % (false). POISSONCOEFFICIENTMATRIX is constructed such that 10 | % R(:).*eta(:) = POISSONCOEFFICIENTMATRIX * psi(:). 11 | % POISSONCOEFFICIENTMATRIX is sparse and only deals with the interior 12 | % points. 13 | % 14 | % References: 15 | % 1) JM Lopez and J Shen. An Efficient Spectral-Projection Method for 16 | % the Navier-Stokes Equations in Cylindrical Geometries - Part I - 17 | % Axisymmetric Cases. Journal of Computational Physics. 139, 308-326 18 | % (1998) 19 | % 20 | % 21 | % 22 | % Copyright 2012 Freja Nordsiek 23 | % 24 | % Licensed under the Apache License, Version 2.0 (the "License"); 25 | % you may not use this file except in compliance with the License. 26 | % You may obtain a copy of the License at 27 | % 28 | % http://www.apache.org/licenses/LICENSE-2.0 29 | % 30 | % Unless required by applicable law or agreed to in writing, software 31 | % distributed under the License is distributed on an "AS IS" BASIS, 32 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 33 | % See the License for the specific language governing permissions and 34 | % limitations under the License. 35 | 36 | % Equation A.6 works out to be 37 | % 38 | % -psi_rr + (1/r)*psi_r - psi_zz = r*eta. PoissonCoefficientMatrix will 39 | % describe the right hand side. 40 | 41 | % The coefficient matrices for each term will be made separately because 42 | % the second term requires special handling due to the division by r (don't 43 | % want any 0/0 -> NaN's filling the matrix) and the third term requires 44 | % special handling depending on whether the axial boundary condition is 45 | % periodic or not. 46 | 47 | % Make the first term. 48 | 49 | negPsi_rr_coeffs = -d2fdx2FiniteDifferenceNonUniformMatrix(R,R(1,:),2); 50 | 51 | % Make the second term without dividing by R first. Then, only divide the 52 | % non-zero entries by R at tthose points (doing it this way avoids dividing 53 | % any zero entries by R that would then either stay zero or become NaN). 54 | % This has to be done using a for loop. 55 | 56 | psi_r_overR_coeffs = dfdxFiniteDifferenceNonUniformMatrix(R,R(1,:),2); 57 | for ii=find(psi_r_overR_coeffs)' 58 | [row col] = ind2sub(size(psi_r_overR_coeffs),ii); 59 | psi_r_overR_coeffs(row,col) = psi_r_overR_coeffs(row,col) / R(col); 60 | end 61 | 62 | % Make the third term. The way that this is done depends on whether the 63 | % axial boundary conditions are periodic or not. 64 | 65 | if periodicZ 66 | dz = diff(Z(1:2,1)); 67 | negPsi_zz_coeffs = -d2fdx2FiniteDifferencePeriodicMatrix(R,dz,2); 68 | else 69 | negPsi_zz_coeffs = -d2fdx2FiniteDifferenceNonUniformMatrix(R,Z(:,1),1); 70 | end 71 | 72 | % Make PoissonCoefficientMatrix by adding the different terms together. 73 | 74 | PoissonCoefficientMatrix = negPsi_rr_coeffs + psi_r_overR_coeffs + negPsi_zz_coeffs; 75 | 76 | % Now, some points not in the interior were included and even for those in 77 | % the interior, some may be using points out of the interior. These points 78 | % need to be eliminated. So, we take all the nonzero entries and get the 79 | % row and column indices. If the r-values (and z-values if the system is 80 | % not axially periodic) of either point (row or column) are on the borders, 81 | % they are eliminated by setting their coefficient to zero. 82 | 83 | indices = find(PoissonCoefficientMatrix); 84 | [rows cols] = ind2sub(size(PoissonCoefficientMatrix),indices); 85 | 86 | if ~periodicZ 87 | % indices2 = find(R(rows) == R(1,1) | R(rows) == R(1,end) | Z(rows) == Z(1,1) | Z(rows) == Z(end,1)); 88 | indices2 = find(R(rows) == R(1,1) | R(rows) == R(1,end) | Z(rows) == Z(1,1) | Z(rows) == Z(end,1) ... 89 | | R(cols) == R(1,1) | R(cols) == R(1,end) | Z(cols) == Z(1,1) | Z(cols) == Z(end,1)); 90 | else 91 | % indices2 = find(R(rows) == R(1,1) | R(rows) == R(1,end)); 92 | indices2 = find(R(rows) == R(1,1) | R(rows) == R(1,end) ... 93 | | R(cols) == R(1,1) | R(cols) == R(1,end)); 94 | end 95 | PoissonCoefficientMatrix(indices(indices2)) = 0; 96 | -------------------------------------------------------------------------------- /src/DNS_cylindrical_axisymmetric_finiteDifference/DNScylAxiFDapplyBoundaryConditions.m: -------------------------------------------------------------------------------- 1 | function [Gamma eta psi] = DNScylAxiFDapplyBoundaryConditions(Gamma, eta, psi, t, boundaryInformation) 2 | %NSCYLAXIFDAPPLYBOUNDARYCONDITIONS applies the boundary conditions. 3 | % [GAMMA ETA PSI] = NSCYLAXIFDAPPLYBOUNDARYCONDITIONS(GAMMA,ETA,PSI,T,BOUNDARYINFORMATION) 4 | % Applies the boundary conditions at time T using the boundary information 5 | % in the boundaryInformation structure BOUNDARYINFORMATION. GAMMA, ETA, and 6 | % PSI are the angular velocity, theta component of vorticity, and the 2D 7 | % streamfunction respectively. A boundaryInformation structure has five 8 | % fields: 9 | % 10 | % periodicZ : Whether the system is axially periodic (true) or not (false) 11 | % 12 | % rMinBoundary, rMaxBoundary, zMinBoundary, zMaxBoundary : structures that 13 | % describe the boundaries at the minimum r-value, maximum r-value, 14 | % minimum z-value, and maximum z-value respectively. Each has a mandatory 15 | % field 'Type' which tells what type of boundary it it. It must be 'wall' 16 | % for all boundaries except the minimum r boundary where it can be 'axis' 17 | % if it is the axis of rotation (its r-value had better be zero or funny 18 | % results will occur). If it is a 'wall', then the field 'GammaValues' 19 | % must be a function handle that takes a single argument, the time T, and 20 | % returns the Gamma values that are the wall is supposed to have at each 21 | % grid point on the wall at that time. 22 | % 23 | % References: 24 | % 1) JM Lopez and J Shen. An Efficient Spectral-Projection Method for 25 | % the Navier-Stokes Equations in Cylindrical Geometries - Part I - 26 | % Axisymmetric Cases. Journal of Computational Physics. 139, 308-326 27 | % (1998) 28 | % DOI: 10.1006/jcph.1997.5872 29 | % 30 | % 31 | % 32 | % Copyright 2012 Freja Nordsiek 33 | % 34 | % Licensed under the Apache License, Version 2.0 (the "License"); 35 | % you may not use this file except in compliance with the License. 36 | % You may obtain a copy of the License at 37 | % 38 | % http://www.apache.org/licenses/LICENSE-2.0 39 | % 40 | % Unless required by applicable law or agreed to in writing, software 41 | % distributed under the License is distributed on an "AS IS" BASIS, 42 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 43 | % See the License for the specific language governing permissions and 44 | % limitations under the License. 45 | 46 | % psi = 0 on the walls and axis, normal and tangential derivatives of psi 47 | % are zero on walls, eta = 0 on the axis, Gamma = 0 the axis, and 48 | % Gamma = r*v on walls where v is the azimuthal velocity of the wall at the 49 | % given point (Lopez and Shen 1998). 50 | 51 | % Do axial boundary conditions first, then radial. 52 | 53 | % If the system is not axially periodic, then the boundary conditions need 54 | % to be enforced on the ends. Otherwise, there is nothing that needs to be 55 | % done. 56 | 57 | if ~boundaryInformation.periodicZ 58 | 59 | % The boundary at the minimum z must be a wall. 60 | 61 | if ~strcmpi(boundaryInformation.zMinBoundary.Type,'wall') 62 | error('z-min boundary type not supported.'); 63 | end 64 | 65 | % Since the boundary is a wall, set psi equal to zero at it and the 66 | % next value of z in and set Gamma to what the GammaValues function 67 | % handle returns. 68 | 69 | Gamma(end,:) = boundaryInformation.zMinBoundary.GammaValues(t); 70 | psi((end-1):end,:) = 0; 71 | % psi(end,:) = 0; 72 | 73 | % The boundary at the maximum z must be a wall. 74 | 75 | if ~strcmpi(boundaryInformation.zMaxBoundary.Type,'wall') 76 | error('z-max boundary type not supported.'); 77 | end 78 | 79 | % Since the boundary is a wall, set psi equal to zero at it and the 80 | % next value of z in and set Gamma to what the GammaValues function 81 | % handle returns. 82 | 83 | Gamma(1,:) = boundaryInformation.zMaxBoundary.GammaValues(t); 84 | psi(1:2,:) = 0; 85 | % psi(1,:) = 0; 86 | 87 | end 88 | 89 | % The boundary at the minimum r can either be the axis or a wall. If it is 90 | % an axis; Gamma, eta, and psi are set to zero on it. If it is a wall, psi 91 | % is set to zero at it and the next r (makes the normal and tangential 92 | % derivatives of it zero) and Gamma is set to the values gotten from the 93 | % GammaValues function handle at time t. 94 | 95 | switch lower(boundaryInformation.rMinBoundary.Type) 96 | case 'axis' 97 | Gamma(:,1) = 0; 98 | eta(:,1) = 0; 99 | psi(:,1) = 0; 100 | case 'wall' 101 | Gamma(:,1) = boundaryInformation.rMinBoundary.GammaValues(t); 102 | psi(:,1:2) = 0; 103 | % psi(:,1) = 0; 104 | otherwise 105 | error('r-min boundary type not supported.'); 106 | end 107 | 108 | % The boundary at the maximum r must be a wall. 109 | 110 | if ~strcmpi(boundaryInformation.rMaxBoundary.Type,'wall') 111 | error('r-max boundary type not supported.'); 112 | end 113 | 114 | % Since the boundary is a wall, set psi equal to zero at it and the next 115 | % value of r in and set Gamma to what the GammaValues function handle 116 | % returns. 117 | 118 | Gamma(:,end) = boundaryInformation.rMaxBoundary.GammaValues(t); 119 | psi(:,(end-1):end) = 0; 120 | % psi(:,end) = 0; 121 | -------------------------------------------------------------------------------- /src/finite_differencers/dfdxFiniteDifferenceMatrix.m: -------------------------------------------------------------------------------- 1 | function coeffMatrix = dfdxFiniteDifferenceMatrix(f,h,dim) 2 | %DFDXFINITEDIFFERENCEMATRIX finds coeff matrix for the first finite difference on a uniform grid. 3 | % COEFFMATRIX = DFDXFINITEDIFFERENCEMATRIX(F, H, DIM) 4 | % Creates the coefficient matrix, COEFFMATRIX which is sparse, to take the 5 | % first centered finite difference of F on a uniform grid along direction 6 | % DIM (1 is row, 2 is column, and 3 is page) where H is the grid spacing. 7 | % Then, the finite difference is calculated by dF(:)=COEFFMATRIX*F(:). The 8 | % difference formula is, for a one dimensional F (extends to two and three 9 | % dimensions by just re-application of it to each row/col/page/whatever), 10 | % given by 11 | % 12 | % Df_i/Dx = (f_(i+1) - f_(i-1)) / 2*h 13 | % 14 | % 15 | % 16 | % Copyright 2012 Freja Nordsiek 17 | % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); 19 | % you may not use this file except in compliance with the License. 20 | % You may obtain a copy of the License at 21 | % 22 | % http://www.apache.org/licenses/LICENSE-2.0 23 | % 24 | % Unless required by applicable law or agreed to in writing, software 25 | % distributed under the License is distributed on an "AS IS" BASIS, 26 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | % See the License for the specific language governing permissions and 28 | % limitations under the License. 29 | 30 | % Get the size vector of f and pad any missing column or page sizes with 31 | % one. 32 | 33 | siz = size(f); 34 | siz((numel(siz)+1):3) = 1; 35 | 36 | % Three vectors will be used in constructing the coefficient matrix. rows 37 | % will hold the indices of the grid points that the difference is being 38 | % evaluated at, cols will hold the indices of the grid points in f that 39 | % will be used to evaluate the difference, and coeffs will hold the 40 | % coefficients applied tot eh grid points specified in cols to find the 41 | % differences at the grid points specified in rows. 42 | 43 | % The total number of entries will be the product fo the dimensions of f 44 | % after subtracting 2 from dimension dim (can't calculate difference at the 45 | % ends). So, we subtract 2 from the proper entry in siz, make rows, and add 46 | % 2 back. 47 | 48 | siz(dim) = siz(dim)-2; 49 | rows = zeros(prod(siz),1); 50 | siz(dim) = siz(dim)+2; 51 | 52 | % To pre-allocate cols and coeffs, rows can simply be copied into them. 53 | 54 | cols = rows; 55 | coeffs = rows; 56 | 57 | % There are some slight differences to how it needs to be handled for each 58 | % dimension type, so they are handled separately; but the basic algorithm 59 | % is the same. 60 | % 61 | % Each row, column, and page are iterated over except the end ones along 62 | % dimension dim. Then, as two entries are to be added in all three vectors, 63 | % we simplify things can calculate the index to which (1:2) must be added 64 | % to reach the proper entries in the vectors. This is simply the page index 65 | % minus the starting plus the column index minus the starting times the 66 | % number of pages we are looping over plus the row index minus the starting 67 | % times the number of pages we are looping over times the number of columns 68 | % we are looping over. Then, the two entries into rows are just the index 69 | % associated with (ii,jj,kk). The two entries in cols are just the indices 70 | % associated with (ii,jj,kk) but +/- 1 in direction dim. The coefficients 71 | % are simply +/- 1/(2*h). 72 | 73 | switch dim 74 | case 1 75 | for ii=2:(siz(1)-1) 76 | for jj=1:siz(2) 77 | for kk=1:siz(3) 78 | baseIndex = 2*((kk-1) + (jj-1)*siz(3) + (ii-2)*siz(3)*siz(2)); 79 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 80 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[1;-1],jj+[0;0],kk+[0;0]); 81 | coeffs(baseIndex + (1:2)) = [1; -1]*(1/(2*h)); 82 | end 83 | end 84 | end 85 | case 2 86 | for ii=1:siz(1) 87 | for jj=2:(siz(2)-1) 88 | for kk=1:siz(3) 89 | baseIndex = 2*((kk-1) + (jj-2)*siz(3) + (ii-1)*siz(3)*(siz(2)-2)); 90 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 91 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[1;-1],kk+[0;0]); 92 | coeffs(baseIndex + (1:2)) = [1; -1]*(1/(2*h)); 93 | end 94 | end 95 | end 96 | case 3 97 | for ii=1:siz(1) 98 | for jj=1:siz(2) 99 | for kk=2:(siz(3)-1) 100 | baseIndex = 2*((kk-2) + (jj-1)*(siz(3)-2) + (ii-1)*(siz(3)-2)*siz(2)); 101 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 102 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[0;0],kk+[1;-1]); 103 | coeffs(baseIndex + (1:2)) = [1; -1]*(1/(2*h)); 104 | end 105 | end 106 | end 107 | otherwise 108 | error('DIM can only be 1, 2, or 3.'); 109 | end 110 | 111 | % To make the sparse matrix a little faster to access, the entries will be 112 | % sorted by rows and then cols. The resulting sorted vectors are then fed 113 | % into the sparse command to make a sparse matrix with a number of rows and 114 | % columns equal to the total number of elements of f with values coeffs at 115 | % (rows,cols). 116 | 117 | junk = sortrows([rows,cols,coeffs]); 118 | 119 | coeffMatrix = sparse(junk(:,1),junk(:,2),junk(:,3),numel(f),numel(f)); 120 | -------------------------------------------------------------------------------- /src/DNS_cylindrical_axisymmetric_finiteDifference/private/DNScylAxiFDtimeDerivative.m: -------------------------------------------------------------------------------- 1 | function [Gamma_t eta_t] = DNScylAxiFDtimeDerivative(Gamma,eta,psi,nu,R,Z,periodicZ) 2 | %NSCYLAXIFDTIMEDERIVATIVE finds the time derivatives in the axisymmetric cylindrical NSE. 3 | % [GAMMA_t ETA_t] = NSCYLAXIFDTIMEDERIVATIVE(GAMMA,ETA,PSI,NU,R,Z,PERIODICZ) 4 | % Finds the time derivatives of GAMMA and ETA in axisymmetric cylindrical 5 | % Navier-Stokes equations using finite difference methods, but does not 6 | % apply the boundary conditions. GAMMA, ETA, and PSI are the angular 7 | % velocity, theta component of vorticity, and the 2D streamfunction 8 | % respectively at the grid points whose (z,r) coordinates are given by the 9 | % coordinate matrices R and Z (produced by meshgrid). NU is the viscosity 10 | % (note, this function works with the NSE in real units, not in 11 | % dimensionless form). PERIODICZ is a flag indicating whether the axial 12 | % boundary condition is periodic (true) or not (false). 13 | % 14 | % References: 15 | % 1) JM Lopez and J Shen. An Efficient Spectral-Projection Method for 16 | % the Navier-Stokes Equations in Cylindrical Geometries - Part I - 17 | % Axisymmetric Cases. Journal of Computational Physics. 139, 308-326 18 | % (1998) 19 | % 20 | % 21 | % 22 | % Copyright 2012 Freja Nordsiek 23 | % 24 | % Licensed under the Apache License, Version 2.0 (the "License"); 25 | % you may not use this file except in compliance with the License. 26 | % You may obtain a copy of the License at 27 | % 28 | % http://www.apache.org/licenses/LICENSE-2.0 29 | % 30 | % Unless required by applicable law or agreed to in writing, software 31 | % distributed under the License is distributed on an "AS IS" BASIS, 32 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 33 | % See the License for the specific language governing permissions and 34 | % limitations under the License. 35 | 36 | % Since the eta equation uses a lot of derivatives of eta/r, it is easier 37 | % and more efficient to just calculate it first instead of doing it each 38 | % time individually. 39 | 40 | Rinv = R.^-1; 41 | 42 | etaOverR = eta.*Rinv; 43 | 44 | % Do all the derivatives with respect to r that are needed making sure to 45 | % use the non-uniform grid finite difference functions. 46 | 47 | Gamma_r = dfdxFiniteDifferenceNonUniform(Gamma,R,2); 48 | Gamma_rr = d2fdx2FiniteDifferenceNonUniform(Gamma,R,2); 49 | psi_r = dfdxFiniteDifferenceNonUniform(psi,R,2); 50 | % psi_rr = d2fdx2FiniteDifferenceNonUniform(psi,R,2); 51 | etaOverR_r = dfdxFiniteDifferenceNonUniform(etaOverR,R,2); 52 | etaOverR_rr = d2fdx2FiniteDifferenceNonUniform(etaOverR,R,2); 53 | 54 | % How the axial derivatives are handled depends on whether we are doing 55 | % periodic boundary conditions or not. If it is periodic, then the periodic 56 | % uniform grid finite difference codes are used. Otherwise, the non-uniform 57 | % grid codes are used. 58 | 59 | if periodicZ 60 | dz = diff(Z(1:2,1)); 61 | Gamma_z = dfdxFiniteDifferencePeriodic(Gamma,dz,1); 62 | Gamma_zz = d2fdx2FiniteDifferencePeriodic(Gamma,dz,1); 63 | psi_z = dfdxFiniteDifferencePeriodic(psi,dz,1); 64 | % psi_zz = d2fdx2FiniteDifferencePeriodic(psi,dz,1); 65 | etaOverR_z = dfdxFiniteDifferencePeriodic(etaOverR,dz,1); 66 | etaOverR_zz = d2fdx2FiniteDifferencePeriodic(etaOverR,dz,1); 67 | else 68 | Gamma_z = dfdxFiniteDifferenceNonUniform(Gamma,Z,1); 69 | Gamma_zz = d2fdx2FiniteDifferenceNonUniform(Gamma,Z,1); 70 | psi_z = dfdxFiniteDifferenceNonUniform(psi,Z,1); 71 | % psi_zz = d2fdx2FiniteDifferenceNonUniform(psi,Z,1); 72 | etaOverR_z = dfdxFiniteDifferenceNonUniform(etaOverR,Z,1); 73 | etaOverR_zz = d2fdx2FiniteDifferenceNonUniform(etaOverR,Z,1); 74 | end 75 | 76 | % We want all the derivative matrices to be the same size as Gamma, eta, 77 | % and psi; so we have to zero pad in a column of zeros before and after for 78 | % all the r-derivative matrices since the finite difference codes only give 79 | % the derivatives for the interior r-values. 80 | 81 | pad = zeros(size(R,1),1); 82 | 83 | Gamma_r = [pad,Gamma_r,pad]; 84 | Gamma_rr = [pad,Gamma_rr,pad]; 85 | psi_r = [pad,psi_r,pad]; 86 | % psi_rr = [pad,psi_rr,pad]; 87 | etaOverR_r = [pad,etaOverR_r,pad]; 88 | etaOverR_rr = [pad,etaOverR_rr,pad]; 89 | 90 | % If we are not axially periodic, then we need to pad a row of zeros before 91 | % and after the z-derivative matrices (the finite difference codes only 92 | % give derivatives for interior z-values) and zero out the top and bottom 93 | % rows of the r-derivatives so as to not effect the boundary points. 94 | 95 | if ~periodicZ 96 | 97 | pad = zeros(1,size(Z,2)); 98 | Gamma_z = [pad;Gamma_z;pad]; 99 | Gamma_zz = [pad;Gamma_zz;pad]; 100 | psi_z = [pad;psi_z;pad]; 101 | % psi_zz = [pad;psi_zz;pad]; 102 | etaOverR_z = [pad;etaOverR_z;pad]; 103 | etaOverR_zz = [pad;etaOverR_zz;pad]; 104 | 105 | Gamma_r([1 end],:) = 0; 106 | Gamma_rr([1 end],:) = 0; 107 | psi_r([1 end],:) = 0; 108 | % psi_rr([1 end],:) = 0; 109 | etaOverR_r([1 end],:) = 0; 110 | etaOverR_rr([1 end],:) = 0; 111 | 112 | end 113 | 114 | % Calculate the time derivatives of Gamma and eta. Equations A.4 and A.5, 115 | % after writing out the terms, going back to non-normalized units (also 116 | % means 1/Re is replaced with nu), and a bit of simplifying leads to these 117 | % equations. 118 | 119 | Gamma_t = nu*(Gamma_rr + Gamma_zz) + ((psi_z - nu).*Gamma_r - psi_r.*Gamma_z).*Rinv; 120 | 121 | eta_t = nu*R.*(etaOverR_rr + etaOverR_zz) + (psi_z + nu).*etaOverR_r ... 122 | - psi_r.*etaOverR_z + 2*Gamma.*Gamma_z.*(Rinv.^3); 123 | -------------------------------------------------------------------------------- /src/finite_differencers/d2fdx2FiniteDifferenceMatrix.m: -------------------------------------------------------------------------------- 1 | function coeffMatrix = d2fdx2FiniteDifferenceMatrix(f,h,dim) 2 | %D2FDX2FINITEDIFFERENCEMATRIX finds coeff matrix for the second finite difference on a uniform grid. 3 | % COEFFMATRIX = D2FDX2FINITEDIFFERENCEMATRIX(F, H, DIM) 4 | % Creates the coefficient matrix, COEFFMATRIX which is sparse, to take the 5 | % second centered finite difference of F on a uniform grid along direction 6 | % DIM (1 is row, 2 is column, and 3 is page) where H is the grid spacing. 7 | % Then, the finite difference is calculated by dF(:)=COEFFMATRIX*F(:). The 8 | % difference formula is, for a one dimensional F (extends to two and three 9 | % dimensions by just re-application of it to each row/col/page/whatever), 10 | % given by 11 | % 12 | % Df_i/Dx = (f_(i+1) - 2*f_i + f_(i-1)) / h^2 13 | % 14 | % 15 | % 16 | % Copyright 2012 Freja Nordsiek 17 | % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); 19 | % you may not use this file except in compliance with the License. 20 | % You may obtain a copy of the License at 21 | % 22 | % http://www.apache.org/licenses/LICENSE-2.0 23 | % 24 | % Unless required by applicable law or agreed to in writing, software 25 | % distributed under the License is distributed on an "AS IS" BASIS, 26 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | % See the License for the specific language governing permissions and 28 | % limitations under the License. 29 | 30 | % Get the size vector of f and pad any missing column or page sizes with 31 | % one. 32 | 33 | siz = size(f); 34 | siz((numel(siz)+1):3) = 1; 35 | 36 | % Three vectors will be used in constructing the coefficient matrix. rows 37 | % will hold the indices of the grid points that the difference is being 38 | % evaluated at, cols will hold the indices of the grid points in f that 39 | % will be used to evaluate the difference, and coeffs will hold the 40 | % coefficients applied tot eh grid points specified in cols to find the 41 | % differences at the grid points specified in rows. 42 | 43 | % The total number of entries will be the product fo the dimensions of f 44 | % after subtracting 2 from dimension dim (can't calculate difference at the 45 | % ends). So, we subtract 2 from the proper entry in siz, make rows, and add 46 | % 2 back. 47 | 48 | siz(dim) = siz(dim)-2; 49 | rows = zeros(prod(siz),1); 50 | siz(dim) = siz(dim)+2; 51 | 52 | % To pre-allocate cols and coeffs, rows can simply be copied into them. 53 | 54 | cols = rows; 55 | coeffs = rows; 56 | 57 | % There are some slight differences to how it needs to be handled for each 58 | % dimension type, so they are handled separately; but the basic algorithm 59 | % is the same. 60 | % 61 | % Each row, column, and page are iterated over except the end ones along 62 | % dimension dim. Then, as three entries are to be added in all three vectors, 63 | % we simplify things can calculate the index to which (1:3) must be added 64 | % to reach the proper entries in the vectors. This is simply the page index 65 | % minus the starting plus the column index minus the starting times the 66 | % number of pages we are looping over plus the row index minus the starting 67 | % times the number of pages we are looping over times the number of columns 68 | % we are looping over. Then, the three entries into rows are just the index 69 | % associated with (ii,jj,kk). The three entries in cols are just the indices 70 | % associated with (ii,jj,kk) but +1,0,-1 in direction dim. The coefficients 71 | % are simply given by the difference formula 72 | 73 | switch dim 74 | case 1 75 | for ii=2:(siz(1)-1) 76 | for jj=1:siz(2) 77 | for kk=1:siz(3) 78 | baseIndex = 3*((kk-1) + (jj-1)*siz(3) + (ii-2)*siz(3)*siz(2)); 79 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 80 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[1;0;-1],jj+[0;0;0],kk+[0;0;0]); 81 | coeffs(baseIndex + (1:3)) = [1; -2; 1]*(1/h^2); 82 | end 83 | end 84 | end 85 | case 2 86 | for ii=1:siz(1) 87 | for jj=2:(siz(2)-1) 88 | for kk=1:siz(3) 89 | baseIndex = 3*((kk-1) + (jj-2)*siz(3) + (ii-1)*siz(3)*(siz(2)-2)); 90 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 91 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[1;0;-1],kk+[0;0;0]); 92 | coeffs(baseIndex + (1:3)) = [1; -2; 1]*(1/h^2); 93 | end 94 | end 95 | end 96 | case 3 97 | for ii=1:siz(1) 98 | for jj=1:siz(2) 99 | for kk=2:(siz(3)-1) 100 | baseIndex = 3*((kk-2) + (jj-1)*(siz(3)-2) + (ii-1)*(siz(3)-2)*siz(2)); 101 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 102 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[0;0;0],kk+[1;0;-1]); 103 | coeffs(baseIndex + (1:3)) = [1; -2; 1]*(1/h^2); 104 | end 105 | end 106 | end 107 | otherwise 108 | error('DIM can only be 1, 2, or 3.'); 109 | end 110 | 111 | % To make the sparse matrix a little faster to access, the entries will be 112 | % sorted by rows and then cols. The resulting sorted vectors are then fed 113 | % into the sparse command to make a sparse matrix with a number of rows and 114 | % columns equal to the total number of elements of f with values coeffs at 115 | % (rows,cols). 116 | 117 | junk = sortrows([rows,cols,coeffs]); 118 | 119 | coeffMatrix = sparse(junk(:,1),junk(:,2),junk(:,3),numel(f),numel(f)); 120 | -------------------------------------------------------------------------------- /src/finite_differencers/dfdxFiniteDifferenceNonUniformMatrix.m: -------------------------------------------------------------------------------- 1 | function coeffMatrix = dfdxFiniteDifferenceNonUniformMatrix(f,x,dim) 2 | %DFDXFINITEDIFFERENCENONUNIFORMMATRIX finds coeff matrix for the first finite difference on a non-uniform grid. 3 | % COEFFMATRIX = DFDXFINITEDIFFERENCENONUNIFORMMATRIX(F, X, DIM) 4 | % Creates the coefficient matrix, COEFFMATRIX which is sparse, to take the 5 | % first centered finite difference of F on a non-uniform grid along 6 | % direction DIM (1 is row, 2 is column, and 3 is page) where X is the 7 | % vector containing the grid point positions in that direction. 8 | % Then, the finite difference is calculated by dF(:)=COEFFMATRIX*F(:). The 9 | % difference formula is, for a one dimensional F (extends to two and three 10 | % dimensions by just re-application of it to each row/col/page/whatever), 11 | % given by 12 | % 13 | % Df_i/Dx = (f_(i+1) - f_(i-1)) / (x_(i+1) - x_(i-1)) 14 | % 15 | % 16 | % 17 | % Copyright 2012 Freja Nordsiek 18 | % 19 | % Licensed under the Apache License, Version 2.0 (the "License"); 20 | % you may not use this file except in compliance with the License. 21 | % You may obtain a copy of the License at 22 | % 23 | % http://www.apache.org/licenses/LICENSE-2.0 24 | % 25 | % Unless required by applicable law or agreed to in writing, software 26 | % distributed under the License is distributed on an "AS IS" BASIS, 27 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | % See the License for the specific language governing permissions and 29 | % limitations under the License. 30 | 31 | % Get the size vector of f and pad any missing column or page sizes with 32 | % one. 33 | 34 | siz = size(f); 35 | siz((numel(siz)+1):3) = 1; 36 | 37 | % Three vectors will be used in constructing the coefficient matrix. rows 38 | % will hold the indices of the grid points that the difference is being 39 | % evaluated at, cols will hold the indices of the grid points in f that 40 | % will be used to evaluate the difference, and coeffs will hold the 41 | % coefficients applied tot eh grid points specified in cols to find the 42 | % differences at the grid points specified in rows. 43 | 44 | % The total number of entries will be the product fo the dimensions of f 45 | % after subtracting 2 from dimension dim (can't calculate difference at the 46 | % ends). So, we subtract 2 from the proper entry in siz, make rows, and add 47 | % 2 back. 48 | 49 | siz(dim) = siz(dim)-2; 50 | rows = zeros(prod(siz),1); 51 | siz(dim) = siz(dim)+2; 52 | 53 | % To pre-allocate cols and coeffs, rows can simply be copied into them. 54 | 55 | cols = rows; 56 | coeffs = rows; 57 | 58 | % There are some slight differences to how it needs to be handled for each 59 | % dimension type, so they are handled separately; but the basic algorithm 60 | % is the same. 61 | % 62 | % Each row, column, and page are iterated over except the end ones along 63 | % dimension dim. Then, as two entries are to be added in all three vectors, 64 | % we simplify things can calculate the index to which (1:2) must be added 65 | % to reach the proper entries in the vectors. This is simply the page index 66 | % minus the starting plus the column index minus the starting times the 67 | % number of pages we are looping over plus the row index minus the starting 68 | % times the number of pages we are looping over times the number of columns 69 | % we are looping over. Then, the two entries into rows are just the index 70 | % associated with (ii,jj,kk). The two entries in cols are just the indices 71 | % associated with (ii,jj,kk) but +/-1 in direction dim. The coefficients 72 | % are simply given by the formula 73 | 74 | switch dim 75 | case 1 76 | for ii=2:(siz(1)-1) 77 | for jj=1:siz(2) 78 | for kk=1:siz(3) 79 | baseIndex = 2*((kk-1) + (jj-1)*siz(3) + (ii-2)*siz(3)*siz(2)); 80 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 81 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[1;-1],jj+[0;0],kk+[0;0]); 82 | coeffs(baseIndex + (1:2)) = [1;-1]/(x(ii+1)-x(ii-1)); 83 | end 84 | end 85 | end 86 | case 2 87 | for ii=1:siz(1) 88 | for jj=2:(siz(2)-1) 89 | for kk=1:siz(3) 90 | baseIndex = 2*((kk-1) + (jj-2)*siz(3) + (ii-1)*siz(3)*(siz(2)-2)); 91 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 92 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[1;-1],kk+[0;0]); 93 | coeffs(baseIndex + (1:2)) = [1;-1]/(x(jj+1)-x(jj-1)); 94 | end 95 | end 96 | end 97 | case 3 98 | for ii=1:siz(1) 99 | for jj=1:siz(2) 100 | for kk=2:(siz(3)-1) 101 | baseIndex = 2*((kk-2) + (jj-1)*(siz(3)-2) + (ii-1)*(siz(3)-2)*siz(2)); 102 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 103 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[0;0],kk+[1;-1]); 104 | coeffs(baseIndex + (1:2)) = [1;-1]/(x(kk+1)-x(kk-1)); 105 | end 106 | end 107 | end 108 | otherwise 109 | error('DIM can only be 1, 2, or 3.'); 110 | end 111 | 112 | % To make the sparse matrix a little faster to access, the entries will be 113 | % sorted by rows and then cols. The resulting sorted vectors are then fed 114 | % into the sparse command to make a sparse matrix with a number of rows and 115 | % columns equal to the total number of elements of f with values coeffs at 116 | % (rows,cols). 117 | 118 | junk = sortrows([rows,cols,coeffs]); 119 | 120 | coeffMatrix = sparse(junk(:,1),junk(:,2),junk(:,3),numel(f),numel(f)); 121 | -------------------------------------------------------------------------------- /src/finite_differencers/d2fdx2FiniteDifferenceNonUniformMatrix.m: -------------------------------------------------------------------------------- 1 | function coeffMatrix = d2fdx2FiniteDifferenceNonUniformMatrix(f,x,dim) 2 | %D2FDX2FINITEDIFFERENCENONUNIFORMMATRIX finds coeff matrix for the second finite difference on a non-uniform grid. 3 | % COEFFMATRIX = D2FDX2FINITEDIFFERENCENONUNIFORMMATRIX(F, X, DIM) 4 | % Creates the coefficient matrix, COEFFMATRIX which is sparse, to take the 5 | % second centered finite difference of F on a non-uniform grid along 6 | % direction DIM (1 is row, 2 is column, and 3 is page) where X is the 7 | % vector containing the grid point positions in that direction. 8 | % Then, the finite difference is calculated by dF(:)=COEFFMATRIX*F(:). The 9 | % difference formula is, for a one dimensional F (extends to two and three 10 | % dimensions by just re-application of it to each row/col/page/whatever), 11 | % given by 12 | % 13 | % D2f_i/Dx2 = [2/(x_(i+1) - x_(i-1))] * [(y_(i+1) - y_i)/(x_(i+1) - x_i) - (y_i - y_(i-1))/(x_i - x_(i-1))] 14 | % 15 | % 16 | % 17 | % Copyright 2012 Freja Nordsiek 18 | % 19 | % Licensed under the Apache License, Version 2.0 (the "License"); 20 | % you may not use this file except in compliance with the License. 21 | % You may obtain a copy of the License at 22 | % 23 | % http://www.apache.org/licenses/LICENSE-2.0 24 | % 25 | % Unless required by applicable law or agreed to in writing, software 26 | % distributed under the License is distributed on an "AS IS" BASIS, 27 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | % See the License for the specific language governing permissions and 29 | % limitations under the License. 30 | 31 | % Get the size vector of f and pad any missing column or page sizes with 32 | % one. 33 | 34 | siz = size(f); 35 | siz((numel(siz)+1):3) = 1; 36 | 37 | % Three vectors will be used in constructing the coefficient matrix. rows 38 | % will hold the indices of the grid points that the difference is being 39 | % evaluated at, cols will hold the indices of the grid points in f that 40 | % will be used to evaluate the difference, and coeffs will hold the 41 | % coefficients applied tot eh grid points specified in cols to find the 42 | % differences at the grid points specified in rows. 43 | 44 | % The total number of entries will be the product fo the dimensions of f 45 | % after subtracting 2 from dimension dim (can't calculate difference at the 46 | % ends). So, we subtract 2 from the proper entry in siz, make rows, and add 47 | % 2 back. 48 | 49 | siz(dim) = siz(dim)-2; 50 | rows = zeros(prod(siz),1); 51 | siz(dim) = siz(dim)+2; 52 | 53 | % To pre-allocate cols and coeffs, rows can simply be copied into them. 54 | 55 | cols = rows; 56 | coeffs = rows; 57 | 58 | % There are some slight differences to how it needs to be handled for each 59 | % dimension type, so they are handled separately; but the basic algorithm 60 | % is the same. 61 | % 62 | % Each row, column, and page are iterated over except the end ones along 63 | % dimension dim. Then, as thre entries are to be added in all three vectors, 64 | % we simplify things can calculate the index to which (1:3) must be added 65 | % to reach the proper entries in the vectors. This is simply the page index 66 | % minus the starting plus the column index minus the starting times the 67 | % number of pages we are looping over plus the row index minus the starting 68 | % times the number of pages we are looping over times the number of columns 69 | % we are looping over. Then, the three entries into rows are just the index 70 | % associated with (ii,jj,kk). The three entries in cols are just the indices 71 | % associated with (ii,jj,kk) but +1,0,-1 in direction dim. The coefficients 72 | % are simply given by the formula 73 | 74 | switch dim 75 | case 1 76 | for ii=2:(siz(1)-1) 77 | for jj=1:siz(2) 78 | for kk=1:siz(3) 79 | baseIndex = 3*((kk-1) + (jj-1)*siz(3) + (ii-2)*siz(3)*siz(2)); 80 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 81 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[1;0;-1],jj+[0;0;0],kk+[0;0;0]); 82 | coeffs(baseIndex + (1:3)) = 2*([1 -1 0]/(x(ii+1)-x(ii)) + [0 -1 1]/(x(ii)-x(ii-1)))/(x(ii+1)-x(ii-1)); 83 | end 84 | end 85 | end 86 | case 2 87 | for ii=1:siz(1) 88 | for jj=2:(siz(2)-1) 89 | for kk=1:siz(3) 90 | baseIndex = 3*((kk-1) + (jj-2)*siz(3) + (ii-1)*siz(3)*(siz(2)-2)); 91 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 92 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[1;0;-1],kk+[0;0;0]); 93 | coeffs(baseIndex + (1:3)) = 2*([1 -1 0]/(x(jj+1)-x(jj)) + [0 -1 1]/(x(jj)-x(jj-1)))/(x(jj+1)-x(jj-1)); 94 | end 95 | end 96 | end 97 | case 3 98 | for ii=1:siz(1) 99 | for jj=1:siz(2) 100 | for kk=2:(siz(3)-1) 101 | baseIndex = 3*((kk-2) + (jj-1)*(siz(3)-2) + (ii-1)*(siz(3)-2)*siz(2)); 102 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 103 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[0;0;0],kk+[1;0;-1]); 104 | coeffs(baseIndex + (1:3)) = 2*([1 -1 0]/(x(kk+1)-x(kk)) + [0 -1 1]/(x(kk)-x(kk-1)))/(x(kk+1)-x(kk-1)); 105 | end 106 | end 107 | end 108 | otherwise 109 | error('DIM can only be 1, 2, or 3.'); 110 | end 111 | 112 | % To make the sparse matrix a little faster to access, the entries will be 113 | % sorted by rows and then cols. The resulting sorted vectors are then fed 114 | % into the sparse command to make a sparse matrix with a number of rows and 115 | % columns equal to the total number of elements of f with values coeffs at 116 | % (rows,cols). 117 | 118 | junk = sortrows([rows,cols,coeffs]); 119 | 120 | coeffMatrix = sparse(junk(:,1),junk(:,2),junk(:,3),numel(f),numel(f)); 121 | -------------------------------------------------------------------------------- /src/finite_differencers/dfdxFiniteDifferencePeriodicMatrix.m: -------------------------------------------------------------------------------- 1 | function coeffMatrix = dfdxFiniteDifferencePeriodicMatrix(f,h,dim) 2 | %DFDXFINITEDIFFERENCEPERIODICMATRIX finds the coeff matrix for the first finite difference on a periodic uniform grid. 3 | % COEFFMATRIX = DFDXFINITEDIFFERENCEPERIODICMATRIX(F, H, DIM) 4 | % Creates the coefficient matrix, COEFFMATRIX which is sparse, to take the 5 | % first centered finite difference of F on a periodic uniform grid along 6 | % direction DIM (1 is row, 2 is column, and 3 is page) where H is the grid 7 | % spacing. Then, the finite difference is calculated by 8 | % dF(:)=COEFFMATRIX*F(:). The difference formula is, for a one dimensional 9 | % F (extends to two and three dimensions by just re-application of it to 10 | % each row/col/page/whatever), given by 11 | % 12 | % Df_i/Dx = (f_(i+1) - f_(i-1)) / 2*h 13 | % 14 | % 15 | % 16 | % Copyright 2012 Freja Nordsiek 17 | % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); 19 | % you may not use this file except in compliance with the License. 20 | % You may obtain a copy of the License at 21 | % 22 | % http://www.apache.org/licenses/LICENSE-2.0 23 | % 24 | % Unless required by applicable law or agreed to in writing, software 25 | % distributed under the License is distributed on an "AS IS" BASIS, 26 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | % See the License for the specific language governing permissions and 28 | % limitations under the License. 29 | 30 | % Get the size vector of f and pad any missing column or page sizes with 31 | % one. 32 | 33 | siz = size(f); 34 | siz((numel(siz)+1):3) = 1; 35 | 36 | % Three vectors will be used in constructing the coefficient matrix. rows 37 | % will hold the indices of the grid points that the difference is being 38 | % evaluated at, cols will hold the indices of the grid points in f that 39 | % will be used to evaluate the difference, and coeffs will hold the 40 | % coefficients applied tot eh grid points specified in cols to find the 41 | % differences at the grid points specified in rows. 42 | 43 | % The total number of entries will be the product fo the dimensions of f. 44 | 45 | rows = zeros(prod(siz),1); 46 | cols = rows; 47 | coeffs = rows; 48 | 49 | % There are some slight differences to how it needs to be handled for each 50 | % dimension type, so they are handled separately; but the basic algorithm 51 | % is the same. 52 | % 53 | % Each row, column, and page are iterated over except the end ones along 54 | % dimension dim. Then, as two entries are to be added in all three vectors, 55 | % we simplify things can calculate the index to which (1:2) must be added 56 | % to reach the proper entries in the vectors. This is simply the page index 57 | % minus the starting plus the column index minus the starting times the 58 | % number of pages we are looping over plus the row index minus the starting 59 | % times the number of pages we are looping over times the number of columns 60 | % we are looping over. Then, the two entries into rows are just the index 61 | % associated with (ii,jj,kk). The two entries in cols are just the indices 62 | % associated with (ii,jj,kk) but +/- 1 in direction dim. The coefficients 63 | % are simply +/- 1/(2*h). The two boundaries and the interior are then 64 | % handled separately. 65 | 66 | switch dim 67 | case 1 68 | for ii=1:siz(1) 69 | for jj=1:siz(2) 70 | for kk=1:siz(3) 71 | baseIndex = 2*((kk-1) + (jj-1)*siz(3) + (ii-1)*siz(3)*siz(2)); 72 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 73 | switch ii 74 | case 1 75 | cols(baseIndex + (1:2)) = sub2ind(siz,[2;siz(1)],jj+[0;0],kk+[0;0]); 76 | case siz(1) 77 | cols(baseIndex + (1:2)) = sub2ind(siz,[1;siz(1)-1],jj+[0;0],kk+[0;0]); 78 | otherwise 79 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[1;-1],jj+[0;0],kk+[0;0]); 80 | end 81 | coeffs(baseIndex + (1:2)) = [1; -1]/(2*h); 82 | end 83 | end 84 | end 85 | case 2 86 | for ii=1:siz(1) 87 | for jj=1:siz(2) 88 | for kk=1:siz(3) 89 | baseIndex = 2*((kk-1) + (jj-1)*siz(3) + (ii-1)*siz(3)*siz(2)); 90 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 91 | switch jj 92 | case 1 93 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],[2;siz(2)],kk+[0;0]); 94 | case siz(2) 95 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],[1;siz(2)-1],kk+[0;0]); 96 | otherwise 97 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[1;-1],kk+[0;0]); 98 | end 99 | coeffs(baseIndex + (1:2)) = [1; -1]/(2*h); 100 | end 101 | end 102 | end 103 | case 3 104 | for ii=1:siz(1) 105 | for jj=1:siz(2) 106 | for kk=1:siz(3) 107 | baseIndex = 2*((kk-1) + (jj-1)*siz(3) + (ii-1)*siz(3)*siz(2)); 108 | rows(baseIndex + (1:2)) = sub2ind(siz,ii,jj,kk)+[0;0]; 109 | switch kk 110 | case 1 111 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[0;0],[2;siz(3)]); 112 | case siz(3) 113 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[0;0],[1;siz(3)-1]); 114 | otherwise 115 | cols(baseIndex + (1:2)) = sub2ind(siz,ii+[0;0],jj+[0;0],kk+[1;-1]); 116 | end 117 | coeffs(baseIndex + (1:2)) = [1; -1]/(2*h); 118 | end 119 | end 120 | end 121 | otherwise 122 | error('DIM can only be 1, 2, or 3.'); 123 | end 124 | 125 | % To make the sparse matrix a little faster to access, the entries will be 126 | % sorted by rows and then cols. The resulting sorted vectors are then fed 127 | % into the sparse command to make a sparse matrix with a number of rows and 128 | % columns equal to the total number of elements of f with values coeffs at 129 | % (rows,cols). 130 | 131 | junk = sortrows([rows,cols,coeffs]); 132 | 133 | coeffMatrix = sparse(junk(:,1),junk(:,2),junk(:,3),numel(f),numel(f)); 134 | -------------------------------------------------------------------------------- /src/finite_differencers/d2fdx2FiniteDifferencePeriodicMatrix.m: -------------------------------------------------------------------------------- 1 | function coeffMatrix = d2fdx2FiniteDifferencePeriodicMatrix(f,h,dim) 2 | %D2FDX2FINITEDIFFERENCEPERIODICMATRIX finds the coeff matrix for the second finite difference on a periodic uniform grid. 3 | % COEFFMATRIX = D2FDX2FINITEDIFFERENCEPERIODICMATRIX(F, H, DIM) 4 | % Creates the coefficient matrix, COEFFMATRIX which is sparse, to take the 5 | % second centered finite difference of F on a periodic uniform grid along 6 | % direction DIM (1 is row, 2 is column, and 3 is page) where H is the grid 7 | % spacing. Then, the finite difference is calculated by 8 | % dF(:)=COEFFMATRIX*F(:). The difference formula is, for a one dimensional 9 | % F (extends to two and three dimensions by just re-application of it to 10 | % each row/col/page/whatever), given by 11 | % 12 | % Df_i/Dx = (f_(i+1) - 2*f_i + f_(i-1)) / h^2 13 | % 14 | % 15 | % 16 | % Copyright 2012 Freja Nordsiek 17 | % 18 | % Licensed under the Apache License, Version 2.0 (the "License"); 19 | % you may not use this file except in compliance with the License. 20 | % You may obtain a copy of the License at 21 | % 22 | % http://www.apache.org/licenses/LICENSE-2.0 23 | % 24 | % Unless required by applicable law or agreed to in writing, software 25 | % distributed under the License is distributed on an "AS IS" BASIS, 26 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | % See the License for the specific language governing permissions and 28 | % limitations under the License. 29 | 30 | % Get the size vector of f and pad any missing column or page sizes with 31 | % one. 32 | 33 | siz = size(f); 34 | siz((numel(siz)+1):3) = 1; 35 | 36 | % Three vectors will be used in constructing the coefficient matrix. rows 37 | % will hold the indices of the grid points that the difference is being 38 | % evaluated at, cols will hold the indices of the grid points in f that 39 | % will be used to evaluate the difference, and coeffs will hold the 40 | % coefficients applied tot eh grid points specified in cols to find the 41 | % differences at the grid points specified in rows. 42 | 43 | % The total number of entries will be the product fo the dimensions of f. 44 | 45 | rows = zeros(prod(siz),1); 46 | cols = rows; 47 | coeffs = rows; 48 | 49 | % There are some slight differences to how it needs to be handled for each 50 | % dimension type, so they are handled separately; but the basic algorithm 51 | % is the same. 52 | % 53 | % Each row, column, and page are iterated over except the end ones along 54 | % dimension dim. Then, as three entries are to be added in all three vectors, 55 | % we simplify things can calculate the index to which (1:23) must be added 56 | % to reach the proper entries in the vectors. This is simply the page index 57 | % minus the starting plus the column index minus the starting times the 58 | % number of pages we are looping over plus the row index minus the starting 59 | % times the number of pages we are looping over times the number of columns 60 | % we are looping over. Then, the three entries into rows are just the index 61 | % associated with (ii,jj,kk). The three entries in cols are just the indices 62 | % associated with (ii,jj,kk) but +1,0,-1 in direction dim. The coefficients 63 | % are simply given by the formula. The two boundaries and the interior are then 64 | % handled separately. 65 | 66 | switch dim 67 | case 1 68 | for ii=1:siz(1) 69 | for jj=1:siz(2) 70 | for kk=1:siz(3) 71 | baseIndex = 3*((kk-1) + (jj-1)*siz(3) + (ii-1)*siz(3)*siz(2)); 72 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 73 | switch ii 74 | case 1 75 | cols(baseIndex + (1:3)) = sub2ind(siz,[2;1;siz(1)],jj+[0;0;0],kk+[0;0;0]); 76 | case siz(1) 77 | cols(baseIndex + (1:3)) = sub2ind(siz,[1;siz(1);siz(1)-1],jj+[0;0;0],kk+[0;0;0]); 78 | otherwise 79 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[1;0;-1],jj+[0;0;0],kk+[0;0;0]); 80 | end 81 | coeffs(baseIndex + (1:3)) = [1; -2; 1]/(h^2); 82 | end 83 | end 84 | end 85 | case 2 86 | for ii=1:siz(1) 87 | for jj=1:siz(2) 88 | for kk=1:siz(3) 89 | baseIndex = 3*((kk-1) + (jj-1)*siz(3) + (ii-1)*siz(3)*siz(2)); 90 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 91 | switch jj 92 | case 1 93 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],[2;1;siz(2)],kk+[0;0;0]); 94 | case siz(2) 95 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],[1;siz(2);siz(2)-1],kk+[0;0;0]); 96 | otherwise 97 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[1;0;-1],kk+[0;0;0]); 98 | end 99 | coeffs(baseIndex + (1:3)) = [1; -2; 1]/(h^2); 100 | end 101 | end 102 | end 103 | case 3 104 | for ii=1:siz(1) 105 | for jj=1:siz(2) 106 | for kk=1:siz(3) 107 | baseIndex = 3*((kk-1) + (jj-1)*siz(3) + (ii-1)*siz(3)*siz(2)); 108 | rows(baseIndex + (1:3)) = sub2ind(siz,ii,jj,kk)+[0;0;0]; 109 | switch kk 110 | case 1 111 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[0;0;0],[2;1;siz(3)]); 112 | case siz(3) 113 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[0;0;0],[1;siz(3);siz(3)-1]); 114 | otherwise 115 | cols(baseIndex + (1:3)) = sub2ind(siz,ii+[0;0;0],jj+[0;0;0],kk+[1;0;-1]); 116 | end 117 | coeffs(baseIndex + (1:3)) = [1; -2; 1]/(h^2); 118 | end 119 | end 120 | end 121 | otherwise 122 | error('DIM can only be 1, 2, or 3.'); 123 | end 124 | 125 | % To make the sparse matrix a little faster to access, the entries will be 126 | % sorted by rows and then cols. The resulting sorted vectors are then fed 127 | % into the sparse command to make a sparse matrix with a number of rows and 128 | % columns equal to the total number of elements of f with values coeffs at 129 | % (rows,cols). 130 | 131 | junk = sortrows([rows,cols,coeffs]); 132 | 133 | coeffMatrix = sparse(junk(:,1),junk(:,2),junk(:,3),numel(f),numel(f)); 134 | -------------------------------------------------------------------------------- /src/DNS_cylindrical_axisymmetric_finiteDifference/private/DNScylAxiFDdoTimeStep.m: -------------------------------------------------------------------------------- 1 | function [Gamma eta psi] = DNScylAxiFDdoTimeStep(Gamma,eta,psi,t,dt,nu,R,Z,poissonEquation,boundaryInformation) 2 | %NSCYLAXIFDDOTIMESTEP does one time step in the axisymmetric cylindrical NSE. 3 | % [GAMMA ETA PSI] = NSCYLAXIFDDOTIMESTEP(GAMMA,ETA,PSI,T,DT,NU,R,Z,POISSONEQUATION,BOUNDARYINFORMATION) 4 | % Does one time step of time from time T to time T + DT in axisymmetric 5 | % cylindrical Navier-Stokes equations using finite difference methods 6 | % including applying the boundary conditions using the second-order 7 | % predictor-corrector scheme lined out in Appendix A (Lopez and Shen 1998). 8 | % GAMMA, ETA, and PSI are the angular velocity, theta component of 9 | % vorticity, and the 2D streamfunction respectively at the grid points 10 | % whose (z,r) coordinates are given by the coordinate matrices R and Z 11 | % (produced by meshgrid). NU is the viscosity (note, this function works 12 | % with the NSE in real units, not in dimensionless form). 13 | % POISSONEQUATION is a structure containing stuff for solving the poisson 14 | % equation in equation A.6 (Lopez and Shen 1998). It contains the 15 | % PoissonCoefficientMatrix which solves 16 | % PSI(:) = PoissonCoefficientMatrix * (R(:).*ETA(:)) along with other 17 | % fields for solving the equation by methods other than doing a 18 | % straightforward and slow and singular linear solution with mldivide. 19 | % BOUNDARYINFORMATION is a boundaryInformation structure containing fields 20 | % describing the boundary conditions. 21 | % 22 | % References: 23 | % 1) JM Lopez and J Shen. An Efficient Spectral-Projection Method for 24 | % the Navier-Stokes Equations in Cylindrical Geometries - Part I - 25 | % Axisymmetric Cases. Journal of Computational Physics. 139, 308-326 26 | % (1998) 27 | % 28 | % 29 | % 30 | % Copyright 2012 Freja Nordsiek 31 | % 32 | % Licensed under the Apache License, Version 2.0 (the "License"); 33 | % you may not use this file except in compliance with the License. 34 | % You may obtain a copy of the License at 35 | % 36 | % http://www.apache.org/licenses/LICENSE-2.0 37 | % 38 | % Unless required by applicable law or agreed to in writing, software 39 | % distributed under the License is distributed on an "AS IS" BASIS, 40 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 41 | % See the License for the specific language governing permissions and 42 | % limitations under the License. 43 | 44 | 45 | % Doing step 1 in Appendix A to find Gamma_star and eta_star, which are 46 | % Gamma and eta advanced in time by dt/2 in an Euler method fashion. 47 | 48 | [Gamma_t eta_t] = DNScylAxiFDtimeDerivative(Gamma,eta,psi, ... 49 | nu,R,Z,boundaryInformation.periodicZ); 50 | 51 | Gamma_star = Gamma + (0.5*dt)*Gamma_t; 52 | eta_star = eta + (0.5*dt)*eta_t; 53 | 54 | % Find psi_star (step 2 in Appendix A) given the values of eta_star and the 55 | % information in poissonEquation describing equation A.6. There are 56 | % multiple ways the equation can be solved and many are present here with 57 | % all but one commented out. The first method is to just use MATLAB's built 58 | % in linear equation solver with the original coefficient matrix but this 59 | % is problematic since it is singular. The second method is to do a matrix 60 | % multiplication with the pseudo inverse of the original coefficient matrix 61 | % which avoids the issue of being singular but this is slow. The other 62 | % methods work solely with the interior points so psi_star must first be 63 | % initialized to zero. The third and fourth methods are just the first and 64 | % second methods but for the interior points and thus avoids singular 65 | % behavior and are a lot faster. The fifth method uses the conjugate 66 | % gradients iterative method using the incomplete LU factorization as 67 | % preconditioners. 68 | 69 | % psi_star = reshape(poissonEquation.CoefficientMatrix\(R(:).*eta_star(:)),size(Gamma)); 70 | % psi_star = reshape(poissonEquation.invCoefficientMatrix*(R(:).*eta_star(:)),size(Gamma)); 71 | 72 | psi_star = zeros(size(Gamma)); 73 | 74 | % psi_star(poissonEquation.interiorPoints) = poissonEquation.InteriorCoefficientMatrix ... 75 | % \ (R(poissonEquation.interiorPoints).*eta_star(poissonEquation.interiorPoints)); 76 | 77 | psi_star(poissonEquation.interiorPoints) = full(poissonEquation.invInteriorCoefficientMatrix ... 78 | * (R(poissonEquation.interiorPoints).*eta_star(poissonEquation.interiorPoints))); 79 | 80 | % [psi_star(poissonEquation.interiorPoints) flag relres iter resvec] = ... 81 | % cgs(poissonEquation.InteriorCoefficientMatrix, ... 82 | % (R(poissonEquation.interiorPoints).*eta_star(poissonEquation.interiorPoints)), ... 83 | % 1e-16,100, ... 84 | % poissonEquation.InteriorL,poissonEquation.InteriorU, ... 85 | % psi(poissonEquation.interiorPoints)); 86 | 87 | % Apply the boundary conditions (step 3). 88 | 89 | [Gamma_star eta_star psi_star] = DNScylAxiFDapplyBoundaryConditions(Gamma_star, ... 90 | eta_star, psi_star, t, boundaryInformation); 91 | 92 | % Doing step 4 in Appendix A which is to advance Gamma and eta by dt using 93 | % the derivatives gotten using star'ed fields. 94 | 95 | [Gamma_t eta_t] = DNScylAxiFDtimeDerivative(Gamma_star,eta_star,psi_star, ... 96 | nu,R,Z,boundaryInformation.periodicZ); 97 | 98 | Gamma = Gamma + dt*Gamma_t; 99 | eta = eta + dt*eta_t; 100 | 101 | % Find psi_star (step 2 in Appendix A) given the values of eta_star and the 102 | % information in poissonEquation describing equation A.6. There are 103 | % multiple ways the equation can be solved and many are present here with 104 | % all but one commented out. The first method is to just use MATLAB's built 105 | % in linear equation solver with the original coefficient matrix but this 106 | % is problematic since it is singular. The second method is to do a matrix 107 | % multiplication with the pseudo inverse of the original coefficient matrix 108 | % which avoids the issue of being singular but this is slow. The other 109 | % methods work solely with the interior points so psi_star must first be 110 | % initialized to zero. The third and fourth methods are just the first and 111 | % second methods but for the interior points and thus avoids singular 112 | % behavior and are a lot faster. The fifth method uses the conjugate 113 | % gradients iterative method using the incomplete LU factorization as 114 | % preconditioners. 115 | 116 | % psi = reshape(poissonEquation.CoefficientMatrix\(R(:).*eta(:)),size(Gamma)); 117 | % psi = reshape(poissonEquation.invCoefficientMatrix*(R(:).*eta(:)),size(Gamma)); 118 | 119 | psi = zeros(size(Gamma)); 120 | 121 | % psi(poissonEquation.interiorPoints) = poissonEquation.InteriorCoefficientMatrix ... 122 | % \ (R(poissonEquation.interiorPoints).*eta(poissonEquation.interiorPoints)); 123 | 124 | psi(poissonEquation.interiorPoints) = full(poissonEquation.invInteriorCoefficientMatrix ... 125 | * (R(poissonEquation.interiorPoints).*eta(poissonEquation.interiorPoints))); 126 | 127 | % [psi(poissonEquation.interiorPoints) flag relres iter resvec] = ... 128 | % cgs(poissonEquation.InteriorCoefficientMatrix, ... 129 | % (R(poissonEquation.interiorPoints).*eta(poissonEquation.interiorPoints)), ... 130 | % 1e-16,100, ... 131 | % poissonEquation.InteriorL,poissonEquation.InteriorU, ... 132 | % psi_star(poissonEquation.interiorPoints)); 133 | 134 | % Apply the boundary conditions (step 6). 135 | 136 | [Gamma eta psi] = DNScylAxiFDapplyBoundaryConditions(Gamma, ... 137 | eta, psi, t, boundaryInformation); 138 | -------------------------------------------------------------------------------- /src/DNS_cylindrical_axisymmetric_finiteDifference/DNScylAxiFDsimulation.m: -------------------------------------------------------------------------------- 1 | function [Gammas etas psis ts] = DNScylAxiFDsimulation(R,Z,parameters,initialConditions,boundaryInformation) 2 | %NSCYLAXIFDSIMULATION does a complete simulation of the axisymmetric cylindrical NSE. 3 | % [GAMMAS ETAS PSIS TS] = NSCYLAXIFDSIMULATION(R,Z,PARAMETERS,INITIALCONDITIONS,BOUNDARYINFORMATION) 4 | % Does a complete simulation of the axisymmetric cylindrical NSE in real 5 | % units as opposed to dimensionless units. The (z,r) grid is specified by 6 | % the coordinate matrices R and Z (produced by meshgrid). The r-mesh can be 7 | % non-uniformly spaced. The z-mesh can either be non-uniformly spaced or be 8 | % periodic uniformly spaced. The fields Gamma, eta, and psi (angular 9 | % velocity, theta component of vorticity, and the 2D streamfunction 10 | % respectively) at each grid point over time are found using the 11 | % second-order predictor-corrector scheme lined out in Appendix A (Lopez 12 | % and Shen 1998). INITIALCONDITIONS is a structure holding the initial 13 | % values of Gamma, eta, and psi in fields 'Gamma', 'eta', and 'psi' 14 | % respectively. PARAMETERS is a structure holding the simulation parameters 15 | % such as the number of time steps to simulate 'NumberTimeSteps', the time 16 | % between each step 'dt', how often in steps should the fields be saved 17 | % 'KeepEveryNSteps', and the kinematic viscosity 'nu'. BOUNDARYINFORMATION 18 | % is a boundaryInformation structure that contains the boundary conditions 19 | % and whose fields are described after this paragraph. The fields at the 20 | % times steps that they are saved at (includes the initial and final 21 | % fields) are returned in GAMMAS, ETAS, and PSIS with each page of the 3D 22 | % matrices being a different time. The times of the saved fields are stored 23 | % in the vector TS. Now for the fields of a boundaryInformation structure. 24 | % 25 | % periodicZ : Whether the system is axially periodic (true) or not (false) 26 | % 27 | % rMinBoundary, rMaxBoundary, zMinBoundary, zMaxBoundary : structures that 28 | % describe the boundaries at the minimum r-value, maximum r-value, 29 | % minimum z-value, and maximum z-value respectively. Each has a mandatory 30 | % field 'Type' which tells what type of boundary it it. It must be 'wall' 31 | % for all boundaries except the minimum r boundary where it can be 'axis' 32 | % if it is the axis of rotation (its r-value had better be zero or funny 33 | % results will occur). If it is a 'wall', then the field 'GammaValues' 34 | % must be a function handle that takes a single argument, the time T, and 35 | % returns the Gamma values that are the wall is supposed to have at each 36 | % grid point on the wall at that time. 37 | % 38 | % 39 | % 40 | % References: 41 | % 1) JM Lopez and J Shen. An Efficient Spectral-Projection Method for 42 | % the Navier-Stokes Equations in Cylindrical Geometries - Part I - 43 | % Axisymmetric Cases. Journal of Computational Physics. 139, 308-326 44 | % (1998) 45 | % DOI: 10.1006/jcph.1997.5872 46 | % 47 | % 48 | % 49 | % Copyright 2012 Freja Nordsiek 50 | % 51 | % Licensed under the Apache License, Version 2.0 (the "License"); 52 | % you may not use this file except in compliance with the License. 53 | % You may obtain a copy of the License at 54 | % 55 | % http://www.apache.org/licenses/LICENSE-2.0 56 | % 57 | % Unless required by applicable law or agreed to in writing, software 58 | % distributed under the License is distributed on an "AS IS" BASIS, 59 | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 60 | % See the License for the specific language governing permissions and 61 | % limitations under the License. 62 | 63 | warningState = warning('query','all'); 64 | warning('off','all'); 65 | 66 | % Apply the boundary conditions to the initial conditions in case they 67 | % presently violate them. 68 | 69 | [initialConditions.Gamma initialConditions.eta initialConditions.psi] = ... 70 | DNScylAxiFDapplyBoundaryConditions(initialConditions.Gamma, ... 71 | initialConditions.eta,initialConditions.psi,0,boundaryInformation); 72 | 73 | % Make a matrix indicating which points are interior (true) and boundary 74 | % (false). So, starting with a true matrix, the first and last r-values are 75 | % set to false and if we are not axially periodic, the first and last 76 | % z-value points are set to false. 77 | 78 | interiorPoints = true(size(R)); 79 | interiorPoints(:,[1 end]) = false; 80 | if ~boundaryInformation.periodicZ 81 | interiorPoints([1 end],:) = false; 82 | end 83 | 84 | % For the poisson equation in A.6 in the time evolution, we need a 85 | % structure to hold various needed pieces of information. First, we should 86 | % grab the interior points. Then, we need to get the CoefficientMatrix that 87 | % gives CoefficientMatrix * psi(:) = R(:).*eta(:). Then, various things can 88 | % be calculated from it to make it easier to solve that equation (the exact 89 | % method will be decided in DNScylAxiFDdoTimeStep.m). The inverse will be 90 | % gotten with the pseudoinverse (can't do normal inverse because it is 91 | % singular). Then, the coefficient matrix will all rows and columns not in 92 | % the interior (they are all empty rows and columns respectively) are 93 | % stripped out producing a new coefficient matrix solely for the interior 94 | % points. Then the matrix inverse and the incomplete LU factorization are 95 | % computed for the interior matrix. 96 | 97 | poissonEquation.interiorPoints = interiorPoints(:); 98 | poissonEquation.CoefficientMatrix = DNScylAxiFDmakePoissonCoefficientMatrix(R,Z,boundaryInformation.periodicZ); 99 | % poissonEquation.invCoefficientMatrix = pinv(full(poissonEquation.CoefficientMatrix)); 100 | poissonEquation.InteriorCoefficientMatrix = poissonEquation.CoefficientMatrix(interiorPoints,interiorPoints); 101 | poissonEquation.invInteriorCoefficientMatrix = inv(poissonEquation.InteriorCoefficientMatrix); 102 | % [poissonEquation.InteriorL poissonEquation.InteriorU] = luinc(poissonEquation.InteriorCoefficientMatrix,0); 103 | 104 | % Make a vector to hold the times of the returned Gamma, eta, and psi 105 | % fields. There will be an entry for the initial conditions, the end 106 | % fields, and one every parameters.KeepEverNSteps. 107 | 108 | ts = zeros(1,2 + floor(parameters.NumberTimeSteps/parameters.KeepEveryNSteps)); 109 | 110 | % Initialize Gammas, etas, and psis to hold all the Gamma, eta, and psi 111 | % fields that will be saved (same number of rows and columns as R and one 112 | % page for each one to be saved). 113 | 114 | Gammas = zeros([size(R),numel(ts)]); 115 | etas = Gammas; 116 | psis = Gammas; 117 | 118 | % Grab the initial conditions. 119 | 120 | Gamma = initialConditions.Gamma; 121 | eta = initialConditions.eta; 122 | psi = initialConditions.psi; 123 | 124 | % Put the initial conditions as the first entries of Gammas, etas, and 125 | % psis. 126 | 127 | Gammas(:,:,1) = Gamma; 128 | etas(:,:,1) = eta; 129 | psis(:,:,1) = psi; 130 | 131 | % Do each time step. 132 | 133 | for ii=1:parameters.NumberTimeSteps 134 | 135 | % Calculate the time at the beginning of the step. 136 | 137 | t = (ii-1)*parameters.dt; 138 | 139 | % Evolve the fluid by one time step. 140 | 141 | [Gamma eta psi] = DNScylAxiFDdoTimeStep(Gamma,eta,psi,t, ... 142 | parameters.dt,parameters.nu,R,Z, ... 143 | poissonEquation,boundaryInformation); 144 | 145 | % If this is one of the time steps at which we are to save the fields, 146 | % save the stuff to ts, Gammas, etas, and psis. dt must be added to t 147 | % because we are now at the end of the time step. 148 | 149 | if ii/parameters.KeepEveryNSteps == floor(ii/parameters.KeepEveryNSteps) 150 | disp([num2str(100*ii/parameters.NumberTimeSteps),'%']); 151 | ts(1 + ii/parameters.KeepEveryNSteps) = t+parameters.dt; 152 | Gammas(:,:,1 + ii/parameters.KeepEveryNSteps) = Gamma; 153 | etas(:,:,1 + ii/parameters.KeepEveryNSteps) = eta; 154 | psis(:,:,1 + ii/parameters.KeepEveryNSteps) = psi; 155 | 156 | % Check to see if any of the fields have nan's in them and if so, 157 | % terminate the simulation now and inform the user. 158 | 159 | if any(isnan(Gamma(:))) || any(isnan(eta(:))) || any(isnan(psi(:))) 160 | disp('NaN''s detected: simulation has become unstable.'); 161 | ts = ts(1:(1 + ii/parameters.KeepEveryNSteps)); 162 | Gammas = Gammas(:,:,1:(1 + ii/parameters.KeepEveryNSteps)); 163 | etas = etas(:,:,1:(1 + ii/parameters.KeepEveryNSteps)); 164 | psis = psis(:,:,1:(1 + ii/parameters.KeepEveryNSteps)); 165 | break; 166 | end 167 | 168 | end 169 | 170 | end 171 | 172 | % Put the final conditions as the last entries of ts, Gammas, etas, and 173 | % psis and we are done. 174 | 175 | ts(end) = t+parameters.dt; 176 | Gammas(:,:,end) = Gamma; 177 | etas(:,:,end) = eta; 178 | psis(:,:,end) = psi; 179 | 180 | warning(warningState); 181 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------