├── README.md ├── StokesFlowSimulation_Tutorial.pdf ├── images ├── flowfield_3D.png ├── flowfield_combo_fig.png └── flowfield_streamfunction.png └── scripts ├── bem_2d_functions ├── calcUV_BEM_2D.m ├── calc_Amat_BEM_2D.m ├── calc_PS_2D.m ├── calc_PSmat_BEM_2D.m ├── calc_SLDL_2D.m └── generateBC_BEM_2D.m ├── bem_3d_functions ├── calc_Amat_BEM_3D.m ├── calc_PS_3D.m ├── calc_PSmat_BEM_3D.m ├── calc_SLDL_3D.m ├── calc_singint.m ├── generateBC_BEM_3D.m ├── grid2tri.m └── trigrid_com_norm.m ├── doit_sim_BEM_2D.m ├── doit_sim_BEM_3D.m ├── doit_sim_MFS_2D.m ├── mfs_2d_functions ├── calcPPsi_MFS_2D.m ├── calcUV_MFS_2D.m ├── calc_Amat_MFS_2D.m └── generateBC_MFS_2D.m └── shared_functions ├── InteriorPts_2D.m ├── InteriorPts_3D.m ├── edge3d ├── edgedetect.asv ├── edgedetect.m ├── example.m ├── license.txt ├── plotsurface.m └── segment.m ├── quiver3D_pub ├── ColorSpec_LongName_to_RGBvalue.m ├── ColorSpec_ShortName_to_RGBvalue.m ├── arrow3D.m ├── demoQuiver3D.m ├── helix.m ├── html │ ├── demoQuiver3D.html │ ├── demoQuiver3D.png │ ├── demoQuiver3D_01.png │ ├── demoQuiver3D_02.png │ ├── demoQuiver3D_03.png │ ├── demoQuiver3D_04.png │ └── demoQuiver3D_05.png ├── quiver3D.m └── rotatePoints.m ├── quiverc.m ├── solve_mixedBC.m ├── vis2Dfield_quiver.m ├── vis2Dfield_streamline.m └── vis3Dfield_cube.m /README.md: -------------------------------------------------------------------------------- 1 | # Stokes-Flow-Simulation 2 | Stokes-Flow-Simulation is a Matlab implementation of boundary element method (BEM) and method of fundamental solutions (MFS) for simulation of Stokes flow based on traction and velocity boundary conditions. 3 | 4 | 5 | 6 | This repository contains an implementation of numerical simulations of low Reynold's number flow (Stokes flow). The work was done as part of my doctoral thesis at Yale University [1]. There are three possible types of simulations that can be performed with the code: 7 | 8 |
    9 |
  1. The method of fundamental solutions (MFS) to solve for flow in 2D 10 |
  2. The boundary element method (BEM) to solve for flow in 2D 11 |
  3. The BEM to solve for flow in 3D 12 |
13 | 14 | In all cases, the routines numerically solve for the vectorial flow field in the interior of the domain after specifying traction and/or flow boundary conditions. The default setting is to simulate a geometry similar to a [lid-driven cavity](https://www.cfd-online.com/Wiki/Lid-driven_cavity_problem). In certain cases, the pressure field, shear stress tensor, and/or stream function can also be directly computed. 15 | 16 | # Installation 17 | 18 | 1. Download folder containing m-files. 19 | 2. Add all folders and subfolders to path in Matlab. 20 | 3. Open doit_sim_BEM_2D.m and execute cell by cell. 21 | 22 | # How to use this repository 23 | The repository contains a series of m-files as well as a tutorial document. The m-files in turn are separated into "doit" executable files that can be run immediately. These files are all located in the scripts folder. The executable files in turn call back-end functions. The functions are divided folderwise into bem_2d_functions, bem_3d_functions, and mfs_2d_functions based on which simulation they are called by. In addition, there is a common shared folder of numerical routines used by all simulation methods, as well as some visualization scripts. 24 | 25 | The tutorial (StokesFlowSimulation_Tutorial.pdf) explains the underlying theory, technical details, and structure of the implementation of these numerical simulations. All of the scripts included are explained in the tutorial document. The tutorial itself is an appendix in my thesis, the full version of which can also be downloaded on my github page (@brendanhuang). 26 | 27 | # References 28 | A couple subroutines are adapted from [2], an implementation of BEM for Laplace's equation. The Stokes flow implementation follows the overall scheme of [3]. Additional background can be found in [4] and [5]. 29 | 30 | [1] B.K. Huang. All optical quantification of ciliary physiology. PhD thesis, Yale University, 2015. 31 | 32 | [2] Stephen Kirkup, Javad Yazdani, NE Mastorakis, M Poulos, V Mladenov, Z Bo- jkovic, D Simian, S Kartalopoulos, A Varonides, and C Udriste. A gentle introduction to the boundary element method in matlab/freemat. In WSEAS International Conference. Proceedings. Mathematics and Computers in Science and Engineering, number 10. WSEAS, 2008. 33 | 34 | [3] C. Pozrikidis. A practical guide to boundary element methods with the software library BEMLIB. Chapman & Hall/CRC, Boca Raton, 2002. 35 | 36 | [4] C. Pozrikidis. Boundary integral and singularity methods for linearized viscous flow. Cambridge University Press, Cambridge England; New York, 1992. 37 | 38 | [5] C. Pozrikidis. Introduction to theoretical and computational fluid dynamics. Oxford University Press, Oxford England; New York, 1997. 39 | -------------------------------------------------------------------------------- /StokesFlowSimulation_Tutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/StokesFlowSimulation_Tutorial.pdf -------------------------------------------------------------------------------- /images/flowfield_3D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/images/flowfield_3D.png -------------------------------------------------------------------------------- /images/flowfield_combo_fig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/images/flowfield_combo_fig.png -------------------------------------------------------------------------------- /images/flowfield_streamfunction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/images/flowfield_streamfunction.png -------------------------------------------------------------------------------- /scripts/bem_2d_functions/calcUV_BEM_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calcUV_BEM_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function estimates the flow field u and v 32 | % by computing the forward equation u_int = G f_boundary + T u_boundary, 33 | % where u_int is the flow field inside the domain, G is the single layer 34 | % potential, T is the double layer potential, f_boundary is the traction at 35 | % the boundary, and u_boundary is the flow at the boundary. It can also 36 | % calculate the analgous pressure field (press) and shear stress tensor 37 | % (stress) using the single and doulbe layer potentials 38 | % 39 | % Inputs: 40 | % f0, u0 - traction and velocity on boundaries 41 | % SLmat, DLmat - single and double layer potential susceptibility matrices 42 | % linking elements on boundary with interior points. 43 | % visc - viscosity 44 | % xpts, ypts: number of points to calculate in the interior. Note this must 45 | % be the same as the xpts, ypts used to calculate the single and double 46 | % layer potentials in calc_Amat_BEM_2D. The position of the points is 47 | % implicit in those matrices. 48 | % Optional Inputs: 49 | % PSL, PDL, SSL, SDL single and double layer potentials for pressure and stress, 50 | % if we would like to directly calculate these quantities on the interior 51 | % 52 | % Outputs: 53 | % u,v - vectorial flow field 54 | % Optional Outputs: 55 | % pres, stress - presssure field, shear stress tensor 56 | 57 | function [u,v,pres,stress] = calcUV_BEM_2D(f0,u0,SLmat,DLmat,xpts,ypts,visc,PSL,PDL,SSL,SDL) 58 | 59 | % calculate the forward equation 60 | uvtot = -1/(4*pi*visc)*SLmat*f0+1/(4*pi)*DLmat*u0; 61 | 62 | % use the information of our number of xpts and ypts to reshape our flow 63 | % field properly 64 | [xgrid,ygrid]=ndgrid(linspace(1,xpts,xpts),linspace(1,ypts,ypts)); 65 | u1=uvtot(1:xpts*ypts); 66 | v1=uvtot(xpts*ypts+1:end); 67 | 68 | u=accumarray([xgrid(:),ygrid(:)],u1,[xpts ypts]); 69 | v=accumarray([xgrid(:),ygrid(:)],v1,[xpts ypts]); 70 | 71 | % if desired, calculate the forward equation for pressure 72 | if nargout==3 73 | pres1 = -1/(4*pi)*PSL*f0+visc/(4*pi)*PDL*u0; 74 | pres=accumarray([xgrid(:),ygrid(:)],pres1,[xpts ypts]); 75 | 76 | % if desired, calculate the forward equation for shear stress as well 77 | elseif nargout ==4 78 | pres1 = -1/(4*pi)*PSL*f0+visc/(4*pi)*PDL*u0; 79 | stress1 = -1/(4*pi)*SSL*f0+visc/(4*pi)*SDL*u0; 80 | pres=accumarray([xgrid(:),ygrid(:)],pres1,[xpts ypts]); 81 | stress1=reshape(stress1,[xpts*ypts,2,2]); 82 | stress=zeros(xpts,ypts,2,2); 83 | 84 | %reshape stress into tensor of xpts x ypts x 2 x 2 85 | for i=1:2 86 | for j=1:2 87 | stress(:,:,i,j)=accumarray([xgrid(:),ygrid(:)],squeeze(stress1(:,i,j)),[xpts ypts]); 88 | end 89 | end 90 | end 91 | 92 | end -------------------------------------------------------------------------------- /scripts/bem_2d_functions/calc_Amat_BEM_2D.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/bem_2d_functions/calc_Amat_BEM_2D.m -------------------------------------------------------------------------------- /scripts/bem_2d_functions/calc_PS_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_PS_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses the pressure and shear stress 32 | % Green's functions in 2D to calculate the coupling between boundary 33 | % elements and points. It fills in the elements of the full Single Layer 34 | % and Double Layer potential matrices. 35 | % 36 | % 37 | % Inputs: 38 | % p1 point to calculate 39 | % r1, r2 vertices of line segment (2D) of boundary element; 40 | % normv normal vectors of boundary element 41 | % p_on is our point being evaluated on our boundary element? 42 | % 43 | % Outputs: 44 | % PSL, PDL: single and double layer potential coupling for pressure 45 | % SSL, SDL: single and double layer potential coupling for shear stress. 46 | % 47 | % References: for form of Green's Functions, see 48 | % [1] C. Pozrikidis. A practical guide to boundary element methods 49 | % with the software library BEMLIB. Chapman & Hall/CRC, Boca Raton, 2002. 50 | % Ch. 7 51 | 52 | 53 | function [PSL,PDL,SSL,SDL] = calc_PS_2D(p1,r1,r2,normal) 54 | 55 | % To evaluate the Green's function on a single element, we use a 56 | % Gauss-Legendre Quadrature. gaussleg, defined below, gives the weights and evaluation locations of 57 | % the Gauss-Legendre quadrature method 58 | [w,x,~]=gaussleg; 59 | 60 | % w and x come out assuming a line segment from 0 - 1. We need to reshift coordinates 61 | xx=r1(1)+x*(r2(1)-r1(1)); 62 | yy=r1(2)+x*(r2(2)-r1(2)); 63 | A=norm(r2-r1); 64 | 65 | xw12=repmat(w,[2 1]); 66 | xw222=permute(repmat(w',1,2,2,2),[2,3,4,1]); 67 | 68 | % pressure_single_2d and pressure_double_2d evaluates the single 69 | % and double layer potential at the series of points 70 | % xx, yy on the boundary element, and coupled to the points p1. 71 | % lponq is no longer necessary because we don't have the analytical 72 | % expressions to deal with singularities 73 | PSL = pressure_single_2d(xx,yy,p1(1),p1(2)); 74 | PSL = A*dot(PSL,xw12,2); 75 | PDL = pressure_double_2d(xx,yy,p1(1),p1(2),normal); 76 | PDL = A*dot(PDL,xw12,2); 77 | 78 | % only calculate shear if we need to 79 | if nargout>2 80 | SSL = stress_single_2d(xx,yy,p1(1),p1(2)); 81 | SSL = A*dot(SSL,xw222,4); 82 | SDL = stress_double_2d(xx,yy,p1(1),p1(2),normal); 83 | SDL = A*dot(SDL,xw222,4); 84 | end 85 | 86 | 87 | end 88 | 89 | function [wts,pts,n]=gaussleg() 90 | % gaussleg gives Gauss-Legendre Quadrature 8 points and weights to approximate 91 | % an integral 92 | n=8; 93 | wts= [ 5.061426814519E-02 0.111190517227 0.156853322939 0.181341891689 0.181341891689 0.156853322939 0.111190517227 5.061426814519E-02]; 94 | pts= [ 1.985507175123E-02 0.101666761293 0.237233795042 0.408282678752 0.591717321248 0.762766204958 0.898333238707 0.980144928249]; 95 | end 96 | 97 | function PS2D=pressure_single_2d(x,y,x0,y0) 98 | % Here we use the pressure Green's function for points in our Gaussian 99 | % Quadrature we calculate the displacement vector dx, dy, and the 100 | % distance dr, and feed it into the formula 101 | % See Ref [1], eq 7.2.13 102 | dx = x-x0; 103 | dy = y-y0; 104 | dr = sqrt(dx.^2+dy.^2); 105 | PS2D(1,:) = 2*dx./dr.^2; 106 | PS2D(2,:) = 2*dy./dr.^2; 107 | end 108 | 109 | function PD2D=pressure_double_2d(x,y,x0,y0,normal) 110 | % Here we do the same for the double layer potential for pressure 111 | % See Ref [1], eq 7.3.8 112 | dx = x-x0; 113 | dy = y-y0; 114 | dr = sqrt(dx.^2+dy.^2); 115 | np = numel(dx); 116 | PD=zeros(2,2,np); 117 | PD2D=zeros(2,np); 118 | PD(1,1,:)=2*(-1./dr.^2+2*dx.^2./dr.^4); 119 | PD(1,2,:)=2*(2*dx.*dy./dr.^4); 120 | PD(2,1,:)=2*(2*dx.*dy./dr.^4); 121 | PD(2,2,:)=2*(-1./dr.^2+2*dy.^2./dr.^4); 122 | 123 | % we have to dot with our normal vector again 124 | for j=1:2 125 | for k=1:np 126 | PD2D(j,k)=normal*squeeze(PD(j,:,k))'; 127 | end 128 | end 129 | end 130 | 131 | function Tijk=stress_single_2d(x,y,x0,y0) 132 | % Here we plug in the Green's function for our shear stress to 133 | % get our single layer potential. Because of the numerous components, we 134 | % chose again to loop through the dimensions 135 | % See Ref [1], eq. 7.2.13 136 | dx = x-x0; 137 | dy = y-y0; 138 | dr = sqrt(dx.^2+dy.^2); 139 | np = numel(dx); 140 | dt=[dx;dy]; 141 | Tijk=zeros(2,2,2,np); 142 | for i=1:2 143 | for j=1:2 144 | for k=1:2 145 | Tijk(i,j,k,:)=-4*dt(i,:).*dt(j,:).*dt(k,:)./dr.^4; 146 | end 147 | end 148 | end 149 | end 150 | 151 | function Kijk=stress_double_2d(x,y,x0,y0,normal) 152 | % Here we plug in the Green's function for our shear stress to 153 | % get our double layer potential. Because of the numerous components, we 154 | % chose again to loop through the dimensions 155 | % See Ref [1], Eq. 7.3.11 156 | dx = x-x0; 157 | dy = y-y0; 158 | np=numel(dx); 159 | dr=sqrt(dx.^2+dy.^2); 160 | dt=[dx;dy]; 161 | 162 | K_ijkl=zeros(2,2,2,2,np); 163 | Kijk=zeros(2,2,2,np); 164 | 165 | for i=1:2 166 | for j=1:2 167 | for k=1:2 168 | for l=1:2 169 | K_ijkl(i,j,k,l,:)=KD(i,k).*KD(j,l).*4./dr.^2+4./dr.^4.*(KD(i,j).*dt(k,:).*dt(l,:)+ ... 170 | KD(i,l).*dt(k,:).*dt(j,:)+KD(k,j).*dt(i,:).*dt(l,:)+KD(k,l).*dt(i,:).*dt(j,:)) ... 171 | -32.*dt(i,:).*dt(j,:).*dt(k,:).*dt(l,:)./dr.^6; 172 | end 173 | end 174 | end 175 | end 176 | 177 | % we will contract over our normal vector again 178 | for i=1:2 179 | for j=1:2 180 | for k=1:2 181 | for l=1:np 182 | Kijk(i,j,k,l)=normal*squeeze(K_ijkl(i,j,k,:,l)); 183 | end 184 | end 185 | end 186 | end 187 | end 188 | 189 | function k = KD(a,b) 190 | % Here we are defining our Kronecker delta function (KD). It is employed in 191 | % calculating the shear stress potential 192 | if a == b 193 | k = 1; 194 | else 195 | k = 0; 196 | end 197 | end 198 | -------------------------------------------------------------------------------- /scripts/bem_2d_functions/calc_PSmat_BEM_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_PSmat_BEM_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses Green's functions for pressure and 32 | % shear stress in 2D to calculate the coupling between boundary elements and points. This function simply 33 | % loops the calc_PSmat_BEM_2D function, a function that calculates individual 34 | % elements in the matrix. 35 | % 36 | % 37 | % Inputs: 38 | % vertpts - location of vertices of line (2D) of boundary elements 39 | % elemvert - vector to identify which vertices belong to which boundary element 40 | % p - location of points that are coupled to boundary elements are evaluated 41 | % p_on - a true / false variable letting us know if we expect some of the 42 | % points that we evluate to be collocated with boundary elements, thus 43 | % giving rise to a possible singularity 44 | % normv - normal vector of each boundary element 45 | % 46 | % Outputs: 47 | % PSLmat - single layer potential pressure matrix 48 | % PDLmat - double layer potential pressure matrix 49 | % SSLmat - single layer potential shear stress matrix 50 | % SDLmat - double layer potential shear stress matrix 51 | % The pressure values are scalar, while the shear stress is a d x d tensor 52 | % Thus, the matrices are m x 2n and 4 m x 2n for d=2. 53 | 54 | function [PSLmat,PDLmat,SSLmat,SDLmat] = calc_PSmat_BEM_2D(p,vertpts,elemvert,normv,p_on) 55 | m=size(p,1); 56 | n=size(elemvert,1); 57 | 58 | % if we want to evaluate pressure and stress on the boundary, we need to 59 | % deal with singularities. These cases have not yet been solved, so we 60 | % return a matrix of zeros 61 | if p_on 62 | PSLmat=zeros(m,2*n); 63 | PDLmat=zeros(m,2*n); 64 | SSLmat=zeros(4*m,2*n); 65 | SDLmat=zeros(4*m,2*n); 66 | 67 | % If we only want pressure and not shear stress, we'll only calculate 68 | % pressure 69 | elseif nargout<3 70 | PSLmat=zeros(2,m,n); 71 | PDLmat=zeros(2,m,n); 72 | SSLmat=zeros(4*m,2*n); 73 | SDLmat=zeros(4*m,2*n); 74 | 75 | for i=1:m 76 | for j=1:n 77 | r1=vertpts(elemvert(j,1),:); 78 | r2=vertpts(elemvert(j,2),:); 79 | normal=normv(j,:); 80 | p1=p(i,:); 81 | [PSLmat(:,i,j),PDLmat(:,i,j),SSLmat(:,:,:,i,j),SDLmat(:,:,:,i,j)]=calc_PS_2D(p1,r1,r2,normal,p_on&i==j); 82 | end 83 | end 84 | PSLmat=reshape(permute(PSLmat,[2,3,1]),[m,2*n]); 85 | PDLmat=reshape(permute(PDLmat,[2,3,1]),[m,2*n]); 86 | 87 | else 88 | % The default case is to calculate pressure and stress. In this case, to 89 | % make sure we have our indexing right, we will create a 3 and 5 90 | % dimensional matrix, but then reshape at the end to m x 2n and 4m x 2n 91 | PSLmat=zeros(2,m,n); 92 | PDLmat=zeros(2,m,n); 93 | SSLmat=zeros(2,2,2,m,n); 94 | SDLmat=zeros(2,2,2,m,n); 95 | for i=1:m 96 | for j=1:n 97 | % To evaluate the Green's function between each boundary 98 | % element and point, we need the endpoints of the boundary 99 | % element (r1, r2), the normal vector of the boundary element 100 | % (normal), and the coordinate of the point (p1) 101 | 102 | r1=vertpts(elemvert(j,1),:); 103 | r2=vertpts(elemvert(j,2),:); 104 | normal=normv(j,:); 105 | p1=p(i,:); 106 | [PSLmat(:,i,j),PDLmat(:,i,j),SSLmat(:,:,:,i,j),SDLmat(:,:,:,i,j)]=calc_PS_2D(p1,r1,r2,normal); 107 | end 108 | end 109 | PSLmat=reshape(permute(PSLmat,[2,3,1]),[m,2*n]); 110 | PDLmat=reshape(permute(PDLmat,[2,3,1]),[m,2*n]); 111 | SSLmat=reshape(permute(SSLmat,[4,1,2,5,3]),[4*m,2*n]); 112 | SDLmat=reshape(permute(SDLmat,[4,1,2,5,3]),[4*m,2*n]); 113 | end 114 | 115 | end -------------------------------------------------------------------------------- /scripts/bem_2d_functions/calc_SLDL_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_SLDL_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses Green's functions in 2D to calculate 32 | % the coupling between boundary elements and points. It fills in the 33 | % elements of the full Single Layer and Double Layer potential matrices 34 | % 35 | % 36 | % Inputs: 37 | % p1 point to calculate 38 | % r1, r2 vertices of line segment (2D) of boundary element; 39 | % normv normal vectors of boundary element 40 | % p_on is our point being evaluated on our boundary element? 41 | % 42 | % Outputs: 43 | % SLxx, SLxy, SLyx, SLyy: single layer potential coupling coefficients 44 | % DLxx, DLxy, DLyx, DLyy double layer potential coupling coeffcients. 45 | % For both, there are 4 components 46 | % 47 | % References: for form of Green's Functions, see 48 | % [1] C. Pozrikidis. A practical guide to boundary element methods 49 | % with the software library BEMLIB. Chapman & Hall/CRC, Boca Raton, 2002, 50 | % Chapter 7 51 | 52 | 53 | function [SLxx,SLxy,SLyx,SLyy,DLxx,DLxy,DLyx,DLyy] = calc_SLDL_2D(p1,r1,r2,normal,lponq) 54 | % To evaluate the Green's function on a single element, we use a 55 | % Gauss-Legendre Quadrature. gaussleg, defined below, gives the weights and evaluation locations of 56 | % the Gauss-Legendre quadrature method 57 | [w,x,~]=gaussleg; 58 | 59 | % w and x come out assuming a line segment from 0 - 1. We need to reshift coordinates 60 | xx=r1(1)+x*(r2(1)-r1(1)); 61 | yy=r1(2)+x*(r2(2)-r1(2)); 62 | A=norm(r2-r1); 63 | 64 | % gf_2d_fs now evaluates the single layer potential at the series of points 65 | % xx, yy on the boundary element, and coupled to the 66 | % lponq deals with whether the point is collocalized on the boundary 67 | % element itself, in which case we have to deal with a singularity 68 | [Gxx,Gxy,Gyx,Gyy]=gf_2d_fs(xx,yy,p1(1),p1(2),lponq); 69 | 70 | SLxx=A*(w*Gxx'); 71 | SLxy=A*(w*Gxy'); 72 | SLyx=A*(w*Gyx'); 73 | SLyy=A*(w*Gyy'); 74 | 75 | % In this 2D implementation, evaluating the Singularity done as per Pozrikidis 76 | % When we evaluate gf_2d_fs, we simply remove the log(r) term. We then 77 | % add in an analytic evaluation now 78 | if lponq 79 | a=norm(p1-r1); 80 | b=norm(p1-r2); 81 | SLxx=SLxx+(a+b-(a*log(a)+b*log(b))); 82 | SLyy=SLyy+(a+b-(a*log(a)+b*log(b))); 83 | end 84 | 85 | % Now we calculate double layer potential. Fortunately, the double layer potential 86 | % is zero if we have a singularity because the dot product of the normal vector with 87 | % the displacement vector between the point and the boundary element is zero (they are 88 | % orthogonal or (n,u) = 0) 89 | % If they are not collocalized, then we evaluate the stresslet Green's function 90 | % at our specified Gauss-Legendre points 91 | if lponq 92 | DLxx=0; 93 | DLxy=0; 94 | DLyx=0; 95 | DLyy=0; 96 | else 97 | [Sxx,Sxy,Syx,Syy]=stresslet_2d(xx,yy,p1(1),p1(2),normal); 98 | DLxx=A*(w*Sxx); 99 | DLxy=A*(w*Sxy); 100 | DLyx=A*(w*Syx); 101 | DLyy=A*(w*Syy); 102 | end 103 | 104 | end 105 | 106 | function [wts,pts,n]=gaussleg() 107 | % gaussleg gives Gauss-Legendre Quadrature 8 points and weights to approximate 108 | % an integral 109 | n=8; 110 | wts= [ 5.061426814519E-02 0.111190517227 0.156853322939 0.181341891689 0.181341891689 0.156853322939 0.111190517227 5.061426814519E-02]; 111 | pts= [ 1.985507175123E-02 0.101666761293 0.237233795042 0.408282678752 0.591717321248 0.762766204958 0.898333238707 0.980144928249]; 112 | end 113 | 114 | function [Gxx,Gxy,Gyx,Gyy]=gf_2d_fs(x,y,x0,y0,lponq) 115 | % Here we use the Oseen-Burgers tensor for points in our Gaussian 116 | % Quadrature 117 | % See Ref [1], Eq. 7.2.13 118 | 119 | % Calculate the displacement vector dx, dy, and the distance dr 120 | dx = x-x0; 121 | dy = y-y0; 122 | dr = sqrt(dx.^2+dy.^2); 123 | 124 | % As noted above, if the point is in the boundary element, we ignore the 125 | % log(r) term for now. We'll add back in the analytic answer later 126 | if lponq 127 | Gxx =dx.^2./dr.^2; 128 | Gxy =dx.*dy./dr.^2; 129 | Gyx =dx.*dy./dr.^2; 130 | Gyy =dy.^2./dr.^2; 131 | else 132 | Gxx = -log(dr) + dx.^2./dr.^2; 133 | Gxy = dx.*dy./dr.^2; 134 | Gyx = dx.*dy./dr.^2; 135 | Gyy = -log(dr) + dy.^2./dr.^2; 136 | end 137 | end 138 | 139 | function [Txx,Txy,Tyx,Tyy]=stresslet_2d(x,y,x0,y0,normal) 140 | % Here we plug in the Green's function for our stresslet to 141 | % get our double layer potential. 142 | % See Ref [1], Eq. 7.2.13 143 | dx = x-x0; 144 | dy = y-y0; 145 | np=numel(dx); 146 | 147 | dr=sqrt(dx.^2+dy.^2); 148 | dt=[dx;dy]; 149 | 150 | 151 | Tijk=zeros(2,2,2,np); 152 | Tij=zeros(2,2,np); 153 | 154 | % There are a number of components to evaluate, so in order to keep the 155 | % scripting as compact as possible and to avoid scripting errors, we 156 | % use a general expression and loop through the indices 157 | for i=1:2 158 | for j=1:2 159 | for k=1:2 160 | Tijk(i,j,k,:)=-4*dt(i,:).*dt(j,:).*dt(k,:)./dr.^4; 161 | end 162 | end 163 | end 164 | 165 | % Now we take the inner product of Tijk with nk, our normal vector 166 | for i=1:2 167 | for j=1:2 168 | for k=1:np 169 | Tij(i,j,k)=normal*squeeze(Tijk(i,j,:,k)); 170 | end 171 | end 172 | end 173 | Txx=squeeze(Tij(1,1,:)); 174 | Txy=squeeze(Tij(1,2,:)); 175 | Tyx=squeeze(Tij(2,1,:)); 176 | Tyy=squeeze(Tij(2,2,:)); 177 | end -------------------------------------------------------------------------------- /scripts/bem_2d_functions/generateBC_BEM_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: generateBC_BEM_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function generates the boundary points and boundary 32 | % conditions for the cavity driven fluid flow. There are several options 33 | % for input 34 | % 35 | % Inputs: 36 | % BCType - type of boundary conditions, either traction or velocity 37 | % boundundbound - set as bound or unbound. The unbound (open) geometry consists 38 | % of only a single horizontal surface, with fluid free to circulate 39 | % elsewhere. The bound (closed) geometry is a rectangular cavity 40 | % corner1, corner2 - these two points need to be 2d coordinates that give 41 | % the lower left and upper right boundary of the rectangular cavity. In the 42 | % case of the unbound condition, they will also define where we calculate 43 | % our flow 44 | % nbc - number of boundary elements along each of the four walls of the 45 | % surface (total points will be nbc x 4 for closed geometry) 46 | % Ubound - set the speed (or traction) of the moving portion of the boundary 47 | % fos - fraction of surface of bottom wall that is moving or applying 48 | % traction to the fluid. fos = 1 means the entire wall moves 49 | % 50 | % Outputs: 51 | % vertpts - location of vertices of line (2D) of boundaries 52 | % elemvert - vector to identify which vertices belong to which boundary element 53 | % p - location of points where boundary elements are evaluated; 54 | % bcx, bcy, bcu, bcv - values of boundary element points, both location and value of either velocity or traction; 55 | % alpha - index specifying at each of bcu, bcv, whether it is a velocity or traction condition 56 | % normv - normal vector of each boundary element 57 | 58 | function [elemvert,vertpts,bcmidx,bcmidy,bcu,bcv,p,normv,alpha] = generateBC_BEM_2D(BCtype,boundunbound,corner1,corner2,nbc,Ubound,fos) 59 | 60 | % in case we don't specify the fraction of the moving surface, we'll assume 61 | % the whole thing is moving 62 | if nargin==6 63 | fos = 1; 64 | end 65 | 66 | % calculate the total width and height of the cavity 67 | dx=corner2(1)-corner1(1); 68 | dy=corner2(2)-corner1(2); 69 | 70 | % generate the location of the boundary elements and the speed / traction 71 | % associated with each 72 | % in the case of unbounded, we only need to worry about the bottom surface 73 | % in the case of bounded cavity, we need to construct four walls 74 | switch boundunbound 75 | case 'unbounded' 76 | bxbot = linspace(corner1(1),corner2(1),nbc)'; 77 | bybot = linspace(corner1(2),corner1(2),nbc)'; 78 | bcu= linspace(0,0,nbc)'; 79 | bcv= linspace(0,0,nbc)'; 80 | velboundleft=round(nbc/2-fos*nbc/2); 81 | velboundright=min(round(nbc/2+fos*nbc/2),nbc-1); 82 | bcu(velboundleft:velboundright)=Ubound; 83 | bcxcoor=(bxbot(1:end-1)+bxbot(2:end))/2; 84 | bcycoor=(bybot(1:end-1)+bybot(2:end))/2; 85 | bcu=bcu(1:end-1); 86 | bcv=bcv(1:end-1); 87 | l1=linspace(1,nbc,nbc)'; 88 | elemvert=[l1,circshift(l1,[1,1])]; 89 | elemvert=elemvert(2:end,:); 90 | vertpts=[bxbot,bybot]; 91 | case 'bounded' 92 | bxbot=linspace(corner1(1),corner2(1),nbc)'; 93 | bybot=linspace(corner1(2),corner1(2),nbc)'; 94 | bxright=linspace(corner2(1),corner2(1),nbc)'; 95 | byright=linspace(corner1(2),corner2(2),nbc)'; 96 | bxtop=linspace(corner2(1),corner1(1),nbc)'; 97 | bytop=linspace(corner2(2),corner2(2),nbc)'; 98 | bxleft=linspace(corner1(1),corner1(1),nbc)'; 99 | byleft=linspace(corner2(2),corner1(2),nbc)'; 100 | bxbot=bxbot(1:end-1);bybot=bybot(1:end-1); 101 | bxright=bxright(1:end-1);byright=byright(1:end-1); 102 | bxtop=bxtop(1:end-1);bytop=bytop(1:end-1); 103 | bxleft=bxleft(1:end-1);byleft=byleft(1:end-1); 104 | bcxcoor=[bxbot; bxright; bxtop; bxleft]; 105 | bcycoor=[bybot; byright; bytop; byleft]; 106 | 107 | bcv=zeros(size(bcxcoor)); 108 | velboundleft=max(round(nbc*(1/2-fos/2)),2); 109 | velboundright=min(round(nbc*(1/2+fos/2)),nbc); 110 | bubot=linspace(0,0,nbc)'; 111 | bubot(velboundleft:velboundright)=Ubound; 112 | buright=linspace(0,0,nbc)';butop=linspace(0,0,nbc)';buleft=linspace(0,0,nbc)'; 113 | bubot=bubot(1:end-1);buright=buright(1:end-1);butop=butop(1:end-1);buleft=buleft(1:end-1); 114 | bcu=[bubot; buright; butop; buleft]; 115 | l1=linspace(1,numel(bcxcoor),numel(bcxcoor))'; 116 | elemvert=[l1,circshift(l1,[1,1])]; 117 | vertpts=[bcxcoor,bcycoor]; 118 | end 119 | 120 | % qa and qb are intermediate variables to help us calculate p, the 121 | % midpoints of each boundary element. Note that when we calculate our 122 | % initial matrix, we calculate the effect of a full element (line segment) 123 | % on a single point that is taken to be the midpoint of another line 124 | % element 125 | qa=[vertpts(elemvert(:,1),1), vertpts(elemvert(:,1),2)]; 126 | qb=[vertpts(elemvert(:,2),1), vertpts(elemvert(:,2),2)]; 127 | 128 | p=(qa+qb)/2; 129 | bcmidx=p(:,1); 130 | bcmidy=p(:,2); 131 | 132 | % calculate a unit vector normal to each element. 133 | pm=qa-qb; 134 | qlen=sqrt(pm(:,1).^2+pm(:,2).^2); 135 | normv=zeros(size(pm)); 136 | normv(:,1)=-pm(:,2)./qlen; 137 | normv(:,2)=pm(:,1)./qlen; 138 | 139 | % now we calculate alpha, which assigns a value to each boundary element 140 | % stating whether that element specifies a velocity or traction boundary 141 | % condition. Notably, we may specify the y-direction as flow (impenetrable 142 | % wall), but specify the x-direction as traction 143 | switch BCtype 144 | case 'velocity' 145 | alpha = false(size(bcu)); 146 | alpha = [alpha;alpha]; 147 | case 'traction' 148 | alpha = zeros(size(bcu)); 149 | alpha(bcu~=0)=1; 150 | alpha=logical([alpha;zeros(size(bcu))]); 151 | bcu=-bcu; 152 | end 153 | 154 | end -------------------------------------------------------------------------------- /scripts/bem_3d_functions/calc_Amat_BEM_3D.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/bem_3d_functions/calc_Amat_BEM_3D.m -------------------------------------------------------------------------------- /scripts/bem_3d_functions/calc_PS_3D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_PS_3D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses the pressure and shear stress 32 | % Green's functions in 3D to calculate the coupling between boundary 33 | % elements and points. It fills in the elements of the full Single Layer 34 | % and Double Layer potential matrices. 35 | % 36 | % 37 | % Inputs: 38 | % p1 point to calculate 39 | % r1, r2, r3 - vertices of triangle of boundary element; 40 | % normv - normal vectors of boundary element 41 | % p_on - is our point being evaluated on our boundary element? 42 | % 43 | % Outputs: 44 | % PSL, PDL: single and double layer potential coupling for pressure 45 | % SSL, SDL: single and double layer potential coupling for shear stress. 46 | % 47 | % References: for form of Green's Functions, see 48 | % [1] C. Pozrikidis. A practical guide to boundary element methods 49 | % with the software library BEMLIB. Chapman & Hall/CRC, Boca Raton, 2002. 50 | % Ch. 7 51 | 52 | function [PSL,PDL,SSL,SDL] = calc_PS_3D(p1,r1,r2,r3,normal) 53 | % We need to map a 2D triangle that lives in 3 dimensions onto a a flat 2D 54 | % coordinate system before we do our Gaussian quadrature. We take advantage 55 | % of the fact that we are in a cube by first finding out which dimension 56 | % has the same coordinates for all points, then define "x" and "y" accordingly 57 | whichone=whichissame(r1,r2,r3); 58 | % Calculate the area A of the triangle 59 | A=norm(cross(r2-r1,r3-r1))/2.0; 60 | 61 | % To evaluate the Green's function on a single element, we use a 62 | % Gauss-Legendre Quadrature. gaussleg, defined below, gives the weights and evaluation locations of 63 | % the Gauss-Legendre quadrature method 64 | 65 | 66 | N=5; 67 | xw = TriGL(N); 68 | if whichone==1 69 | x = r1(1)*ones(size(xw(:,1))); 70 | y = r1(2)*(1-xw(:,1)-xw(:,2))+r2(2)*xw(:,1)+r3(2)*xw(:,2); 71 | z = r1(3)*(1-xw(:,1)-xw(:,2))+r2(3)*xw(:,1)+r3(3)*xw(:,2); 72 | elseif whichone==2 73 | x = r1(1)*(1-xw(:,1)-xw(:,2))+r2(1)*xw(:,1)+r3(1)*xw(:,2); 74 | y = r1(2)*ones(size(xw(:,1))); 75 | z = r1(3)*(1-xw(:,1)-xw(:,2))+r2(3)*xw(:,1)+r3(3)*xw(:,2); 76 | elseif whichone==3 77 | x = r1(1)*(1-xw(:,1)-xw(:,2))+r2(1)*xw(:,1)+r3(1)*xw(:,2); 78 | y = r1(2)*(1-xw(:,1)-xw(:,2))+r2(2)*xw(:,1)+r3(2)*xw(:,2); 79 | z = r1(3)*ones(size(xw(:,1))); 80 | end 81 | x=x';y=y';z=z'; 82 | xw13=repmat(xw(:,3)',[3 1]); 83 | xw333=permute(repmat(xw(:,3),1,3,3,3),[2,3,4,1]); 84 | 85 | % pressure_single_3d and pressure_double_3d evaluate the single 86 | % and double layer potential at the series of points 87 | % xx, yy on the boundary element, and coupled to the points p1. 88 | % lponq is no longer necessary because we don't have the analytical 89 | % expressions to deal with singularities 90 | 91 | PSL = pressure_single_3d(x,y,z,p1(1),p1(2),p1(3)); 92 | PSL = A*dot(PSL,xw13,2); 93 | PDL = pressure_double_3d(x,y,z,p1(1),p1(2),p1(3),normal); 94 | PDL = A*dot(PDL,xw13,2); 95 | 96 | % only calculate shear if we need to 97 | if nargout>2 98 | SSL = stress_single_3d(x,y,z,p1(1),p1(2),p1(3)); 99 | SSL = A*dot(SSL,xw333,4); 100 | SDL = stress_double_3d(x,y,z,p1(1),p1(2),p1(3),normal); 101 | SDL = A*dot(SDL,xw333,4); 102 | end 103 | 104 | end 105 | 106 | function whichone=whichissame(r1,r2,r3) 107 | % simple function to determine which of the three coordinates is invariant 108 | % across all the triangles 109 | if r1(1)==r2(1) && r1(1)==r3(1) 110 | whichone=1; 111 | elseif r1(2)==r2(2) && r1(2)==r3(2) 112 | whichone=2; 113 | elseif r1(3)==r2(3) && r1(3)==r3(3) 114 | whichone=3; 115 | end 116 | end 117 | 118 | function PS3D=pressure_single_3d(x,y,z,x0,y0,z0) 119 | % Here we use the pressure Green's function for points in our Gaussian 120 | % Quadrature we calculate the displacement vector dx, dy, and the 121 | % distance dr, and feed it into the formula 122 | % See Ref [1], eq 7.2.14 123 | dx = x-x0; 124 | dy = y-y0; 125 | dz = z-z0; 126 | dr = sqrt(dx.^2+dy.^2+dz.^2); 127 | np = numel(dx); 128 | PS3D=zeros(3,np); 129 | PS3D(1,:)=2*dx./dr.^3; 130 | PS3D(2,:)=2*dy./dr.^3; 131 | PS3D(3,:)=2*dz./dr.^3; 132 | end 133 | 134 | function PD3D=pressure_double_3d(x,y,z,x0,y0,z0,normal) 135 | % Here we do the same for the double layer potential for pressure 136 | % See Ref [1], eq 7.4.4 137 | dx = x-x0; 138 | dy = y-y0; 139 | dz = z-z0; 140 | dr = sqrt(dx.^2+dy.^2+dz.^2); 141 | np = numel(dx); 142 | PD=zeros(3,3,np); 143 | PD3D=zeros(3,np); 144 | PD(1,1,:)=4*(-1./dr.^3+3*dx.^2./dr.^5); 145 | PD(1,2,:)=4*(3*dx.*dy./dr.^5); 146 | PD(1,3,:)=4*(3*dx.*dz./dr.^5); 147 | PD(2,1,:)=4*(3*dx.*dy./dr.^5); 148 | PD(2,2,:)=4*(-1./dr.^3+3*dy.^2./dr.^5); 149 | PD(2,3,:)=4*(3*dy.*dz./dr.^5); 150 | PD(3,1,:)=4*(3*dx.*dz./dr.^5); 151 | PD(3,2,:)=4*(3*dx.*dy./dr.^5); 152 | PD(3,3,:)=4*(-1./dr.^3+3*dz.^2./dr.^5); 153 | for j=1:3 154 | for k=1:np 155 | %dot with normal vector 156 | PD3D(j,k)=normal*squeeze(PD(j,:,k))'; 157 | end 158 | end 159 | end 160 | 161 | function Tijk=stress_single_3d(x,y,z,x0,y0,z0) 162 | % Here we plug in the Green's function for our shear stress to 163 | % get our single layer potential. Because of the numerous components, we 164 | % chose again to loop through the dimensions 165 | % See Ref [1], eq. 7.2.14 166 | 167 | dx = x-x0; 168 | dy = y-y0; 169 | dz = z-z0; 170 | dr = sqrt(dx.^2+dy.^2+dz.^2); 171 | np = numel(dx); 172 | dt=[dx;dy;dz]; 173 | Tijk=zeros(3,3,3,np); 174 | for i=1:3 175 | for j=1:3 176 | for k=1:3 177 | Tijk(i,j,k,:)=-6*dt(i,:).*dt(j,:).*dt(k,:)./dr.^5; 178 | end 179 | end 180 | end 181 | end 182 | 183 | function Kijk=stress_double_3d(x,y,z,x0,y0,z0,normal) 184 | % Here we plug in the Green's function for our shear stress to 185 | % get our double layer potential. Because of the numerous components, we 186 | % chose again to loop through the dimensions 187 | % See Ref [1], Eq. 7.4.6 188 | 189 | dx = x-x0; 190 | dy = y-y0; 191 | dz = z-z0; 192 | np=numel(dx); 193 | dr=sqrt(dx.^2+dy.^2+dz.^2); 194 | dt=[dx;dy;dz]; 195 | 196 | 197 | Psi_ijkl=zeros(3,3,3,3,np); 198 | Kijk=zeros(3,3,3,np); 199 | 200 | for i=1:3 201 | for j=1:3 202 | for k=1:3 203 | for l=1:3 204 | Psi_ijkl(i,j,k,l,:)=KD(i,k).*KD(j,l).*4./dr.^3+6./dr.^5.*(KD(i,j).*dt(k,:).*dt(l,:)+ ... 205 | KD(i,l).*dt(k,:).*dt(j,:)+KD(k,j).*dt(i,:).*dt(l,:)+KD(k,l).*dt(i,:).*dt(j,:)) ... 206 | -60.*dt(i,:).*dt(j,:).*dt(k,:).*dt(l,:)./dr.^7; 207 | end 208 | end 209 | end 210 | end 211 | 212 | % we will contract over our normal vector again 213 | 214 | for i=1:3 215 | for j=1:3 216 | for k=1:3 217 | for l=1:np 218 | Kijk(i,j,k,l)=normal*squeeze(Psi_ijkl(i,j,k,:,l)); 219 | end 220 | end 221 | end 222 | end 223 | end 224 | 225 | 226 | function xw = TriGL(n) 227 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 228 | % Function TriGaussPoints provides the Gaussian points and weights % 229 | % for the Gaussian quadrature of order n for the standard triangles. % 230 | % 231 | % 232 | % Input: n - the order of the Gaussian quadrature (n<=12) % 233 | % 234 | % 235 | % Output: xw - a n by 3 matrix: % 236 | % 1st column gives the x-coordinates of points % 237 | % 2nd column gives the y-coordinates of points % 238 | % 3rd column gives the weights % 239 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 240 | 241 | xw = zeros(n,3); 242 | if (n == 1) 243 | xw=[0.33333333333333 0.33333333333333 1.00000000000000]; 244 | elseif (n == 2) 245 | xw=[0.16666666666667 0.16666666666667 0.33333333333333 246 | 0.16666666666667 0.66666666666667 0.33333333333333 247 | 0.66666666666667 0.16666666666667 0.33333333333333]; 248 | elseif (n == 3) 249 | xw=[0.33333333333333 0.33333333333333 -0.56250000000000 250 | 0.20000000000000 0.20000000000000 0.52083333333333 251 | 0.20000000000000 0.60000000000000 0.52083333333333 252 | 0.60000000000000 0.20000000000000 0.52083333333333]; 253 | elseif (n == 4) 254 | xw=[0.44594849091597 0.44594849091597 0.22338158967801 255 | 0.44594849091597 0.10810301816807 0.22338158967801 256 | 0.10810301816807 0.44594849091597 0.22338158967801 257 | 0.09157621350977 0.09157621350977 0.10995174365532 258 | 0.09157621350977 0.81684757298046 0.10995174365532 259 | 0.81684757298046 0.09157621350977 0.10995174365532]; 260 | elseif (n == 5) 261 | xw=[0.33333333333333 0.33333333333333 0.22500000000000 262 | 0.47014206410511 0.47014206410511 0.13239415278851 263 | 0.47014206410511 0.05971587178977 0.13239415278851 264 | 0.05971587178977 0.47014206410511 0.13239415278851 265 | 0.10128650732346 0.10128650732346 0.12593918054483 266 | 0.10128650732346 0.79742698535309 0.12593918054483 267 | 0.79742698535309 0.10128650732346 0.12593918054483]; 268 | elseif (n == 6) 269 | xw=[0.24928674517091 0.24928674517091 0.11678627572638 270 | 0.24928674517091 0.50142650965818 0.11678627572638 271 | 0.50142650965818 0.24928674517091 0.11678627572638 272 | 0.06308901449150 0.06308901449150 0.05084490637021 273 | 0.06308901449150 0.87382197101700 0.05084490637021 274 | 0.87382197101700 0.06308901449150 0.05084490637021 275 | 0.31035245103378 0.63650249912140 0.08285107561837 276 | 0.63650249912140 0.05314504984482 0.08285107561837 277 | 0.05314504984482 0.31035245103378 0.08285107561837 278 | 0.63650249912140 0.31035245103378 0.08285107561837 279 | 0.31035245103378 0.05314504984482 0.08285107561837 280 | 0.05314504984482 0.63650249912140 0.08285107561837]; 281 | elseif (n == 7) 282 | xw=[0.33333333333333 0.33333333333333 -0.14957004446768 283 | 0.26034596607904 0.26034596607904 0.17561525743321 284 | 0.26034596607904 0.47930806784192 0.17561525743321 285 | 0.47930806784192 0.26034596607904 0.17561525743321 286 | 0.06513010290222 0.06513010290222 0.05334723560884 287 | 0.06513010290222 0.86973979419557 0.05334723560884 288 | 0.86973979419557 0.06513010290222 0.05334723560884 289 | 0.31286549600487 0.63844418856981 0.07711376089026 290 | 0.63844418856981 0.04869031542532 0.07711376089026 291 | 0.04869031542532 0.31286549600487 0.07711376089026 292 | 0.63844418856981 0.31286549600487 0.07711376089026 293 | 0.31286549600487 0.04869031542532 0.07711376089026 294 | 0.04869031542532 0.63844418856981 0.07711376089026]; 295 | elseif (n == 8) 296 | xw=[0.33333333333333 0.33333333333333 0.14431560767779 297 | 0.45929258829272 0.45929258829272 0.09509163426728 298 | 0.45929258829272 0.08141482341455 0.09509163426728 299 | 0.08141482341455 0.45929258829272 0.09509163426728 300 | 0.17056930775176 0.17056930775176 0.10321737053472 301 | 0.17056930775176 0.65886138449648 0.10321737053472 302 | 0.65886138449648 0.17056930775176 0.10321737053472 303 | 0.05054722831703 0.05054722831703 0.03245849762320 304 | 0.05054722831703 0.89890554336594 0.03245849762320 305 | 0.89890554336594 0.05054722831703 0.03245849762320 306 | 0.26311282963464 0.72849239295540 0.02723031417443 307 | 0.72849239295540 0.00839477740996 0.02723031417443 308 | 0.00839477740996 0.26311282963464 0.02723031417443 309 | 0.72849239295540 0.26311282963464 0.02723031417443 310 | 0.26311282963464 0.00839477740996 0.02723031417443 311 | 0.00839477740996 0.72849239295540 0.02723031417443]; 312 | 313 | else 314 | disp('Bad input n'); 315 | end 316 | end 317 | 318 | function k = KD(a,b) 319 | % Here we are defining our Kronecker delta function (KD). It is employed in 320 | % calculating the shear stress potential 321 | 322 | if a == b 323 | k = 1; 324 | else 325 | k = 0; 326 | end 327 | end 328 | -------------------------------------------------------------------------------- /scripts/bem_3d_functions/calc_PSmat_BEM_3D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_PSmat_BEM_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses Green's functions for pressure and 32 | % shear stress in 2D to calculate the coupling between boundary elements and points. This function simply 33 | % loops the calc_PSmat_BEM_2D function, a function that calculates individual 34 | % elements in the matrix. 35 | % 36 | % 37 | % Inputs: 38 | % vertpts - location of vertices of line (2D) of boundary elements 39 | % elemvert - vector to identify which vertices belong to which boundary element 40 | % p - location of points that are coupled to boundary elements are evaluated 41 | % p_on - a true / false variable letting us know if we expect some of the 42 | % points that we evluate to be collocated with boundary elements, thus 43 | % giving rise to a possible singularity 44 | % normv - normal vector of each boundary element 45 | % 46 | % Outputs: 47 | % PSLmat - single layer potential pressure matrix 48 | % PDLmat - double layer potential pressure matrix 49 | % SSLmat - single layer potential shear stress matrix 50 | % SDLmat - double layer potential shear stress matrix 51 | % The pressure values are scalar, while the shear stress is a d x d tensor 52 | % Thus, the matrices are m x 2n and 4 m x 2n for d=2. 53 | 54 | function [PSLmat,PDLmat,SSLmat,SDLmat] =calc_PSmat_BEM_3D(p,vertpts,elemvert,normv,p_on) 55 | 56 | n=size(elemvert,1); 57 | m=size(p,1); 58 | 59 | % if we want to evaluate pressure and stress on the boundary, we need to 60 | % deal with singularities. These cases have not yet been solved, so we 61 | % return a matrix of zeros 62 | if p_on 63 | PSLmat=zeros(m,3*n); 64 | PDLmat=zeros(m,3*n); 65 | SSLmat=zeros(9*m,3*n); 66 | SDLmat=zeros(9*m,3*n); 67 | disp('Not valid at boundaries'); 68 | elseif nargout<3 69 | % If we only want pressure and not shear stress, we'll only calculate 70 | % pressure 71 | 72 | PSLmat=zeros(3,m,n); 73 | PDLmat=zeros(3,m,n); 74 | SSLmat=zeros(9*m,3*n); 75 | SDLmat=zeros(9*m,3*n); 76 | 77 | for i=1:m 78 | for j=1:n 79 | % To evaluate the Green's function between each boundary 80 | % element and point, we need the endpoints of the boundary 81 | % element (r1, r2), the normal vector of the boundary element 82 | % (normal), and the coordinate of the point (p1) 83 | 84 | r1=vertpts(elemvert(j,1),:); 85 | r2=vertpts(elemvert(j,2),:); 86 | r3=vertpts(elemvert(j,3),:); 87 | normal=normv(j,:); 88 | p1=p(i,:); 89 | [PSLmat(:,i,j),PDLmat(:,i,j)] = calc_PS_3D(p1,r1,r2,r3,normal); 90 | end 91 | end 92 | PSLmat=reshape(permute(PSLmat,[2,3,1]),[m,3*n]); 93 | PDLmat=reshape(permute(PDLmat,[2,3,1]),[m,3*n]); 94 | else 95 | 96 | % The default case is to calculate pressure and stress. In this case, to 97 | % make sure we have our indexing right, we will create a 3 and 5 98 | % dimensional matrix, but then reshape at the end to m x 3n and 9m x 3n 99 | 100 | PSLmat=zeros(3,m,n); 101 | PDLmat=zeros(3,m,n); 102 | SSLmat=zeros(3,3,3,m,n); 103 | SDLmat=zeros(3,3,3,m,n); 104 | 105 | for i=1:m 106 | for j=1:n 107 | % To evaluate the Green's function between each boundary 108 | % element and point, we need the endpoints of the boundary 109 | % element (r1, r2), the normal vector of the boundary element 110 | % (normal), and the coordinate of the point (p1) 111 | r1=vertpts(elemvert(j,1),:); 112 | r2=vertpts(elemvert(j,2),:); 113 | r3=vertpts(elemvert(j,3),:); 114 | normal=normv(j,:); 115 | p1=p(i,:); 116 | [PSLmat(:,i,j),PDLmat(:,i,j),SSLmat(:,:,:,i,j),SDLmat(:,:,:,i,j)] = calc_PS_3D(p1,r1,r2,r3,normal); 117 | end 118 | end 119 | PSLmat=reshape(permute(PSLmat,[2,3,1]),[m,3*n]); 120 | PDLmat=reshape(permute(PDLmat,[2,3,1]),[m,3*n]); 121 | SSLmat=reshape(permute(SSLmat,[4,1,2,5,3]),[9*m,3*n]); 122 | SDLmat=reshape(permute(SDLmat,[4,1,2,5,3]),[9*m,3*n]); 123 | 124 | end 125 | 126 | end -------------------------------------------------------------------------------- /scripts/bem_3d_functions/calc_SLDL_3D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_SLDL_3D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses Green's functions in 3D to calculate 32 | % the coupling between boundary elements and points. It fills in the 33 | % elements of the full Single Layer and Double Layer potential matrices 34 | % 35 | % 36 | % Inputs: 37 | % p1 point to calculate 38 | % r1, r2 vertices of line segment (2D) of boundary element; 39 | % normv normal vectors of boundary element 40 | % p_on is our point being evaluated on our boundary element? 41 | % 42 | % Outputs: 43 | % GSL: single layer potential coupling coefficients 44 | % GDL: double layer potential coupling coeffcients. 45 | % For both, there are 9 components 46 | % 47 | % References: for form of Green's Functions, see 48 | % [1] C. Pozrikidis. A practical guide to boundary element methods 49 | % with the software library BEMLIB. Chapman & Hall/CRC, Boca Raton, 2002, 50 | % Chapter 7 51 | 52 | function [GSL,GDL] = calc_SLDL_3D(p1,r1,r2,r3,normal,ponq) 53 | % We need to map a 2D triangle that lives in 3 dimensions onto a a flat 2D 54 | % coordinate system before we do our Gaussian quadrature. We take advantage 55 | % of the fact that we are in a cube by first finding out which dimension 56 | % has the same coordinates for all points, then define "x" and "y" accordingly 57 | 58 | whichone=whichissame(r1,r2,r3); 59 | 60 | % Calculate the area A of the triangle 61 | A=norm(cross(r2-r1,r3-r1))/2.0; 62 | 63 | % For points that are collocated with the boundary element, we have to call 64 | % the special calc_singint function to handle the singularity. 65 | if ponq 66 | if whichone==1 67 | r12d=[r1(2);r1(3)]; 68 | r22d=[r2(2);r2(3)]; 69 | r32d=[r3(2);r3(3)]; 70 | p12d=[p1(2);p1(3)]; 71 | [Gyy,Gyz,Gyx,Gzy,Gzz,Gzx,Gxy,Gxz,Gxx]=calc_singint(p12d,r12d,r22d,r32d); 72 | elseif whichone==2 73 | r12d=[r1(1);r1(3)]; 74 | r22d=[r2(1);r2(3)]; 75 | r32d=[r3(1);r3(3)]; 76 | p12d=[p1(1);p1(3)]; 77 | [Gxx,Gxz,Gxy,Gzx,Gzz,Gzy,Gyx,Gyz,Gyy]=calc_singint(p12d,r12d,r22d,r32d); 78 | elseif whichone==3 79 | r12d=[r1(1);r1(2)]; 80 | r22d=[r2(1);r2(2)]; 81 | r32d=[r3(1);r3(2)]; 82 | p12d=[p1(1);p1(2)]; 83 | [Gxx,Gxy,Gxz,Gyx,Gyy,Gyz,Gzx,Gzy,Gzz]=calc_singint(p12d,r12d,r22d,r32d); 84 | end 85 | GSL=[Gxx,Gxy,Gxz;Gyx,Gyy,Gyz;Gzx,Gzy,Gzz]; 86 | GDL=zeros(3,3); 87 | else 88 | % for non collocated points, we use the Gaussian-Legendre quadrature on 89 | % a triangle 90 | N=5; 91 | xw = TriGL(N); 92 | xwmat=permute(repmat(xw(:,3),1,3,3),[2,3,1]); 93 | if whichone==1 94 | x = r1(1)*ones(size(xw(:,1))); 95 | y = r1(2)*(1-xw(:,1)-xw(:,2))+r2(2)*xw(:,1)+r3(2)*xw(:,2); 96 | z = r1(3)*(1-xw(:,1)-xw(:,2))+r2(3)*xw(:,1)+r3(3)*xw(:,2); 97 | elseif whichone==2 98 | x = r1(1)*(1-xw(:,1)-xw(:,2))+r2(1)*xw(:,1)+r3(1)*xw(:,2); 99 | y = r1(2)*ones(size(xw(:,1))); 100 | z = r1(3)*(1-xw(:,1)-xw(:,2))+r2(3)*xw(:,1)+r3(3)*xw(:,2); 101 | elseif whichone==3 102 | x = r1(1)*(1-xw(:,1)-xw(:,2))+r2(1)*xw(:,1)+r3(1)*xw(:,2); 103 | y = r1(2)*(1-xw(:,1)-xw(:,2))+r2(2)*xw(:,1)+r3(2)*xw(:,2); 104 | z = r1(3)*ones(size(xw(:,1))); 105 | end 106 | x=x';y=y';z=z'; 107 | 108 | % now we call the actual form of the Green's function in 3D 109 | GSL = gf3d_SL_par(x,y,z,p1(1),p1(2),p1(3)); 110 | GSL = A*dot(GSL,xwmat,3); 111 | GDL = stresslet_3d(x,y,z,p1(1),p1(2),p1(3),normal); 112 | GDL = A*dot(GDL,xwmat,3); 113 | end 114 | 115 | end 116 | 117 | function whichone=whichissame(r1,r2,r3) 118 | % simple function to determine which of the three coordinates is invariant 119 | % across all the triangles 120 | if r1(1)==r2(1) && r1(1)==r3(1) 121 | whichone=1; 122 | elseif r1(2)==r2(2) && r1(2)==r3(2) 123 | whichone=2; 124 | elseif r1(3)==r2(3) && r1(3)==r3(3) 125 | whichone=3; 126 | end 127 | end 128 | 129 | function GF3=gf3d_SL_par(x,y,z,x0,y0,z0) 130 | % Here we use the Oseen-Burgers tensor 131 | % See Ref [1], Eq. 7.2.14 132 | % We don't have to worry about singularities here because we already 133 | % encapsulated that analysis in our function calc_singint 134 | 135 | % Calculate the displacement vector dx, dy, and the distance dr 136 | dx = x-x0; 137 | dy = y-y0; 138 | dz = z-z0; 139 | dr = sqrt(dx.^2+dy.^2+dz.^2); 140 | np = numel(dx); 141 | GF3=zeros(3,3,np); 142 | GF3(1,1,:)=1./dr+dx.^2./dr.^3; 143 | GF3(1,2,:)=dx.*dy./dr.^3; 144 | GF3(1,3,:)=dx.*dz./dr.^3; 145 | GF3(2,1,:)=dx.*dy./dr.^3; 146 | GF3(2,2,:)=1./dr+dy.^2./dr.^3; 147 | GF3(2,3,:)=dy.*dz./dr.^3; 148 | GF3(3,1,:)=dx.*dz./dr.^3; 149 | GF3(3,2,:)=dy.*dz./dr.^3; 150 | GF3(3,3,:)=1./dr+dz.^2./dr.^3; 151 | end 152 | 153 | function Tij=stresslet_3d(x,y,z,x0,y0,z0,normal) 154 | % Here we plug in the Green's function for our stresslet to get our double 155 | % layer potnential. See Ref [1], Eq. 7.2.14 156 | 157 | dx = x-x0; 158 | dy = y-y0; 159 | dz = z-z0; 160 | np=numel(dx); 161 | 162 | dr=sqrt(dx.^2+dy.^2+dz.^2); 163 | dt=[dx;dy;dz]; 164 | 165 | 166 | Tijk=zeros(3,3,3,np); 167 | Tij=zeros(3,3,np); 168 | 169 | for i=1:3 170 | for j=1:3 171 | for k=1:3 172 | Tijk(i,j,k,:)=-6*dt(i,:).*dt(j,:).*dt(k,:)./dr.^5; 173 | end 174 | end 175 | end 176 | 177 | for i=1:3 178 | for j=1:3 179 | for k=1:np 180 | Tij(i,j,k)=normal*squeeze(Tijk(i,j,:,k)); 181 | end 182 | end 183 | end 184 | end 185 | 186 | function xw = TriGL(n) 187 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 188 | % Function TriGaussPoints provides the Gaussian points and weights % 189 | % for the Gaussian quadrature of order n for the standard triangles. % 190 | % 191 | % 192 | % Input: n - the order of the Gaussian quadrature (n<=12) % 193 | % 194 | % 195 | % Output: xw - a n by 3 matrix: % 196 | % 1st column gives the x-coordinates of points % 197 | % 2nd column gives the y-coordinates of points % 198 | % 3rd column gives the weights % 199 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 200 | 201 | xw = zeros(n,3); 202 | if (n == 1) 203 | xw=[0.33333333333333 0.33333333333333 1.00000000000000]; 204 | elseif (n == 2) 205 | xw=[0.16666666666667 0.16666666666667 0.33333333333333 206 | 0.16666666666667 0.66666666666667 0.33333333333333 207 | 0.66666666666667 0.16666666666667 0.33333333333333]; 208 | elseif (n == 3) 209 | xw=[0.33333333333333 0.33333333333333 -0.56250000000000 210 | 0.20000000000000 0.20000000000000 0.52083333333333 211 | 0.20000000000000 0.60000000000000 0.52083333333333 212 | 0.60000000000000 0.20000000000000 0.52083333333333]; 213 | elseif (n == 4) 214 | xw=[0.44594849091597 0.44594849091597 0.22338158967801 215 | 0.44594849091597 0.10810301816807 0.22338158967801 216 | 0.10810301816807 0.44594849091597 0.22338158967801 217 | 0.09157621350977 0.09157621350977 0.10995174365532 218 | 0.09157621350977 0.81684757298046 0.10995174365532 219 | 0.81684757298046 0.09157621350977 0.10995174365532]; 220 | elseif (n == 5) 221 | xw=[0.33333333333333 0.33333333333333 0.22500000000000 222 | 0.47014206410511 0.47014206410511 0.13239415278851 223 | 0.47014206410511 0.05971587178977 0.13239415278851 224 | 0.05971587178977 0.47014206410511 0.13239415278851 225 | 0.10128650732346 0.10128650732346 0.12593918054483 226 | 0.10128650732346 0.79742698535309 0.12593918054483 227 | 0.79742698535309 0.10128650732346 0.12593918054483]; 228 | elseif (n == 6) 229 | xw=[0.24928674517091 0.24928674517091 0.11678627572638 230 | 0.24928674517091 0.50142650965818 0.11678627572638 231 | 0.50142650965818 0.24928674517091 0.11678627572638 232 | 0.06308901449150 0.06308901449150 0.05084490637021 233 | 0.06308901449150 0.87382197101700 0.05084490637021 234 | 0.87382197101700 0.06308901449150 0.05084490637021 235 | 0.31035245103378 0.63650249912140 0.08285107561837 236 | 0.63650249912140 0.05314504984482 0.08285107561837 237 | 0.05314504984482 0.31035245103378 0.08285107561837 238 | 0.63650249912140 0.31035245103378 0.08285107561837 239 | 0.31035245103378 0.05314504984482 0.08285107561837 240 | 0.05314504984482 0.63650249912140 0.08285107561837]; 241 | elseif (n == 7) 242 | xw=[0.33333333333333 0.33333333333333 -0.14957004446768 243 | 0.26034596607904 0.26034596607904 0.17561525743321 244 | 0.26034596607904 0.47930806784192 0.17561525743321 245 | 0.47930806784192 0.26034596607904 0.17561525743321 246 | 0.06513010290222 0.06513010290222 0.05334723560884 247 | 0.06513010290222 0.86973979419557 0.05334723560884 248 | 0.86973979419557 0.06513010290222 0.05334723560884 249 | 0.31286549600487 0.63844418856981 0.07711376089026 250 | 0.63844418856981 0.04869031542532 0.07711376089026 251 | 0.04869031542532 0.31286549600487 0.07711376089026 252 | 0.63844418856981 0.31286549600487 0.07711376089026 253 | 0.31286549600487 0.04869031542532 0.07711376089026 254 | 0.04869031542532 0.63844418856981 0.07711376089026]; 255 | elseif (n == 8) 256 | xw=[0.33333333333333 0.33333333333333 0.14431560767779 257 | 0.45929258829272 0.45929258829272 0.09509163426728 258 | 0.45929258829272 0.08141482341455 0.09509163426728 259 | 0.08141482341455 0.45929258829272 0.09509163426728 260 | 0.17056930775176 0.17056930775176 0.10321737053472 261 | 0.17056930775176 0.65886138449648 0.10321737053472 262 | 0.65886138449648 0.17056930775176 0.10321737053472 263 | 0.05054722831703 0.05054722831703 0.03245849762320 264 | 0.05054722831703 0.89890554336594 0.03245849762320 265 | 0.89890554336594 0.05054722831703 0.03245849762320 266 | 0.26311282963464 0.72849239295540 0.02723031417443 267 | 0.72849239295540 0.00839477740996 0.02723031417443 268 | 0.00839477740996 0.26311282963464 0.02723031417443 269 | 0.72849239295540 0.26311282963464 0.02723031417443 270 | 0.26311282963464 0.00839477740996 0.02723031417443 271 | 0.00839477740996 0.72849239295540 0.02723031417443]; 272 | 273 | else 274 | disp('Bad input n'); 275 | end 276 | return 277 | 278 | end -------------------------------------------------------------------------------- /scripts/bem_3d_functions/calc_singint.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_singint 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function analytically calculates the Green's function 32 | % (single layer potential) between a right triangular boundary element and 33 | % a point that is located at the center of mass of that triangle. The 34 | % function breaks up the integration into three segments corresponding to 35 | % three vertices and evaluates the integral. Specifically, it uses a radial 36 | % transform of coordinates that takes the location of the singularity to be 37 | % at r=0 38 | % 39 | % 40 | % Inputs: 41 | % r1, r2, r3 - vertices of the triangle 42 | % p - center of mass of the triangle 43 | % 44 | % Outputs: 45 | % Gxx ... Gzz: Nine components of the single layer potential 46 | % 47 | % References: I derived the analytic expression for each of the three 48 | % segments of the triangle. I could not find any references that published 49 | % the form here 50 | 51 | function [Gxx,Gxy,Gxz,Gyx,Gyy,Gyz,Gzx,Gzy,Gzz] = calc_singint(p,r1,r2,r3) 52 | 53 | % First we need to calculate a few properties of the triangle, including the 54 | % lengths of the sides, the vector between the center of mass and each 55 | % point 56 | s12=norm(r1-r2); 57 | s13=norm(r1-r3); 58 | s23=norm(r2-r3); 59 | Avec=r1-p; 60 | Bvec=r2-p; 61 | Cvec=r3-p; 62 | A=norm(Avec); 63 | B=norm(Bvec); 64 | C=norm(Cvec); 65 | 66 | % check clockwise versus counterclockwise orientation of triangle. If it is 67 | % oriented clockwise, we need to reverse direction of integration. 68 | c1=cross([r2-r1;0],[r3-r1;0]); 69 | 70 | % get our angular limits of integration 71 | theta01=atan2(Avec(2),Avec(1)); 72 | theta02=atan2(Bvec(2),Bvec(1)); 73 | theta03=atan2(Cvec(2),Cvec(1)); 74 | arc1=theta02-theta01; 75 | if abs(arc1)>pi 76 | arc1=abs(abs(arc1)-2*pi); 77 | else 78 | arc1=abs(arc1); 79 | end 80 | 81 | arc2=theta03-theta02; 82 | 83 | if abs(arc2)>pi 84 | arc2=abs(abs(arc2)-2*pi); 85 | else 86 | arc2=abs(arc2); 87 | end 88 | 89 | arc3=theta01-theta03; 90 | 91 | if abs(arc3)>pi 92 | arc3=abs(abs(arc3)-2*pi); 93 | else 94 | arc3=abs(arc3); 95 | end 96 | 97 | % use law of cosines to calculate angles of triangle 98 | thetaA1=acos((B^2+s12^2-A^2)/(2*B*s12)); 99 | thetaB1=acos((A^2+s12^2-B^2)/(2*A*s12)); 100 | thetaB2=acos((C^2+s23^2-B^2)/(2*C*s23)); 101 | thetaC2=acos((B^2+s23^2-C^2)/(2*B*s23)); 102 | thetaC3=acos((A^2+s13^2-C^2)/(2*A*s13)); 103 | thetaA3=acos((C^2+s13^2-A^2)/(2*C*s13)); 104 | 105 | %set limits of integration 106 | if c1(3)>0 107 | theta1s=theta01; 108 | theta2s=theta02; 109 | theta3s=theta03; 110 | theta1a=thetaB1; 111 | theta2a=thetaC2; 112 | theta3a=thetaA3; 113 | AA=A; 114 | BB=B; 115 | CC=C; 116 | else 117 | theta1s=theta02; 118 | theta2s=theta03; 119 | theta3s=theta01; 120 | theta1a=thetaA1; 121 | theta2a=thetaB2; 122 | theta3a=thetaC3; 123 | AA=B; 124 | BB=C; 125 | CC=A; 126 | end 127 | 128 | %evaluate integrals analytically we have to compute each of the vectorial 129 | %components (coupling xx, xy, xz etc.). Amongst each component, each 130 | %integral consists of three segments, arising from the three sides of the 131 | %triangle 132 | funintxy= @(phi,A,b,phi0) 1/2*A*sin(b)*((log(cos(1/2*(b-phi0+phi))) ... 133 | -log(sin(1/2*(b-phi0+phi))))*sin(2*(b-phi0))-2*sin(b-phi0-phi)); 134 | intxy=feval(funintxy,theta1s+arc1,AA,theta1a,theta1s)- feval(funintxy,theta1s,AA,theta1a,theta1s) ... 135 | + feval(funintxy,theta2s+arc2,BB,theta2a,theta2s)- feval(funintxy,theta2s,BB,theta2a,theta2s) ... 136 | + feval(funintxy,theta3s+arc3,CC,theta3a,theta3s)- feval(funintxy,theta3s,CC,theta3a,theta3s); 137 | 138 | funintxx= @(phi,A,b,phi0) A*sin(b)*(cos(b - phi0)*cos(phi) + ... 139 | cos(b - phi0).^2*(-log(cos(1/2*(b - phi0 + phi))) + ... 140 | log(sin(1/2*(b - phi0 + phi)))) + sin(b - phi0)*sin(phi)); 141 | intxx=feval(funintxx,theta1s+arc1,AA,theta1a,theta1s)- feval(funintxx,theta1s,AA,theta1a,theta1s) ... 142 | + feval(funintxx,theta2s+arc2,BB,theta2a,theta2s)- feval(funintxx,theta2s,BB,theta2a,theta2s) ... 143 | + feval(funintxx,theta3s+arc3,CC,theta3a,theta3s)- feval(funintxx,theta3s,CC,theta3a,theta3s); 144 | 145 | funintyy= @(phi,A,b,phi0) 1/2*A*sin(b)*(-2*cos(b - phi - phi0) + ... 146 | 2*(-log(cos(1/2*(b + phi - phi0))) + ... 147 | log(sin(1/2*(b + phi - phi0))))*sin(b - phi0)^2); 148 | intyy=feval(funintyy,theta1s+arc1,AA,theta1a,theta1s)- feval(funintyy,theta1s,AA,theta1a,theta1s) ... 149 | + feval(funintyy,theta2s+arc2,BB,theta2a,theta2s)- feval(funintyy,theta2s,BB,theta2a,theta2s) ... 150 | + feval(funintyy,theta3s+arc3,CC,theta3a,theta3s)- feval(funintyy,theta3s,CC,theta3a,theta3s); 151 | 152 | funintr= @(phi,A,b,phi0) A*(-log(cos(1/2*(b + phi - phi0))) ... 153 | + log(sin(1/2*(b + phi - phi0))))*sin(b); 154 | intr=feval(funintr,theta1s+arc1,AA,theta1a,theta1s)- feval(funintr,theta1s,AA,theta1a,theta1s) ... 155 | + feval(funintr,theta2s+arc2,BB,theta2a,theta2s)- feval(funintr,theta2s,BB,theta2a,theta2s) ... 156 | + feval(funintr,theta3s+arc3,CC,theta3a,theta3s)- feval(funintr,theta3s,CC,theta3a,theta3s); 157 | 158 | intzz=0; 159 | intyz=0; 160 | intxz=0; 161 | 162 | % Get matrix coefficients based on Gij = dij/r + xi xj/r^3 163 | Gxx=intxx+intr; 164 | Gxy=intxy; 165 | Gxz=intxz; 166 | Gyx=intxy; 167 | Gyy=intyy+intr; 168 | Gyz=intyz; 169 | Gzx=intxz; 170 | Gzy=intxz; 171 | Gzz=intzz+intr; 172 | 173 | 174 | end -------------------------------------------------------------------------------- /scripts/bem_3d_functions/generateBC_BEM_3D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: generateBC_BEM_3D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function generates the boundary points and boundary 32 | % conditions for the cavity driven fluid flow. There are several options 33 | % for input 34 | % 35 | % Inputs: 36 | % BCType - type of boundary conditions, either traction or velocity 37 | % boundundbound - set as bound or unbound. The unbound (open) geometry consists 38 | % of only a single horizontal surface, with fluid free to circulate 39 | % elsewhere. The bound (closed) geometry is a rectangular cavity 40 | % corner1, corner2 - these two points need to be 3D coordinates that give 41 | % the bottom front left and top back right boundary of the cuboid cavity. In the 42 | % case of the unbound condition, they will also define the limits where 43 | % we compute our flow 44 | % nbc - number of boundary elements along each of the six walls of the 45 | % surface (total points will be nbc x 6 for closed geometry) 46 | % Ubound - set the speed (or traction) of the moving portion of the boundary 47 | % fos - fraction of surface of bottom wall that is moving or applying 48 | % traction to the fluid. fos = 1 means the entire wall moves 49 | % 50 | % Outputs: 51 | % vertpts - location of vertices of triangles of boundary elements 52 | % elemvert - vector to identify which vertices belong to which boundary element 53 | % p - location of points where boundary elements are evaluated; 54 | % bcx, bcy, bcz, bcu, bcv, bcw - values of boundary element points, both location and value of either velocity or traction; 55 | % alpha - index specifying at each of bcu, bcv, bcw whether it is a velocity or traction condition 56 | % normv - normal vector of each boundary element 57 | 58 | function [elemvert,vertpts,bcx,bcy,bcz,bcu,bcv,bcw,p,normv,alpha] = generateBC_BEM_3D(BCtype,boundunbound,corner1,corner2,nbc,Ubound,fos) 59 | 60 | nx=nbc; 61 | ny=nbc; 62 | nz=nbc; 63 | 64 | nxbot=nx; 65 | nybot=ny; 66 | 67 | switch boundunbound 68 | case 'bounded' 69 | % This function custom generates a mesh of triangles on 6 surfaces. The 70 | % mesh is generated by first creating a rectangular grid, then dividing 71 | % each rectangle on the grid into right triangles with grd2tri and trigrid_com_norm. 72 | % For computational convenience here, each rectangle that is bisected gets cut 73 | % into an A and B triangle, so we end up with two sets of triangles. This 74 | % distinction is important because the ordering of the points on the 75 | % triangle determines the direction of the normal vector. It also 76 | % eventually determines the direction of integration for analytic integrals 77 | % computed on the triangle. 78 | [xtop,ytop] = meshgrid(linspace(corner1(1),corner2(1),nx),linspace(corner1(2),corner2(2),ny)); 79 | ztop=ones(size(xtop))*corner2(3); 80 | [tritopA,tritopB]=grid2tri(ny,nx); %call grid2tri function to create two sets of triangles 81 | [yright,zright] = meshgrid(linspace(corner1(2),corner2(2),ny),linspace(corner1(3),corner2(3),nz)); 82 | xright=ones(size(yright))*corner2(1); 83 | [trirightA,trirightB]=grid2tri(nz,ny); 84 | [yleft,zleft] = meshgrid(linspace(corner1(2),corner2(2),ny),linspace(corner1(3),corner2(3),nz)); 85 | xleft=ones(size(yleft))*corner1(1); 86 | [trileftA,trileftB]=grid2tri(nz,ny,2); 87 | [xback,zback] = meshgrid(linspace(corner1(1),corner2(1),nx),linspace(corner1(3),corner2(3),nz)); 88 | yback=ones(size(xback))*corner1(2); 89 | [tribackA,tribackB]=grid2tri(nz,nx); 90 | [xfront,zfront] = meshgrid(linspace(corner1(1),corner2(1),nx),linspace(corner1(3),corner2(3),nz)); 91 | yfront=ones(size(xfront))*corner2(2); 92 | [trifrontA,trifrontB]=grid2tri(nz,nx,2); 93 | [xbot,ybot] = meshgrid(linspace(corner1(1),corner2(1),nxbot),linspace(corner1(2),corner2(2),nybot)); 94 | zbot=ones(size(xbot))*corner1(3); 95 | [tribotA,tribotB]=grid2tri(nybot,nxbot,2); 96 | 97 | % trigrid_com_norm calculates the normal vector and center of mass of each 98 | % of the triangles. The output of grid2tri contains indices but not 99 | % absolute coordinates, so triggrid_com_norm incorporates the actual mesh 100 | % location 101 | [normbackA,combackA]=trigrid_com_norm(tribackA,xback,yback,zback); 102 | [normbackB,combackB]=trigrid_com_norm(tribackB,xback,yback,zback); 103 | [normfrontA,comfrontA]=trigrid_com_norm(trifrontA,xfront,yfront,zfront); 104 | [normfrontB,comfrontB]=trigrid_com_norm(trifrontB,xfront,yfront,zfront); 105 | [normtopA,comtopA]=trigrid_com_norm(tritopA,xtop,ytop,ztop); 106 | [normtopB,comtopB]=trigrid_com_norm(tritopB,xtop,ytop,ztop); 107 | [normbotA,combotA]=trigrid_com_norm(tribotA,xbot,ybot,zbot); 108 | [normbotB,combotB]=trigrid_com_norm(tribotB,xbot,ybot,zbot); 109 | [normleftA,comleftA]=trigrid_com_norm(trileftA,xleft,yleft,zleft); 110 | [normleftB,comleftB]=trigrid_com_norm(trileftB,xleft,yleft,zleft); 111 | [normrightA,comrightA]=trigrid_com_norm(trirightA,xright,yright,zright); 112 | [normrightB,comrightB]=trigrid_com_norm(trirightB,xright,yright,zright); 113 | 114 | % generate boundary conditions 115 | bctop=zeros(size(xtop,1)-1,size(xtop,2)-1,3); 116 | bcleft=zeros(size(xleft,1)-1,size(xleft,2)-1,3); 117 | bcright=zeros(size(xright,1)-1,size(xright,2)-1,3); 118 | bcfront=zeros(size(xfront,1)-1,size(xfront,2)-1,3); 119 | bcback=zeros(size(xback,1)-1,size(xback,2)-1,3); 120 | 121 | velboundleft=max(round((nxbot)*(1/2-fos/2)),1); 122 | velboundright=min(round((nxbot)*(1/2+fos/2)),size(xbot,2)-1); 123 | velboundback=max(round((nybot)*(1/2-fos/2)),1); 124 | velboundfront=min(round((nybot)*(1/2+fos/2)),size(xbot,1)-1); 125 | 126 | 127 | movingwallx=(velboundleft:velboundright); 128 | movingwally=(velboundback:velboundfront); 129 | bcbot=zeros(size(xbot,1)-1,size(xbot,2)-1,3); 130 | bcbot(movingwally,movingwallx,1)=Ubound; 131 | 132 | % We have to re order everything. By convention, we always do bottom, 133 | % top, left, right, back, front 134 | bctot_ordered=[reshape(bcbot(:,:,1),[],1),reshape(bcbot(:,:,2),[],1),reshape(bcbot(:,:,3),[],1); ... 135 | reshape(bcbot(:,:,1),[],1),reshape(bcbot(:,:,2),[],1),reshape(bcbot(:,:,3),[],1); ... 136 | reshape(bctop(:,:,1),[],1),reshape(bctop(:,:,2),[],1),reshape(bctop(:,:,3),[],1); ... 137 | reshape(bctop(:,:,1),[],1),reshape(bctop(:,:,2),[],1),reshape(bctop(:,:,3),[],1); ... 138 | reshape(bcleft(:,:,1),[],1),reshape(bcleft(:,:,2),[],1),reshape(bcleft(:,:,3),[],1); ... 139 | reshape(bcleft(:,:,1),[],1),reshape(bcleft(:,:,2),[],1),reshape(bcleft(:,:,3),[],1); ... 140 | reshape(bcright(:,:,1),[],1),reshape(bcright(:,:,2),[],1),reshape(bcright(:,:,3),[],1); ... 141 | reshape(bcright(:,:,1),[],1),reshape(bcright(:,:,2),[],1),reshape(bcright(:,:,3),[],1); ... 142 | reshape(bcback(:,:,1),[],1),reshape(bcback(:,:,2),[],1),reshape(bcback(:,:,3),[],1); ... 143 | reshape(bcback(:,:,1),[],1),reshape(bcback(:,:,2),[],1),reshape(bcback(:,:,3),[],1); ... 144 | reshape(bcfront(:,:,1),[],1),reshape(bcfront(:,:,2),[],1),reshape(bcfront(:,:,3),[],1); ... 145 | reshape(bcfront(:,:,1),[],1),reshape(bcfront(:,:,2),[],1),reshape(bcfront(:,:,3),[],1); ... 146 | ]; 147 | 148 | bcu=bctot_ordered(:,1); 149 | bcv=bctot_ordered(:,2); 150 | bcw=bctot_ordered(:,3); 151 | 152 | %Give a unique ordering to our vertex points 153 | vertpts=[xbot(:),ybot(:),zbot(:);xtop(:),ytop(:),ztop(:);... 154 | xleft(:),yleft(:),zleft(:);xright(:),yright(:),zright(:);... 155 | xback(:),yback(:),zback(:);xfront(:),yfront(:),zfront(:)]; 156 | nptbot=nxbot*nybot; 157 | npttop=nx*ny; 158 | nptleft=ny*nz; 159 | nptback=nx*nz; 160 | shift1=nptbot; 161 | shift2=shift1+npttop; 162 | shift3=shift2+nptleft; 163 | shift4=shift3+nptleft; 164 | shift5=shift4+nptback; 165 | 166 | % Index our triangles, now putting back together A and B 167 | elemvert=[tribotA;tribotB;tritopA+shift1;tritopB+shift1;... 168 | trileftA+shift2;trileftB+shift2;trirightA+shift3;trirightB+shift3;... 169 | tribackA+shift4;tribackB+shift4;trifrontA+shift5;trifrontB+shift5]; 170 | p=[combotA;combotB;comtopA;comtopB;... 171 | comleftA;comleftB;comrightA;comrightB;... 172 | combackA;combackB;comfrontA;comfrontB]; 173 | bcx=p(:,1); 174 | bcy=p(:,2); 175 | bcz=p(:,3); 176 | 177 | normv=[normbotA;normbotB;normtopA;normtopB;... 178 | normleftA;normleftB;normrightA;normrightB;... 179 | normbackA;normbackB;normfrontA;normfrontB]; 180 | 181 | case 'unbounded' 182 | % This function custom generates a mesh of triangles on only the bottom surface. 183 | % The mesh is generated by first creating a rectangular grid, then dividing 184 | % each rectangle on the grid into right triangles with grd2tri. For 185 | % computational convenience here, each rectangle that is bisected gets cut 186 | % into an A and B triangle, so we end up with two sets of triangles. This 187 | % distinction is important because the ordering of the points on the 188 | % triangle determines the direction of the normal vector. It also 189 | % eventually determines the direction of integration for analytic integrals 190 | % computed on the triangle. 191 | 192 | 193 | [xbot,ybot] = meshgrid(linspace(corner1(1),corner2(1),nxbot),linspace(corner1(2),corner2(2),nybot)); 194 | zbot=ones(size(xbot))*corner1(3); 195 | [tribotA,tribotB]=grid2tri(nybot,nxbot,2); 196 | 197 | % trigrid_com_norm calculates the normal vector and center of mass of each 198 | % of the triangles. 199 | [normbotA,combotA]=trigrid_com_norm(tribotA,xbot,ybot,zbot); 200 | [normbotB,combotB]=trigrid_com_norm(tribotB,xbot,ybot,zbot); 201 | velboundleft=max(round((nxbot-1)*(1/2-fos/2)),1); 202 | velboundright=min(round((nxbot-1)*(1/2+fos/2)),size(xbot,2)-1); 203 | velboundback=max(round((nybot-1)*(1/2-fos/2)),1); 204 | velboundfront=min(round((nybot-1)*(1/2+fos/2)),size(xbot,1)-1); 205 | movingwallx=(velboundleft:velboundright); 206 | movingwally=(velboundback:velboundfront); 207 | bcbot=zeros(size(xbot,1)-1,size(xbot,2)-1,3); 208 | bcbot(movingwally,movingwallx,1)=Ubound; 209 | 210 | % Re-order our boundary conditions 211 | bctot_ordered=[reshape(bcbot(:,:,1),[],1),reshape(bcbot(:,:,2),[],1),reshape(bcbot(:,:,3),[],1); ... 212 | reshape(bcbot(:,:,1),[],1),reshape(bcbot(:,:,2),[],1),reshape(bcbot(:,:,3),[],1)]; 213 | bcu=bctot_ordered(:,1); 214 | bcv=bctot_ordered(:,2); 215 | bcw=bctot_ordered(:,3); 216 | 217 | %Give a unique ordering to our vertex points 218 | vertpts=[xbot(:),ybot(:),zbot(:)]; 219 | elemvert=[tribotA;tribotB]; 220 | p=[combotA;combotB]; 221 | bcx=p(:,1); 222 | bcy=p(:,2); 223 | bcz=p(:,3); 224 | normv=[normbotA;normbotB]; 225 | 226 | end 227 | 228 | % now we calculate alpha, which assigns a value to each boundary element 229 | % stating whether that element specifies a velocity or traction boundary 230 | % condition. Notably, we may specify the z-direction as flow (impenetrable 231 | % wall), but specify the x and y-direction as traction 232 | 233 | switch BCtype 234 | case 'velocity' 235 | alpha=false(size(bctot_ordered)); 236 | alpha=[alpha(:,1);alpha(:,2);alpha(:,3)]; 237 | case 'traction' 238 | alpha=false(size(bctot_ordered)); 239 | alpha(bctot_ordered~=0)=true; 240 | alpha=[alpha(:,1);alpha(:,2);alpha(:,3)]; 241 | end 242 | 243 | end -------------------------------------------------------------------------------- /scripts/bem_3d_functions/grid2tri.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: grid2tri 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function takes rectangular grid defined by the number 32 | % of points along each dimension (nx = s1, ny = s2) rectangle into two right triangles 33 | % (upper right (ur) and bottom left (bl)). It attempts to orient both ur and 34 | % bl triangles such that the surfaces both have normals oriented in the same 35 | % direction. 36 | % 37 | % Inputs: 38 | % s1, s2 - number of x and y points in each dimension 39 | % optional: flipnorm - in case the normal vector is oriented in the wrong direction 40 | % (i.e. facing out of the cube), flipnorm reverses the direction of the 41 | % unit normal vector 42 | % 43 | % Outputs: 44 | % tribl, triur: bottom left and upper right triangles consisting of the 45 | % indices to take from a mesh grid. 46 | 47 | function [tribl,triur] = grid2tri(s1,s2,flipnorm) 48 | if nargin==2 49 | flipnorm=1; 50 | end 51 | 52 | 53 | tribl=zeros((s1-1)*(s2-1),3); 54 | triur=zeros((s1-1)*(s2-1),3); 55 | i3=1; 56 | for i1=1:s1-1 57 | for i2=1:s2-1 58 | tribl(i3,1)=sub2ind([s1,s2],i1,i2); 59 | tribl(i3,2)=sub2ind([s1,s2],i1+1,i2); 60 | tribl(i3,3)=sub2ind([s1,s2],i1,i2+1); 61 | triur(i3,2)=sub2ind([s1,s2],i1+1,i2); 62 | triur(i3,1)=sub2ind([s1,s2],i1,i2+1); 63 | triur(i3,3)=sub2ind([s1,s2],i1+1,i2+1); 64 | i3=i3+1; 65 | end 66 | end 67 | if flipnorm==2 68 | triur=[triur(:,2),triur(:,1),triur(:,3)]; 69 | tribl=[tribl(:,2),tribl(:,1),tribl(:,3)]; 70 | end 71 | 72 | end 73 | -------------------------------------------------------------------------------- /scripts/bem_3d_functions/trigrid_com_norm.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: trigrid_com_norm 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function takes the coordinates of a mesh grid and the 32 | % output of the grid2tri function (specifying indices) and returns the 33 | % center of mass as well as the normal vector of the triangles generated on 34 | % the grid 35 | % 36 | % Inputs: 37 | % tri - indexing output of tri2grid 38 | % xcoor, ycoor, zcoor - meshgrid at all locations, split up into x, y, and 39 | % z coordinates 40 | % 41 | % Outputs: 42 | % normd - unit normal vector of each triangle 43 | % com - center of mass of each triangle. The center of mass will be used as 44 | % our points to evaluate on the each boundary element 45 | 46 | function [normd,com] = trigrid_com_norm(tri,xcoor,ycoor,zcoor) 47 | com=zeros(size(tri)); 48 | 49 | com(:,1)=mean([xcoor(tri(:,1)) , xcoor(tri(:,2)), xcoor(tri(:,3))],2); 50 | com(:,2)=mean([ycoor(tri(:,1)) , ycoor(tri(:,2)), ycoor(tri(:,3))],2); 51 | com(:,3)=mean([zcoor(tri(:,1)) , zcoor(tri(:,2)), zcoor(tri(:,3))],2); 52 | 53 | qa=[xcoor(tri(:,1)),ycoor(tri(:,1)),zcoor(tri(:,1))]; 54 | qb=[xcoor(tri(:,2)),ycoor(tri(:,2)),zcoor(tri(:,2))]; 55 | qc=[xcoor(tri(:,3)),ycoor(tri(:,3)),zcoor(tri(:,3))]; 56 | 57 | u=qb-qa; 58 | v=qc-qa; 59 | Nx=u(:,2).*v(:,3)-u(:,3).*v(:,2); 60 | Ny=u(:,3).*v(:,1)-u(:,1).*v(:,3); 61 | Nz=u(:,1).*v(:,2)-u(:,2).*v(:,1); 62 | mag=sqrt(Nx.^2+Ny.^2+Nz.^2); 63 | normd=[Nx./mag,Ny./mag,Nz./mag]; 64 | 65 | 66 | 67 | end -------------------------------------------------------------------------------- /scripts/doit_sim_BEM_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: doit_sim_BEM_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This doit script runs a simulation of a 2D lid-driven 32 | % cavity using the boundary element method (BEM). 33 | % 34 | % 35 | % Inputs: 36 | % BCType - type of boundary conditions, either traction or velocity 37 | % boundundbound - set as bound or unbound. The unbound (open) geometry consists 38 | % of only a single horizontal surface, with fluid free to circulate 39 | % elsewhere. The bound (closed) geometry is a rectangular cavity 40 | % corner1, corner2 - these two points need to be 2d coordinates that give 41 | % the lower left and upper right boundary of the rectangular cavity. In the 42 | % case of the unbound condition, they will also define where we calculate 43 | % our flow 44 | % nbc - number of boundary elements along each of the four walls of the 45 | % surface (total points will be nbc x 4 for closed geometry) 46 | % Ubound - set the speed (or traction) of the moving portion of the boundary 47 | % fos - fraction of surface of bottom wall that is moving or applying 48 | % traction to the fluid. fos = 1 means the entire wall moves 49 | % xpts, ypts: number of points in the x and y direction to be evaluated on 50 | % the interior of the domain for flow 51 | % visc - the viscosity of the fluid is required to relate traction to flow 52 | % 53 | % Outputs: 54 | % xint,yint: grid of x,y coordinates where flow is evaluated 55 | % u,v: flow vector at locations xint, yint 56 | % bcx,bcy: location of centers of boundary elements 57 | % ub,vb: flow vector of boundary elements 58 | % fx,fy: traction at boundary elements 59 | % 60 | % 61 | %% Specify the inputs as detailed in the script description 62 | corner1=[0,0]; 63 | corner2=[0.25,0.125]; 64 | xpts=20; 65 | ypts=10; 66 | numbc=40; 67 | Uspeed=10; 68 | fos=0.8; 69 | visc=1; 70 | %% Generate the geometry and boundary conditions of the flow 71 | [elemvert,vertpts,bcx,bcy,bcu,bcv,p,normv,alpha] = generateBC_BEM_2D('traction','bounded',corner1,corner2,numbc,Uspeed,fos); 72 | %% Plot the location of the boundary points to check 73 | 74 | dx=corner2(1)-corner1(1); 75 | dy=corner2(2)-corner1(2); 76 | figure(1);plot(p(:,1),p(:,2),'x',vertpts(:,1),vertpts(:,2)) 77 | xlim([corner1(1)-0.1*dx corner2(1)+0.1*dy]); 78 | ylim([corner1(2)-0.1*dy corner2(2)+0.1*dy]); 79 | title('Plot of boundaries of problems, with x marking center of each boundary element') 80 | xlabel('x coord') 81 | ylabel('y coord') 82 | %% Calculate the Green's Function matrix (single and double layer potential) 83 | tic 84 | [SLmat,DLmat]=calc_Amat_BEM_2D(p,vertpts,elemvert,normv,true); 85 | toc 86 | %% Solve the boundary integral equation (see tutorial Eq. 41) 87 | BCtotal=[bcu;bcv]; 88 | [u0,f0,ub,vb,fx,fy] = solve_mixedBC(SLmat,DLmat,BCtotal,visc,alpha,'2D'); 89 | 90 | %% Generate a grid over the points we would like to evaluate in the domain 91 | % High shearing occurs near the corners, so numerical errors are increased 92 | % in those locations. The last parameter gives how close to these corners 93 | % we would like to calculate 94 | [xint,yint]=InteriorPts_2D(corner1,corner2,xpts,ypts,0.95); 95 | intpts=[xint(:),yint(:)]; 96 | 97 | %% Calculate the single and double layer potential effects on the interior points 98 | tic 99 | [SLint,DLint]=calc_Amat_BEM_2D(intpts,vertpts,elemvert,normv,false); 100 | toc 101 | %% Calculate the pressure and shear stress single and double layer potentials 102 | [PSLint,PDLint,SSLint,SDLint]=calc_PSmat_BEM_2D(intpts,vertpts,elemvert,normv,false); 103 | 104 | %% Calculate the flow field u, v, option to also calculate the pressure and shear stress tensors 105 | %[u,v] = calcUV_BEM(f0,u0,SLint,DLint,xpts,ypts,visc); 106 | %[u,v,pres] = calcUV_BEM(f0,u0,SLint,DLint,xpts,ypts,visc,PSLint,PDLint); 107 | [u,v,pres,stress]=calcUV_BEM_2D(f0,u0,SLint,DLint,xpts,ypts,visc,PSLint,PDLint,SSLint,SDLint); 108 | 109 | %% Plot the flow field and boundary conditions 110 | vis2Dfield_quiver(xint,yint,u,v,bcx,bcy,ub,vb,2); -------------------------------------------------------------------------------- /scripts/doit_sim_BEM_3D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: doit_sim_BEM_3D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This doit script runs a simulation of a 3D lid-driven 32 | % cavity using the boundary element method (BEM). 33 | % 34 | % 35 | % Inputs: 36 | % BCType - type of boundary conditions, either traction or velocity 37 | % boundundbound - set as bound or unbound. The unbound (open) geometry consists 38 | % of only a single horizontal surface, with fluid free to circulate 39 | % elsewhere. The bound (closed) geometry is a rectangular cavity 40 | % corner1, corner2 - these two points need to be 3D coordinates that give 41 | % the bottom front left and top back right boundary of the cuboid cavity. In the 42 | % case of the unbound condition, they will also define the limeits we calculate our flow 43 | % nbc - number of boundary elements along each of the four walls of the 44 | % surface (total points will be nbc x 6 for closed geometry) 45 | % Ubound - set the speed (or traction) of the moving portion of the boundary 46 | % fos - fraction of surface of bottom wall that is moving or applying 47 | % traction to the fluid. fos = 1 means the entire wall moves 48 | % xpts, ypts: number of points in the x and y direction to be evaluated on 49 | % the interior of the domain for flow 50 | % visc - the viscosity of the fluid is required to relate traction to flow 51 | % 52 | % Outputs: 53 | % xint,yint: grid of x,y coordinates where flow is evaluated 54 | % u,v: flow vector at locations xint, yint 55 | % bcx,bcy: location of centers of boundary elements 56 | % ub,vb: flow vector of boundary elements 57 | % fx,fy: traction at boundary elements 58 | % 59 | % 60 | %% Define basic parameters of simulation 61 | corner1=[-5,-5,0]; % bottom left corner of cube where flow will be simulated 62 | corner2=[5,5,5]; % top right corner of cube 63 | xpts=6; % number of x, y, and z pts to simulate in interior 64 | ypts=6; 65 | zpts=3; 66 | numbc=5; % size of mesh 67 | Uspeed=1; % either speed or traction at boundary 68 | fos=0.2; % fraction of surface that is "moving" 69 | visc=1; % viscosity of the fluid 70 | 71 | %% generate boundary conditions and geometry 72 | % triangular mesh, consisting of vertpts (locations of triangle vertices) 73 | % and elemvert (describes the vertices of each triangle), as well as 74 | % boundary conditions (specifying 'velocity' or 'traction' [mixed]), center 75 | % points of the triangle p, normal vectors at those locations, and the 76 | % alpha vector, which denotes which boundary points are velocity, and which 77 | % are traction 78 | % 79 | [elemvert,vertpts,bcx,bcy,bcz,bcu,bcv,bcw,p,normv,alpha] = generateBC_BEM_3D('traction','bounded',corner1,corner2,numbc,Uspeed,fos); 80 | %% plot the mesh as well as the normal vectors to double check that everything looks kosher 81 | % For the closed domain, the normal vectors should all be pointing inward 82 | % to the cube. 83 | figure(1);trimesh(elemvert,vertpts(:,1),vertpts(:,2),vertpts(:,3)); 84 | title('Mesh of boundary') 85 | figure(2);quiver3(p(:,1),p(:,2),p(:,3),normv(:,1),normv(:,2),normv(:,3)); 86 | title('Normal vectors of each element, plotted at location of element') 87 | %% calculate the single and double layer potential (i.e. susceptibility matrix) 88 | % between each element on the boundary boundary. Special algorithms are 89 | % required when calculating susceptibility between an element and itself (singular), 90 | % and ponq denotes that we are considering singular points 91 | tic 92 | [SLmat,DLmat]=calc_Amat_BEM_3D(p,vertpts,elemvert,normv,true); 93 | toc 94 | %% solve the boundary integral equation (see tutorial Eq. 41) 95 | % solve_mixedBC will solve the Fredholm integral of the first kind for 96 | % velocity. If the boundary conditions are mixed, it will swap out the 97 | % unknown velocities for known stresses and will end up still solving the 98 | % Fredholm integral. Robin conditions are possible to solve but 99 | % not addressed here. f0 is the force at the boundary (3 components each), 100 | % while u0 is the velocity at the boundary (3 components each). 101 | BCtotal=[bcu;bcv;bcw]; 102 | [u0,f0,ub,vb,wb,fx,fy,fz] = solve_mixedBC(SLmat,DLmat,BCtotal,visc,alpha,'3D'); 103 | %% define a 3D grid where you want to evaluate the fluid in the box 104 | 105 | [xint,yint,zint]=InteriorPts_3D(corner1,corner2,xpts,ypts,zpts,0.90); 106 | intpts=[xint(:),yint(:),zint(:)]; 107 | %% Calulate pressure and stress susceptibility matrices 108 | % both single layer and double layer potentials for each 109 | % PSL = pressure single layer, PDL = pressure double layer 110 | % SSL = stress single layer, SDL = stress double layer 111 | [PSLint,PDLint,SSLint,SDLint]=calc_PSmat_BEM_3D(intpts,vertpts,elemvert,normv,false); 112 | 113 | %% Calulate single and double layer potential for flow for interior points 114 | tic 115 | [SLint,DLint]=calc_Amat_BEM_3D(intpts,vertpts,elemvert,normv,false); 116 | toc 117 | %% Plug these back into the boundary integral equations to evaluate 118 | % flow field, pressure, and shear stress tensor at interior points 119 | % because stress tensor is 3x3, it has been collapsed into a single tensor, 120 | % while the 1x3 velocity vector is given as separate components 121 | 122 | [u,v,w] = calcUV_BEM_3D(f0,u0,SLint,DLint,xpts,ypts,zpts,visc); 123 | %[u,v,w,pres] = calcUV_BEM_3D(f0,u0,SLint,DLint,xpts,ypts,zpts,visc,PSLint,PDLint); 124 | %[u,v,w,pres,stress] = calcUV_BEM_3D(f0,u0,SLint,DLint,xpts,ypts,zpts,visc,PSLint,PDLint,SSLint,SDLint); 125 | 126 | %% Visualize flow field 127 | vis3Dfield_cube(corner1,corner2,xint,yint,zint,u,v,w,bcx,bcy,bcz,ub,vb,wb,vertpts,elemvert) 128 | -------------------------------------------------------------------------------- /scripts/doit_sim_MFS_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: doit_sim_MFS_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This doit script runs a simulation of a 2D lid-driven 32 | % cavity using the method of fundamental solutions (MFS). 33 | % 34 | % 35 | % Inputs: 36 | % boundundbound - set as bounded or unbounded. The unbound (open) geometry consists 37 | % of only a single horizontal surface, with fluid free to circulate 38 | % elsewhere. The bound (closed) geometry is a rectangular cavity 39 | % corner1, corner2 - these two points need to be 2d coordinates that give 40 | % the lower left and upper right boundary of the rectangular cavity. In the 41 | % case of the unbound condition, they will also define where we calculate 42 | % our flow 43 | % nbc - number of boundary points / stokeslets along each of the four walls of the 44 | % surface (total points will be nbc x 4 for closed geometry) that we will 45 | % evalute 46 | % Ubound - set the speed of the moving portion of the boundary. Traction 47 | % currently not implemented 48 | % fos - fraction of surface of bottom wall that is moving or applying 49 | % traction to the fluid. fos = 1 means the entire wall moves 50 | % xpts, ypts: number of points in the x and y direction to be evaluated on 51 | % the interior of the domain for flow 52 | % visc - the viscosity of the fluid is required to relate traction to flow 53 | % 54 | % Outputs: 55 | % xint,yint: grid of x,y coordinates where flow is evaluated 56 | % u,v: flow vector at locations xint, yint 57 | % bcx,bcy: location of centers of boundary elements 58 | % bcu,bcv: flow vector of boundary elements 59 | % 60 | % 61 | %% Specify the inputs as detailed in the script description 62 | corner1=[0,0]; 63 | corner2=[1,1]; 64 | xpts=20; 65 | ypts=20; 66 | numbc=20; 67 | b=0.01; 68 | Uspeed=10; 69 | fos=0.5; 70 | %% Generate the geometry and boundary conditions of the flow 71 | [scx,scy,bcx,bcy,bcu,bcv]=generateBC_MFS_2D(1,'bounded',corner1,corner2,numbc,b,Uspeed,fos); 72 | 73 | %% Calculate the Green's Function matrix 74 | Amat=calc_Amat_MFS_2D(bcx,bcy,scx,scy); 75 | BCtotal=transpose([bcu,bcv]); 76 | 77 | %% Solve the inverse equation (see tutorial Eq. 14) 78 | qcoeff=inv(Amat)*BCtotal; 79 | %% Generate a grid over the points we would like to evaluate in the domain 80 | % High shearing occurs near the corners, so numerical errors are increased 81 | % in those locations. The last parameter gives how close to these corners 82 | % we would like to calculate 83 | [xint,yint]=InteriorPts_2D(corner1,corner2,xpts,ypts,0.95); 84 | 85 | %% Calculate the flow, pressure, and stream function Green's functions on the interior 86 | [Aint,Pint,Psiint]=calc_Amat_MFS_2D(transpose(xint(:)),transpose(yint(:)),scx,scy); 87 | 88 | %% Compute the flow field, pressure, and stream function 89 | [u,v] = calcUV_MFS_2D(qcoeff,Aint,xpts,ypts); 90 | press = calcPPsi_MFS_2D(qcoeff,Pint,xpts,ypts); 91 | psi= calcPPsi_MFS_2D(qcoeff,Psiint,xpts,ypts); 92 | 93 | %% Plot the flow field, streamlines, and boundary conditions 94 | vis2Dfield_quiver(xint,yint,u,v,bcx,bcy,bcu,bcv,1); 95 | vis2Dfield_streamline(xint,yint,psi,bcx,bcy,bcu,bcv,2) 96 | -------------------------------------------------------------------------------- /scripts/mfs_2d_functions/calcPPsi_MFS_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calcPPsi_MFS_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function estimates either the streamfunction or 32 | % pressure field by computing the forward equation in MFS 33 | % 34 | % Inputs: 35 | % qcoeff - strength / coefficients of stokeslets 36 | % Pint - flow Green's function / susceptibility matrix for either pressure 37 | % or streamfunction 38 | % xpts, ypts - number of xpts and y pts in the interior grid to calculate 39 | % Note this must be the same as the xpts, ypts used to calculate the 40 | % original Amat 41 | % 42 | % 43 | % Outputs: 44 | % p - field for either pressure or streamfunction 45 | 46 | function p = calcPPsi_MFS_2D(qcoeff,Pint,xpts,ypts) 47 | 48 | ptot=Pint*qcoeff; 49 | [xgrid,ygrid]=meshgrid(linspace(1,xpts,xpts),linspace(1,ypts,ypts)); 50 | 51 | p=accumarray([ygrid(:),xgrid(:)],ptot,[ypts xpts]); 52 | 53 | end -------------------------------------------------------------------------------- /scripts/mfs_2d_functions/calcUV_MFS_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calcUV_MFS_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function estimates the flow field u and v 32 | % by computing the forward equation u = G f in the method of fundamental 33 | % solutions 34 | % 35 | % Inputs: 36 | % qcoeff - strength / coefficients of stokeslets 37 | % Amat - flow Green's function / susceptibility matrix 38 | % xpts, ypts - number of xpts and y pts in the interior grid to calculate 39 | % Note this must be the same as the xpts, ypts used to calculate the 40 | % original Amat 41 | % 42 | % 43 | % Outputs: 44 | % u,v - vectorial flow field 45 | 46 | function [u,v] = calcUV_MFS_2D(qcoeff,Amat,xpts,ypts) 47 | uvtot=Amat*qcoeff; % Calculate forward equation 48 | [xgrid,ygrid]=meshgrid(linspace(1,xpts,xpts),linspace(1,ypts,ypts)); 49 | u1=uvtot(1:xpts*ypts); 50 | v1=uvtot(xpts*ypts+1:end); 51 | 52 | u=accumarray([ygrid(:),xgrid(:)],u1,[ypts xpts]); 53 | v=accumarray([ygrid(:),xgrid(:)],v1,[ypts xpts]); 54 | end -------------------------------------------------------------------------------- /scripts/mfs_2d_functions/calc_Amat_MFS_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: calc_Amat_MFS_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function uses Green's functions in 2D to calculate 32 | % the coupling between boundary elements and points. It does so for flow, 33 | % pressure, and the streamfunction 34 | % 35 | % 36 | % Inputs: 37 | % boundarycoordx,boundarycoordy - location of boundary points 38 | % stokescoordx,stokescoordy - location of stokeslets 39 | % visc - viscosity 40 | % 41 | % Outputs: 42 | % Amat - Flow Green's function / susceptibility matrix 43 | % Optional Outputs: 44 | % Apres, Apsi - Pressure and streamfunction Green's functions / 45 | % susceptibility matrix 46 | 47 | function [Amat,Apres,Apsi] = calc_Amat_MFS_2D(boundarycoordx,boundarycoordy,stokescoordx,stokescoordy,visc) 48 | if nargin==4 49 | visc=1; 50 | end 51 | 52 | 53 | nstokes=numel(stokescoordx); 54 | npts=numel(boundarycoordx); 55 | 56 | % calculate displacement vector and distances between stokselets / points 57 | xij=transpose(repmat(boundarycoordx,nstokes,1))-repmat(stokescoordx,npts,1); 58 | yij=transpose(repmat(boundarycoordy,nstokes,1))-repmat(stokescoordy,npts,1); 59 | rij=(xij.^2+yij.^2).^0.5; 60 | 61 | % calculate the xx, xy, yx, yy components of the matrix 62 | fij=-2*log(rij)+2*(xij.^2).*(rij.^(-2))-3; 63 | gij=2*xij.*yij.*(rij.^(-2)); 64 | hij=2*xij.*yij.*(rij.^(-2)); 65 | kij=-2*log(rij)+2*(yij.^2).*(rij.^(-2))-3; 66 | 67 | % put all components back together. Note here, our Amat is slightly 68 | % different from our BEM matrix because it contains the factor 8 pi visc 69 | % already incorporated. Thus when we solve the inverse equation, we don't 70 | % need to weight by those factors. 71 | Amat=[fij, gij; hij, kij]/(8*pi*visc); 72 | 73 | % calculate the pressure Green's function matrix 74 | if nargout>1 75 | fpres=xij.*rij.^(-2); 76 | gpres=yij.*rij.^(-2); 77 | Apres=[fpres, gpres]/(2*pi); 78 | end 79 | 80 | % calculate the streamfunction Green's function matrix 81 | if nargout>2 82 | fpsi=-2*yij.*log(rij)-yij; 83 | gpsi=2*xij.*log(rij)-xij; 84 | Apsi=[fpsi,gpsi]/(8*pi*visc); 85 | end 86 | 87 | end 88 | -------------------------------------------------------------------------------- /scripts/mfs_2d_functions/generateBC_MFS_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: generateBC_MFS_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function generates the boundary points and boundary 32 | % conditions for the cavity driven fluid flow. 33 | % 34 | % Inputs: 35 | % boundundbound - set as bound or unbound. The unbound (open) geometry consists 36 | % of only a single horizontal surface, with fluid free to circulate 37 | % elsewhere. The bound (closed) geometry is a rectangular cavity 38 | % corner1, corner2 - these two points need to be 2d coordinates that give 39 | % the lower left and upper right boundary of the rectangular cavity. In the 40 | % case of the unbound condition, they will also define where we calculate 41 | % our flow 42 | % nbc - number of boundary elements along each of the four walls of the 43 | % surface (total points will be nbc x 4 for closed geometry) 44 | % Ubound - set the speed (or traction) of the moving portion of the boundary 45 | % b - how far away we would like to place the Stokeslets. In this script, 46 | % stokeslets are placed along the line between a boundary point and the 47 | % center of mass (com), at a distance dtermined by b 48 | % fos - fraction of surface of bottom wall that is moving or applying 49 | % traction to the fluid. fos = 1 means the entire wall moves 50 | % ploton - whether to plot the boundary points to review 51 | % 52 | % Outputs: 53 | % stokescoordx, stokesccordy - location of stokeslets (fictious forces) 54 | % bcxcoor, bcycoor, bcu, bcv - values of boundary element points, both location and value of either velocity or traction; 55 | 56 | function [stokescoordx,stokescoordy,bcxcoor,bcycoor,bcu,bcv] = generateBC_MFS_2D(ploton,boundunbound,corner1,corner2,nbc,b,Ubound,fos) 57 | 58 | if nargin==7 59 | fos = 1; 60 | end 61 | 62 | % calculate center of mass of rectangle 63 | com=[corner1(1)+corner2(1),corner1(2)+corner2(2)]/2; 64 | 65 | switch boundunbound 66 | case 'unbounded' 67 | bcxcoor = linspace(corner1(1),corner2(1),nbc); 68 | bcycoor = linspace(corner1(2),corner1(2),nbc); 69 | % define speed of moving boundary 70 | bcu= linspace(0,0,nbc); 71 | bcv= linspace(0,0,nbc); 72 | velboundleft=max(round(nbc*(1/2-fos/2)),2); 73 | velboundright=min(round(nbc*(1/2+fos/2)),nbc); 74 | bcu(velboundleft-1:velboundright)=Ubound; 75 | % place stokeslets at a fractional distance b 76 | stokescoordx=bcxcoor+b*(bcxcoor-com(1)); 77 | stokescoordy=bcycoor+b*(bcycoor-com(2)); 78 | case 'bounded' 79 | bxbot=linspace(corner1(1),corner2(1),nbc); 80 | bybot=linspace(corner1(2),corner1(2),nbc); 81 | bxright=linspace(corner2(1),corner2(1),nbc); 82 | byright=linspace(corner1(2),corner2(2),nbc); 83 | bxtop=linspace(corner2(1),corner1(1),nbc); 84 | bytop=linspace(corner2(2),corner2(2),nbc); 85 | bxleft=linspace(corner1(1),corner1(1),nbc); 86 | byleft=linspace(corner2(2),corner1(2),nbc); 87 | bxbot=bxbot(1:end-1);bybot=bybot(1:end-1); 88 | bxright=bxright(1:end-1);byright=byright(1:end-1); 89 | bxtop=bxtop(1:end-1);bytop=bytop(1:end-1); 90 | bxleft=bxleft(1:end-1);byleft=byleft(1:end-1); 91 | bcxcoor=[bxbot bxright bxtop bxleft]; 92 | bcycoor=[bybot byright bytop byleft]; 93 | 94 | % place stokeslets at a fractional distance b 95 | stokescoordx=bcxcoor+b*(bcxcoor-com(1)); 96 | stokescoordy=bcycoor+b*(bcycoor-com(2)); 97 | 98 | % define speed of moving boundary 99 | bcv=zeros(size(stokescoordy)); 100 | velboundleft=max(round(nbc*(1/2-fos/2)),2); 101 | velboundright=min(round(nbc*(1/2+fos/2)),nbc); 102 | bubot=linspace(0,0,nbc); 103 | bubot(velboundleft:velboundright)=Ubound; 104 | buright=linspace(0,0,nbc);butop=linspace(0,0,nbc);buleft=linspace(0,0,nbc); 105 | bubot=bubot(1:end-1);buright=buright(1:end-1);butop=butop(1:end-1);buleft=buleft(1:end-1); 106 | bcu=[bubot buright butop buleft]; 107 | end 108 | 109 | % plot geometry if selected 110 | if ploton==1 111 | figure(1);plot(stokescoordx,stokescoordy,'x',bcxcoor,bcycoor,'o',com(1),com(2),'+'); 112 | figure(2);quiver(bcxcoor,bcycoor,bcu,bcv); 113 | end 114 | 115 | end -------------------------------------------------------------------------------- /scripts/shared_functions/InteriorPts_2D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: InteriorPts_2D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function generates a grid of points on the interior of 32 | % the domain of our Stokes flow problem in two dimensions. 33 | % 34 | % 35 | % Inputs: 36 | % corner1, corner2 - corners of box of meshgrid 37 | % xpts, ypts - number of points in the x and y dimension 38 | % closeness - how close we want to put points to the corners, where we may 39 | % encounter high shearing 40 | % 41 | % Outputs: 42 | % xc, yc - grid of x and y coordinates 43 | 44 | function [xc,yc]=InteriorPts_2D(corner1,corner2,xpts,ypts,closeness) 45 | 46 | dx=(corner2(1)-corner1(1))*(1-closeness); 47 | dy=(corner2(2)-corner1(2))*(1-closeness); 48 | [xc,yc]=ndgrid(linspace(corner1(1)+dx,corner2(1)-dx,xpts),linspace(corner1(2)+dy,corner2(2)-dy,ypts)); 49 | end -------------------------------------------------------------------------------- /scripts/shared_functions/InteriorPts_3D.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: InteriorPts_3D 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function generates a grid of points on the interior of 32 | % the domain of our Stokes flow problem in two dimensions. 33 | % 34 | % 35 | % Inputs: 36 | % corner1, corner2 - corners of cuboid to define the meshgrid 37 | % xpts, ypts, zpts - number of points in the x, y, and z dimension 38 | % closeness - how close we want to put points to the corners, where we may 39 | % encounter high shearing 40 | % 41 | % Outputs: 42 | % xc, yc, zc - cubic grid of x, y, and z coordinates 43 | 44 | function [xc,yc,zc]=InteriorPts_3D(corner1,corner2,xpts,ypts,zpts,closeness) 45 | 46 | dx=(corner2(1)-corner1(1))*(1-closeness); 47 | dy=(corner2(2)-corner1(2))*(1-closeness); 48 | dz=(corner2(3)-corner1(3))*(1-closeness); 49 | 50 | [xc,yc,zc]=ndgrid(linspace(corner1(1)+dx,corner2(1)-dx,xpts),linspace(corner1(2)+dy,corner2(2)-dy,ypts),linspace(corner1(3)+dz,corner2(3)-dz,zpts)); 51 | end -------------------------------------------------------------------------------- /scripts/shared_functions/edge3d/edgedetect.asv: -------------------------------------------------------------------------------- 1 | function [edge,conn_comp,edge_strength] = edgedetect(f,filter,thresholds,min_edge_functional) 2 | % function [edge,conn_comp,edge_strength] = edgedetect(f,filter,thresholds,min_edge_functional) 3 | % 4 | % Detect edges/jumps of given 3D-image f using Canny edge detection 5 | % (differential version, cf. Lindeberg 1998) with hysteresis thresholding 6 | % 7 | % Output: 8 | % edge: Edge/jump surfaces (face & vertex list) 9 | % conn_comp: Connected components of edge set 10 | % edge_strength: Gradient magnitude |nabla f| (of smoothed data) 11 | % 12 | % Input: 13 | % f: Data to detect jumps in (3D-array containing grayscale values) 14 | % filter: (2x1)-vector, filter(1) contains the standard deviation and 15 | % filter(2) the window size of Gaussian convolution filter 16 | % thresholds: (2x1)-vector, upper/lower hysteresis thresholds. 17 | % Edge parts with gradient magnitude less then thresholds(2) 18 | % are removed from the set set. Only those connected 19 | % componenents where the gradient magnitude rises above 20 | % thresholds(1) are kept in the edge set. 21 | % min_edge_functional: Cutoff for edge detection differential for 22 | % speedup: larger value -> faster, less accurate. 23 | % Set to 0 if no speedup is required. 24 | 25 | % default input 26 | if nargin <= 3 27 | min_edge_functional=0; 28 | end 29 | if nargin <= 2 30 | thresholds=0; 31 | end 32 | if nargin <= 1 33 | filter=0; 34 | end 35 | if nargin == 0 36 | error('Missing input arguments.'); 37 | end 38 | 39 | % verify input arguments 40 | if ndims(f)~=3 || ~isvector(thresholds) || ~isvector(filter) ... 41 | || ~isscalar(min_edge_functional) 42 | error('Wrong input argument structure.'); 43 | end 44 | 45 | % standard window size: 2*sigma 46 | if isscalar(filter) 47 | window=ceil(2*filter); 48 | else 49 | window=filter(2); sigma=filter(1); 50 | end 51 | 52 | % apply smoothing filter 53 | if(sigma > 0) 54 | filt=gaussfilter([window;window;window],(diag(sigma).^2)); 55 | f_smooth=imfilter(f,filt,NaN); 56 | else 57 | f_smooth=f; 58 | end 59 | 60 | % calculate gradient magnitude 61 | [gx,gy,gz]=gradient(f_smooth); 62 | f_gradmag=sqrt(gx.^2+gy.^2+gz.^2); 63 | 64 | % define differential filter masks - first order 65 | filt_dx=[-1/2, 0, 1/2]; 66 | filt_dy=shiftdim(filt_dx,1); 67 | filt_dz=shiftdim(filt_dx,-1); 68 | 69 | % define differential filter masks - second order 70 | filt_dxx=[1, -2, 1]; 71 | filt_dyy=shiftdim(filt_dxx,1); 72 | filt_dzz=shiftdim(filt_dxx,-1); 73 | filt_dxy=[1/4, 0, -1/4; 0 0 0; -1/4, 0, 1/4]; 74 | filt_dyz=shiftdim(filt_dxy,-1); 75 | filt_dxz=shiftdim(filt_dyz,1); 76 | 77 | % define differential filter masks - third order 78 | filt_dxxx=[-1/2, 1, 0, -1, 1/2]; 79 | filt_dyyy=shiftdim(filt_dxxx,1); 80 | filt_dzzz=shiftdim(filt_dxxx,-1); 81 | filt_dxxy=[-1/2, 1, -1/2; 0 0 0; 1/2, -1, 1/2]; 82 | filt_dxxz=permute(filt_dxxy,[3 2 1]); 83 | filt_dyyx=permute(filt_dxxy,[2 1 3]); 84 | filt_dyyz=permute(filt_dxxy,[2 3 1]); 85 | filt_dzzx=permute(filt_dxxy,[3 1 2]); 86 | filt_dzzy=permute(filt_dxxy,[1 3 2]); 87 | filt_dxyz=(1/2)*cat(3,-filt_dxy,zeros(3,3),filt_dxy); 88 | 89 | % apply filters 90 | f_dx=imfilter(f_smooth,filt_dx); 91 | f_dy=imfilter(f_smooth,filt_dy); 92 | f_dz=imfilter(f_smooth,filt_dz); 93 | f_dxx=imfilter(f_smooth,filt_dxx); 94 | f_dyy=imfilter(f_smooth,filt_dyy); 95 | f_dzz=imfilter(f_smooth,filt_dzz); 96 | f_dxy=imfilter(f_smooth,filt_dxy); 97 | f_dyz=imfilter(f_smooth,filt_dyz); 98 | f_dxz=imfilter(f_smooth,filt_dxz); 99 | f_dxxx=imfilter(f_smooth,filt_dxxx); 100 | f_dyyy=imfilter(f_smooth,filt_dyyy); 101 | f_dzzz=imfilter(f_smooth,filt_dzzz); 102 | f_dxxy=imfilter(f_smooth,filt_dxxy); 103 | f_dxxz=imfilter(f_smooth,filt_dxxz); 104 | f_dyyx=imfilter(f_smooth,filt_dyyx); 105 | f_dyyz=imfilter(f_smooth,filt_dyyz); 106 | f_dzzx=imfilter(f_smooth,filt_dzzx); 107 | f_dzzy=imfilter(f_smooth,filt_dzzy); 108 | f_dxyz=imfilter(f_smooth,filt_dxyz); 109 | 110 | % calculate differential used for non-maximum surpression 111 | maxedge = f_dx.^2.*f_dxx + f_dy.^2.*f_dyy ... 112 | + f_dz.^2.*f_dzz + 2*f_dx.*f_dy.*f_dxy ... 113 | + 2*f_dy.*f_dz.*f_dyz + 2*f_dx.*f_dz.*f_dxz; 114 | 115 | % remove small variation of edge detection functional 116 | maxedge(abs(maxedge)thresholds(2)); edge=reducesurface(edge,ind); edge_strength=edge_strength(ind); 142 | 143 | % remove connected components of edge set where gradient magnitude 144 | % is never above the upper threshold 145 | [ind,conn_comp]=hysteresis(edge,edge_strength,thresholds); 146 | edge=reducesurface(edge,ind); edge_strength=edge_strength(ind); 147 | [~,~,conn_comp]=unique(conn_comp(ind)); 148 | 149 | end 150 | 151 | 152 | function [ind,conn_comp] = hysteresis(edge,edge_strength,thresholds) 153 | % Apply upper hysteresis threshold on face & vertex list 154 | 155 | % initialize accepted vertex list 156 | ind=true(size(edge.vertices,1),1); 157 | 158 | % find connected components of edge set 159 | conn_comp=conncomp(edge); 160 | 161 | % loop over connected components 162 | for i=1:max(conn_comp) 163 | 164 | % remove component if maximal edge strength is below upper threshold 165 | if max(edge_strength(conn_comp==i)) < thresholds(1) 166 | ind(conn_comp==i)=false; 167 | end 168 | 169 | end 170 | 171 | end 172 | 173 | function surf_new = reducesurface(surf,ind) 174 | % Reduce list of vertices and faces (triangles) to given indices 175 | 176 | % reduce vertex list 177 | surf_new.vertices=surf.vertices(ind,:); 178 | 179 | % corresponding faces 180 | num=(1:sum(ind))'; indlist=NaN(size(surf.vertices,1),1); 181 | indlist(ind)=num; new_elem=indlist(surf.faces); 182 | surf_new.faces=new_elem(~isnan(sum(new_elem,2)),:); 183 | 184 | end 185 | 186 | function cc = conncomp(surf,label) 187 | % Find connected components of given surface (list of faces and vertices) 188 | 189 | % initialize label list if not given a prior 190 | if ~exist('label','var') 191 | label=(1:size(surf.vertices,1))'; 192 | end 193 | 194 | % loop until all nodes of every face have the same label 195 | while max(std(label(surf.faces),0,2))~=0 196 | 197 | % smallest label of every face (vectorized) 198 | m=repmat(min(label(surf.faces),[],2),[3 1]); 199 | 200 | % set label of node to smallest of face (randomize to break cycles) 201 | j=surf.faces(:); p=randperm(length(m)); 202 | label(j(p))=m(p); 203 | end 204 | 205 | % relabel 206 | [~,~,cc]=unique(label); 207 | 208 | end 209 | 210 | function filter = gaussfilter(sz,sigma) 211 | % Calculate Gaussian filter tensor with given dimensions sz 212 | % and covariance matrix sigma 213 | 214 | % initialize 215 | dims=length(sz); ind_cell=cell(dims,1); filter=zeros(sz'); 216 | 217 | % calculate midpoint 218 | midpoint=(sz+1)/2; 219 | 220 | % define (unnormalized) gaussian function 221 | gauss=@(x) exp(-x'*(sigma\x)/2); 222 | 223 | % loop over all elements of tensor 224 | for i=1:numel(filter) 225 | 226 | % get indices of element with linear index i 227 | [ind_cell{:}]=ind2sub(sz',i); ind=cell2mat(ind_cell); 228 | 229 | % calculate gaussian value at size i 230 | filter(i)=gauss(ind-midpoint); 231 | 232 | end 233 | 234 | % get l1 norm of filter 235 | n=filter; 236 | 237 | for d=1:dims 238 | n=sum(n,dims-d+1); 239 | end 240 | 241 | % normalize 242 | filter=filter/n; 243 | 244 | end -------------------------------------------------------------------------------- /scripts/shared_functions/edge3d/edgedetect.m: -------------------------------------------------------------------------------- 1 | function [edge,conn_comp,edge_strength] = edgedetect(f,filter,thresholds,min_edge_functional) 2 | % function [edge,conn_comp,edge_strength] = edgedetect(f,filter,thresholds,min_edge_functional) 3 | % 4 | % Detect edges/jumps of given 3D-image f using Canny edge detection 5 | % (differential version, cf. Lindeberg 1998) with hysteresis thresholding 6 | % 7 | % Output: 8 | % edge: Edge/jump surfaces (face & vertex list) 9 | % conn_comp: Connected components of edge set 10 | % edge_strength: Gradient magnitude |nabla f| (of smoothed data) 11 | % 12 | % Input: 13 | % f: Data to detect jumps in (3D-array containing grayscale values) 14 | % filter: (2x1)-vector, filter(1) contains the standard deviation and 15 | % filter(2) the window size of Gaussian convolution filter 16 | % thresholds: (2x1)-vector, upper/lower hysteresis thresholds. 17 | % Edge parts with gradient magnitude less then thresholds(2) 18 | % are removed from the set set. Only those connected 19 | % componenents where the gradient magnitude rises above 20 | % thresholds(1) are kept in the edge set. 21 | % min_edge_functional: Cutoff for edge detection differential for 22 | % speedup: larger value -> faster, less accurate. 23 | % Set to 0 if no speedup is required. 24 | 25 | % default input 26 | if nargin <= 3 27 | min_edge_functional=0; 28 | end 29 | if nargin <= 2 30 | thresholds=0; 31 | end 32 | if nargin <= 1 33 | filter=0; 34 | end 35 | if nargin == 0 36 | error('Missing input arguments.'); 37 | end 38 | 39 | % verify input arguments 40 | if ndims(f)~=3 || ~isvector(thresholds) || ~isvector(filter) ... 41 | || ~isscalar(min_edge_functional) 42 | error('Wrong input argument structure.'); 43 | end 44 | 45 | % standard window size: 2*sigma 46 | if isscalar(filter) 47 | window=ceil(2*filter); 48 | else 49 | window=filter(2); sigma=filter(1); 50 | end 51 | 52 | % apply smoothing filter 53 | if(sigma > 0) 54 | filt=gaussfilter([window;window;window],(diag(sigma).^2)); 55 | f_smooth=imfilter(f,filt,NaN); 56 | else 57 | f_smooth=f; 58 | end 59 | 60 | % calculate gradient magnitude 61 | [gx,gy,gz]=gradient(f_smooth); 62 | f_gradmag=sqrt(gx.^2+gy.^2+gz.^2); 63 | 64 | % define differential filter masks - first order 65 | filt_dx=[-1/2, 0, 1/2]; 66 | filt_dy=shiftdim(filt_dx,1); 67 | filt_dz=shiftdim(filt_dx,-1); 68 | 69 | % define differential filter masks - second order 70 | filt_dxx=[1, -2, 1]; 71 | filt_dyy=shiftdim(filt_dxx,1); 72 | filt_dzz=shiftdim(filt_dxx,-1); 73 | filt_dxy=[1/4, 0, -1/4; 0 0 0; -1/4, 0, 1/4]; 74 | filt_dyz=shiftdim(filt_dxy,-1); 75 | filt_dxz=shiftdim(filt_dyz,1); 76 | 77 | % define differential filter masks - third order 78 | filt_dxxx=[-1/2, 1, 0, -1, 1/2]; 79 | filt_dyyy=shiftdim(filt_dxxx,1); 80 | filt_dzzz=shiftdim(filt_dxxx,-1); 81 | filt_dxxy=[-1/2, 1, -1/2; 0 0 0; 1/2, -1, 1/2]; 82 | filt_dxxz=permute(filt_dxxy,[3 2 1]); 83 | filt_dyyx=permute(filt_dxxy,[2 1 3]); 84 | filt_dyyz=permute(filt_dxxy,[2 3 1]); 85 | filt_dzzx=permute(filt_dxxy,[3 1 2]); 86 | filt_dzzy=permute(filt_dxxy,[1 3 2]); 87 | filt_dxyz=(1/2)*cat(3,-filt_dxy,zeros(3,3),filt_dxy); 88 | 89 | % apply filters 90 | f_dx=imfilter(f_smooth,filt_dx); 91 | f_dy=imfilter(f_smooth,filt_dy); 92 | f_dz=imfilter(f_smooth,filt_dz); 93 | f_dxx=imfilter(f_smooth,filt_dxx); 94 | f_dyy=imfilter(f_smooth,filt_dyy); 95 | f_dzz=imfilter(f_smooth,filt_dzz); 96 | f_dxy=imfilter(f_smooth,filt_dxy); 97 | f_dyz=imfilter(f_smooth,filt_dyz); 98 | f_dxz=imfilter(f_smooth,filt_dxz); 99 | f_dxxx=imfilter(f_smooth,filt_dxxx); 100 | f_dyyy=imfilter(f_smooth,filt_dyyy); 101 | f_dzzz=imfilter(f_smooth,filt_dzzz); 102 | f_dxxy=imfilter(f_smooth,filt_dxxy); 103 | f_dxxz=imfilter(f_smooth,filt_dxxz); 104 | f_dyyx=imfilter(f_smooth,filt_dyyx); 105 | f_dyyz=imfilter(f_smooth,filt_dyyz); 106 | f_dzzx=imfilter(f_smooth,filt_dzzx); 107 | f_dzzy=imfilter(f_smooth,filt_dzzy); 108 | f_dxyz=imfilter(f_smooth,filt_dxyz); 109 | 110 | % calculate differential used for non-maximum surpression 111 | maxedge = f_dx.^2.*f_dxx + f_dy.^2.*f_dyy ... 112 | + f_dz.^2.*f_dzz + 2*f_dx.*f_dy.*f_dxy ... 113 | + 2*f_dy.*f_dz.*f_dyz + 2*f_dx.*f_dz.*f_dxz; 114 | 115 | % remove small variation of edge detection functional 116 | maxedge(abs(maxedge)thresholds(2)); edge=reducesurface(edge,ind); edge_strength=edge_strength(ind); 142 | 143 | % remove connected components of edge set where gradient magnitude 144 | % is never above the upper threshold 145 | [ind,conn_comp]=hysteresis(edge,edge_strength,thresholds); 146 | edge=reducesurface(edge,ind); edge_strength=edge_strength(ind); 147 | [~,~,conn_comp]=unique(conn_comp(ind)); 148 | 149 | end 150 | 151 | 152 | function [ind,conn_comp] = hysteresis(edge,edge_strength,thresholds) 153 | % Apply upper hysteresis threshold on face & vertex list 154 | 155 | % initialize accepted vertex list 156 | ind=true(size(edge.vertices,1),1); 157 | 158 | % find connected components of edge set 159 | conn_comp=conncomp(edge); 160 | 161 | % loop over connected components 162 | for i=1:max(conn_comp) 163 | 164 | % remove component if maximal edge strength is below upper threshold 165 | if max(edge_strength(conn_comp==i)) < thresholds(1) 166 | ind(conn_comp==i)=false; 167 | end 168 | 169 | end 170 | 171 | end 172 | 173 | function surf_new = reducesurface(surf,ind) 174 | % Reduce list of vertices and faces (triangles) to given indices 175 | 176 | % reduce vertex list 177 | surf_new.vertices=surf.vertices(ind,:); 178 | 179 | % corresponding faces 180 | num=(1:sum(ind))'; indlist=NaN(size(surf.vertices,1),1); 181 | indlist(ind)=num; new_elem=indlist(surf.faces); 182 | surf_new.faces=new_elem(~isnan(sum(new_elem,2)),:); 183 | 184 | end 185 | 186 | function cc = conncomp(surf,label) 187 | % Find connected components of given surface (list of faces and vertices) 188 | 189 | % initialize label list if not given a prior 190 | if ~exist('label','var') 191 | label=(1:size(surf.vertices,1))'; 192 | end 193 | 194 | % loop until all nodes of every face have the same label 195 | while max(std(label(surf.faces),0,2))~=0 196 | 197 | % smallest label of every face (vectorized) 198 | m=repmat(min(label(surf.faces),[],2),[3 1]); 199 | 200 | % set label of node to smallest of face (randomize to break cycles) 201 | j=surf.faces(:); p=randperm(length(m)); 202 | label(j(p))=m(p); 203 | end 204 | 205 | % relabel 206 | [~,~,cc]=unique(label); 207 | 208 | end 209 | 210 | function filter = gaussfilter(sz,sigma) 211 | % Calculate Gaussian filter tensor with given dimensions sz 212 | % and covariance matrix sigma 213 | 214 | % initialize 215 | dims=length(sz); ind_cell=cell(dims,1); filter=zeros(sz'); 216 | 217 | % calculate midpoint 218 | midpoint=(sz+1)/2; 219 | 220 | % define (unnormalized) gaussian function 221 | gauss=@(x) exp(-x'*(sigma\x)/2); 222 | 223 | % loop over all elements of tensor 224 | for i=1:numel(filter) 225 | 226 | % get indices of element with linear index i 227 | [ind_cell{:}]=ind2sub(sz',i); ind=cell2mat(ind_cell); 228 | 229 | % calculate gaussian value at size i 230 | filter(i)=gauss(ind-midpoint); 231 | 232 | end 233 | 234 | % get l1 norm of filter 235 | n=filter; 236 | 237 | for d=1:dims 238 | n=sum(n,dims-d+1); 239 | end 240 | 241 | % normalize 242 | filter=filter/n; 243 | 244 | end -------------------------------------------------------------------------------- /scripts/shared_functions/edge3d/example.m: -------------------------------------------------------------------------------- 1 | % Generate test function f 2 | [X,Y,Z] = meshgrid(1:200,1:100,1:100); 3 | background = sin((X+Y+Z)*pi/100); 4 | blobs = double(sqrt((X-60).^2+(Y-60).^2+(Z-50).^2)<=20) ... 5 | + double(sqrt((X-140).^2+(Y-60).^2+(Z-50).^2)<=10) ... 6 | - double(abs(X-100)<=60 & abs(Y-20)<=5 & abs(Z-50)<=20); 7 | f = background + blobs + 0.2*randn(size(X)); 8 | 9 | % Edge detection parameters 10 | filter = [2; 5]; % Options for Gaussian filter, standard deviation and window size 11 | thresholds = [0.2; 0.1]; % Upper and lower hysteresis thresholds 12 | min_edge_functional = 1e-4; % Low value cutoff for edge detection functional: 13 | % larger value -> faster, less accurate 14 | 15 | % Find jump surfaces/edges of f 16 | [edge,conncomp,edgestrength] = edgedetect(f,filter,thresholds,min_edge_functional); 17 | 18 | % Segmentation parameters 19 | edgesize = 1; % Thickness of the voxelized edge surface 20 | 21 | % Segment image domain using edge set 22 | seglabels = segment(edge,size(f),edgesize); 23 | 24 | % Plot results 25 | figure; imagesc(f(:,:,50)); axis image; set(gca,'YDir','normal'); 26 | colormap gray; colorbar; xlabel('x'); ylabel('y'); title('3D-data [z=50]'); 27 | 28 | figure; title('Edge strength'); 29 | plotsurface(edge,edgestrength,0.6); colorbar; view(130,30); 30 | 31 | figure; title('Connected components of edge set'); 32 | plotsurface(edge,conncomp,0.6); camlight headlight; view(130,30); 33 | 34 | figure; imagesc(seglabels(:,:,50)); axis image; set(gca,'YDir','normal'); 35 | xlabel('x'); ylabel('y'); title('Segmentation [z=50]'); -------------------------------------------------------------------------------- /scripts/shared_functions/edge3d/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Wolf Naetar 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /scripts/shared_functions/edge3d/plotsurface.m: -------------------------------------------------------------------------------- 1 | function plotsurface(surf,coloring,alpha) 2 | % function plotsurface(surf,coloring,alpha) 3 | % Plot surface (face & vertex list) with given coloring 4 | 5 | % default: uniform coloring 6 | if ~exist('coloring','var') 7 | coloring=ones(length(surf.vertices),1); 8 | end 9 | 10 | % default: facealpha = 0.5 11 | if ~exist('alpha','var'); 12 | alpha=0.5; 13 | end 14 | 15 | patch('Faces',surf.faces,'Vertices',surf.vertices,'FaceVertexCData',coloring,'FaceColor','interp','edgecolor', 'interp','FaceAlpha',alpha); 16 | xlabel('x'); ylabel('y'); zlabel('z'); view(3); daspect([1 1 1]); 17 | shading flat; 18 | 19 | end 20 | 21 | -------------------------------------------------------------------------------- /scripts/shared_functions/edge3d/segment.m: -------------------------------------------------------------------------------- 1 | function labels = segment(edge,sz,edgesize) 2 | % function labels = segment(edge,sz,edgesize) 3 | % 4 | % Segment domain of given size into regions enclosed by given edge set 5 | % using bwlabeln (image processing toolbox) 6 | % 7 | % Output: 8 | % labels: Segmentation label for every voxel 9 | % 10 | % Input: 11 | % edge: Edge set as obtained from edgedetect 12 | % sz: Size of image domain, (3x1)-vector 13 | % edgesize: Thickness of edge set in voxels 14 | % (large values help to close holes in the edge set) 15 | 16 | % default parameter: edges with thickness 1 17 | if ~exist('edgesize','var') 18 | edgesize=1; 19 | end 20 | 21 | % create label space 22 | labels=ones(sz); 23 | 24 | % return if no edge is given 25 | if isempty(edge.vertices) 26 | return; 27 | end 28 | 29 | % pixels corresponding to edge itself 30 | edgepix=unique(round(edge.vertices),'rows'); 31 | thin_e=zeros(sz); thin_e(sub2ind(sz,edgepix(:,2),edgepix(:,1),edgepix(:,3)))=1; 32 | 33 | % fatten edge set 34 | fat_e=thin_e; 35 | 36 | for i=1:edgesize 37 | fat_e=grow(fat_e); 38 | end 39 | 40 | % set label to 0 on fat edge set 41 | labels(fat_e>0)=0; 42 | 43 | % find connected components using bwlabeln (image processing toolbox) 44 | labels=bwlabeln(labels,6); 45 | 46 | end 47 | 48 | function x_new = grow(x) 49 | % Function to grow level set of 1 by one pixel (in binary image) 50 | 51 | x_new=x; 52 | 53 | for i=-1:1 54 | for j=-1:1 55 | for k=-1:1 56 | x_new = x_new + circshift(x,[i j k]) + circshift(x,[-i -j -k]); 57 | end 58 | end 59 | end 60 | 61 | end -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/ColorSpec_LongName_to_RGBvalue.m: -------------------------------------------------------------------------------- 1 | function RGBvalue = ColorSpec_LongName_to_RGBvalue(LongName) 2 | 3 | % RGBvalue = ColorSpec_LongName_to_RGBvalue(LongName) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % 5 | % Given the color 'LongName' ('red','green',...) convert to the matrix equivalent 6 | % 7 | % Example: 8 | % val = ColorSpec_LongName_to_RGBvalue('magenta'); 9 | % ------> returns the three-element equivalent to magenta = [1 0 1] 10 | % 11 | % 12 | % Author: Shawn Arseneau 13 | % Created: September 14, 2006 14 | % 15 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 | 17 | switch(lower(LongName)) 18 | case 'yellow' 19 | RGBvalue = [1 1 0]; 20 | case 'magenta' 21 | RGBvalue = [1 0 1]; 22 | case 'cyan' 23 | RGBvalue = [0 1 1]; 24 | case 'red' 25 | RGBvalue = [1 0 0]; 26 | case 'green' 27 | RGBvalue = [0 1 0]; 28 | case 'blue' 29 | RGBvalue = [0 0 1]; 30 | case 'white' 31 | RGBvalue = [1 1 1]; 32 | case 'black' 33 | RGBvalue = [0 0 0]; 34 | otherwise 35 | RGBvalue = []; 36 | msg = sprintf('Unrecognized LongName: %s - See valid list (yellow, magenta, cyan, red, green, blue, white, black)', lower(LongName)); 37 | error(msg); 38 | return; 39 | end 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/ColorSpec_ShortName_to_RGBvalue.m: -------------------------------------------------------------------------------- 1 | function RGBvalue = ColorSpec_ShortName_to_RGBvalue(shortName) 2 | 3 | % RGBvalue = ColorSpec_ShortName_to_RGBvalue(shortName) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % 5 | % Given the single character shortName ('r','g',...) convert to the matrix equivalent 6 | % 7 | % Example: 8 | % val = ColorSpec_ShortName_to_RGBvalue('m'); 9 | % -------> returns the three-element equivalent to 'm' (magenta) = [1 0 1] 10 | % 11 | % Author: Shawn Arseneau 12 | % Created: September 14, 2006 13 | % 14 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 15 | 16 | switch(lower(shortName)) 17 | case 'y' 18 | RGBvalue = [1 1 0]; 19 | case 'm' 20 | RGBvalue = [1 0 1]; 21 | case 'c' 22 | RGBvalue = [0 1 1]; 23 | case 'r' 24 | RGBvalue = [1 0 0]; 25 | case 'g' 26 | RGBvalue = [0 1 0]; 27 | case 'b' 28 | RGBvalue = [0 0 1]; 29 | case 'w' 30 | RGBvalue = [1 1 1]; 31 | case 'k' 32 | RGBvalue = [0 0 0]; 33 | otherwise 34 | RGBvalue = []; 35 | msg = sprintf('Unrecognized ShortName: %s - See valid list (y, m, c, r, g, b, w, k)', lower(ShortName)); 36 | error(msg); 37 | return; 38 | end 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/arrow3D.m: -------------------------------------------------------------------------------- 1 | function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) 2 | 3 | % arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % 5 | % Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead 6 | % pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem) 7 | % deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos') 8 | % colorCode - Color parameters as per the 'surf' command. For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow 9 | % stemRatio - The ratio of the length of the stem in proportion to the arrowhead. For example, a call of: 10 | % arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance 11 | % of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18. 12 | % 13 | % Example: 14 | % arrow3D([0,0,0], [4,3,7]); %---- arrow with default parameters 15 | % axis equal; 16 | % 17 | % Author: Shawn Arseneau 18 | % Created: September 14, 2006 19 | % Updated: September 18, 2006 20 | % 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | if nargin<2 || nargin>4 23 | error('Incorrect number of inputs to arrow3D'); 24 | end 25 | if numel(pos)~=3 || numel(deltaValues)~=3 26 | error('pos and/or deltaValues is incorrect dimensions (should be three)'); 27 | end 28 | if nargin<3 29 | colorCode = 'interp'; 30 | end 31 | if nargin<4 32 | stemRatio = 0.75; 33 | end 34 | 35 | X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector 36 | Y = pos(2); 37 | Z = pos(3); 38 | 39 | [sphi, stheta, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3)); 40 | 41 | %******************************************* CYLINDER == STEM ********************************************* 42 | cylinderRadius = 0.05*srho; 43 | cylinderLength = srho*stemRatio; 44 | [CX,CY,CZ] = cylinder(cylinderRadius); 45 | CZ = CZ.*cylinderLength; %---- lengthen 46 | 47 | %----- ROTATE CYLINDER 48 | [row, col] = size(CX); %---- initial rotation to coincide with X-axis 49 | 50 | newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); 51 | CX = reshape(newEll(:,1), row, col); 52 | CY = reshape(newEll(:,2), row, col); 53 | CZ = reshape(newEll(:,3), row, col); 54 | 55 | [row, col] = size(CX); 56 | newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]); 57 | stemX = reshape(newEll(:,1), row, col); 58 | stemY = reshape(newEll(:,2), row, col); 59 | stemZ = reshape(newEll(:,3), row, col); 60 | 61 | %----- TRANSLATE CYLINDER 62 | stemX = stemX + X; 63 | stemY = stemY + Y; 64 | stemZ = stemZ + Z; 65 | 66 | %******************************************* CONE == ARROWHEAD ********************************************* 67 | coneLength = srho*(1-stemRatio); 68 | coneRadius = cylinderRadius*1.5; 69 | incr = 4; %---- Steps of cone increments 70 | coneincr = coneRadius/incr; 71 | [coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0); %---------- CONE 72 | coneZ = coneZ.*coneLength; 73 | 74 | %----- ROTATE CONE 75 | [row, col] = size(coneX); 76 | newEll = rotatePoints([0 0 -1], [coneX(:), coneY(:), coneZ(:)]); 77 | coneX = reshape(newEll(:,1), row, col); 78 | coneY = reshape(newEll(:,2), row, col); 79 | coneZ = reshape(newEll(:,3), row, col); 80 | 81 | newEll = rotatePoints(deltaValues, [coneX(:), coneY(:), coneZ(:)]); 82 | headX = reshape(newEll(:,1), row, col); 83 | headY = reshape(newEll(:,2), row, col); 84 | headZ = reshape(newEll(:,3), row, col); 85 | 86 | %---- TRANSLATE CONE 87 | V = [0, 0, srho*stemRatio]; %---- centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder 88 | Vp = rotatePoints([0 0 -1], V); 89 | Vp = rotatePoints(deltaValues, Vp); 90 | headX = headX + Vp(1) + X; 91 | headY = headY + Vp(2) + Y; 92 | headZ = headZ + Vp(3) + Z; 93 | %************************************************************************************************************ 94 | hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none'); 95 | hold on; 96 | hHead = surf(headX, headY, headZ, 'FaceColor', colorCode, 'EdgeColor', 'none'); 97 | 98 | if nargout==1 99 | arrowHandle = [hStem, hHead]; 100 | end 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/demoQuiver3D.m: -------------------------------------------------------------------------------- 1 | %% quiver3D - Output a collection of arrows with various color and shape options 2 | 3 | %% Syntax 4 | % * quiver3D(posArray, magnitudeArray) 5 | % * quiver3D(posArray, magnitudeArray, one_ShortNameColor) 6 | % * quiver3D(posArray, magnitudeArray, one_LongNameColor) 7 | % * quiver3D(posArray, magnitudeArray, one_RGBvalueColor) 8 | % * quiver3D(posArray, magnitudeArray, many_RGBvalueColor) 9 | % 10 | %% Description 11 | % * quiver3D(posArray, magnitudeArray) - plot an arrow for each row of posArray in form of (x,y,z) with delta values corresponding to 12 | % the rows of magnitudeArray (u,v,w) using arrow3D, which allows for a 13 | % three-dimensional arrow representation. Since arrow3D uses 'surf', you may use 'camlight' 14 | % and 'lighting' to add more powerful visual effects of the data. 15 | % 16 | % * quiver3D(..., one_ShortNameColor) - colors all arrows the same color using MATLAB's ShortName color convention, {'r','g',...} as per ColorSpec. 17 | % 18 | % * quiver3D(..., one_LongNameColor) - colors all arrows the same color using MATLAB's LongName color convention, {'red','green',...} as per ColorSpec. 19 | % 20 | % * quiver3D(..., one_RGBvalueColor) - colors all arrows the same color using the three element vector representation. For example [0, 1, 0.5] 21 | % 22 | % * quiver3D(..., many_RGBvalueColor) - a distinct color is assigned each of the individual arrows in the quiver in Nx3 format. 23 | % 24 | 25 | %% Example: Basic Call 26 | [X, Y] = meshgrid(0:3:9, 0:3:9); 27 | Z = ones(size(X)); 28 | U = zeros(size(X)); 29 | V = U; 30 | W = ones(size(X))*8; 31 | posArray = [X(:),Y(:),Z(:)]; 32 | magnitudeArray = [U(:),V(:),W(:)]; 33 | quiverHandle = quiver3D(posArray, magnitudeArray, 'r'); 34 | 35 | hold on; 36 | axis equal; 37 | grid on; 38 | xlabel('X'); ylabel('Y'); zlabel('Z'); 39 | view(20,30); 40 | 41 | %% Lighting Effects 42 | lighting phong; 43 | camlight head; 44 | 45 | %% Arrow-specific colors 46 | numArrows = size(posArray,1); 47 | arrowColors = zeros(numArrows, 3); 48 | Rstream = (0:1/(numArrows-1):1)'; 49 | arrowColors(:,1) = Rstream; 50 | delete(quiverHandle); 51 | colorQuiverHandle = quiver3D(posArray, magnitudeArray, arrowColors); 52 | 53 | %% Change of stemRatios 54 | delete(colorQuiverHandle); 55 | colorQuiverHandle = quiver3D(posArray, magnitudeArray, arrowColors, 0.9); 56 | 57 | 58 | %% Helix Example 59 | radius = 7; height = 1; numRotations = 2; numPoints = 25; arrowScale = 0.8; 60 | [posArray1, magnitudeArray1] = helix(radius, height, numRotations, numPoints, arrowScale); 61 | arrowColors1 = zeros(numPoints, 3); 62 | BlackToWhite = (0:1/(numPoints-1):1); 63 | WhiteToBlack = (1:-1/(numPoints-1):0); 64 | arrowColors1(:,1) = WhiteToBlack'; 65 | arrowColors1(:,2) = BlackToWhite'; 66 | 67 | radius = 2; height = 0.66; numRotations = 3; 68 | [posArray2, magnitudeArray2] = helix(radius, height, numRotations, numPoints, arrowScale); 69 | arrowColors2 = zeros(numPoints, 3); 70 | arrowColors2(:,3) = BlackToWhite'; 71 | 72 | delete(colorQuiverHandle); 73 | quiver3D(posArray1, magnitudeArray1, arrowColors1, 0.6); 74 | quiver3D(posArray2, magnitudeArray2, arrowColors2, 0.6); 75 | axis equal; 76 | grid on; 77 | xlabel('X'); ylabel('Y'); zlabel('Z'); 78 | view(20,10); 79 | axis tight; 80 | camlight head; 81 | lighting phong; 82 | 83 | 84 | %% Credits 85 | % Author: Shawn Arseneau 86 | % 87 | % Created: September 15, 2006 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/helix.m: -------------------------------------------------------------------------------- 1 | function [pos,mag] = helix(radius, height, numRevolutions, numPoints, arrowScale) 2 | 3 | % [pos,mag] = helix(radius, height, numRevolutions, numPoints, arrowScale) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % 5 | % Parametric equation of the 3D helix 6 | % [pos] = helix(radius, height) - output pos = [x(:),y(:),z(:)] locations along a helix 7 | % [pos,mag] = helix(radius, height) - output (x,y,z) along with tangent arrows (u,v,w) with fixed magnitude 8 | % [...] = helix(..., numRevolutions) - default = two rotations of the helix 9 | % [...] = helix(..., numRevolutions, numPoints) - number of samples along the helix (default = 25) 10 | % [...] = helix(..., numRevolutions, numPoints, arrowScale) - magnitude of the tangent arrows (default = 0.8) 11 | % 12 | % Example: 13 | % [pos, mag] = helix(5, 4, 7, 50, 0.24); 14 | % quiver3D(posArray1, magnitudeArray1); %---- plots a helix with radius=5, height=4, with 7 revolutions, sampled at 50 points with arrows 24% of the length 15 | % % between sampled points 16 | % 17 | % Author: Shawn Arseneau 18 | % Created: September 15, 2006 19 | % 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | 22 | if nargin<2 || nargin>5 23 | error('Incorrect number of inputs to helix'); 24 | end 25 | if nargout~=1 && nargout~=2 26 | error('Incorrect number of outputs to helix'); 27 | end 28 | if nargin<=4 29 | arrowScale = 0.8; 30 | end 31 | if nargin<=3 32 | numPoints = 25; 33 | end 34 | if nargin<=2 35 | numRevolutions = 2; 36 | end 37 | 38 | endAngle = numRevolutions*2*pi; 39 | t = (0:endAngle/numPoints:endAngle); 40 | X_all = radius*cos(t); 41 | Y_all = radius*sin(t); 42 | Z_all = height*t; 43 | 44 | X = X_all(1:end-1); X_end = X_all(2:end); 45 | Y = Y_all(1:end-1); Y_end = Y_all(2:end); 46 | Z = Z_all(1:end-1); Z_end = Z_all(2:end); 47 | 48 | pos = [X(:),Y(:),Z(:)]; 49 | 50 | if nargout==2 51 | U = arrowScale*(X_end - X); 52 | V = arrowScale*(Y_end - Y); 53 | W = arrowScale*(Z_end - Z); 54 | mag = [U(:),V(:),W(:)]; 55 | end 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | quiver3D - Output a collection of arrows with various color and shape options 10 | 11 | 12 | 70 | 71 |

quiver3D - Output a collection of arrows with various color and shape options

72 | 73 |

Contents

74 |
75 | 85 |
86 |

Syntax

87 |
88 |
    89 |
  • quiver3D(posArray, magnitudeArray)
  • 90 |
  • quiver3D(posArray, magnitudeArray, one_ShortNameColor)
  • 91 |
  • quiver3D(posArray, magnitudeArray, one_LongNameColor)
  • 92 |
  • quiver3D(posArray, magnitudeArray, one_RGBvalueColor)
  • 93 |
  • quiver3D(posArray, magnitudeArray, many_RGBvalueColor)
  • 94 |
95 |
96 |

Description

97 |
98 |
    99 |
  • quiver3D(posArray, magnitudeArray) - plot an arrow for each row of posArray in form of (x,y,z) with delta values corresponding 100 | to the rows of magnitudeArray (u,v,w) using arrow3D, which allows for a 101 | three-dimensional arrow representation. Since arrow3D uses 'surf', you may use 'camlight' 102 | and 'lighting' to add more powerful visual effects of the data. 103 |
  • 104 |
105 |
106 |
107 |
    108 |
  • quiver3D(..., one_ShortNameColor) - colors all arrows the same color using MATLAB's ShortName color convention, {'r','g',...} 109 | as per ColorSpec. 110 |
  • 111 |
112 |
113 |
114 |
    115 |
  • quiver3D(..., one_LongNameColor) - colors all arrows the same color using MATLAB's LongName color convention, {'red','green',...} 116 | as per ColorSpec. 117 |
  • 118 |
119 |
120 |
121 |
    122 |
  • quiver3D(..., one_RGBvalueColor) - colors all arrows the same color using the three element vector representation. For example 123 | [0, 1, 0.5] 124 |
  • 125 |
126 |
127 |
128 |
    129 |
  • quiver3D(..., many_RGBvalueColor) - a distinct color is assigned each of the individual arrows in the quiver in Nx3 format.
  • 130 |
131 |
132 |

Example: Basic Call

    [X, Y] = meshgrid(0:3:9, 0:3:9);
133 |     Z = ones(size(X));
134 |     U = zeros(size(X));
135 |     V = U;
136 |     W = ones(size(X))*8;
137 |     posArray = [X(:),Y(:),Z(:)];
138 |     magnitudeArray = [U(:),V(:),W(:)];
139 |     quiverHandle = quiver3D(posArray, magnitudeArray, 'r');
140 | 
141 |     hold on;
142 |     axis equal;
143 |     grid on;
144 |     xlabel('X'); ylabel('Y'); zlabel('Z');
145 |     view(20,30);
146 | 

Lighting Effects

    lighting phong;
147 |     camlight head;
148 | 

Arrow-specific colors

    numArrows = size(posArray,1);
149 |     arrowColors = zeros(numArrows, 3);
150 |     Rstream = (0:1/(numArrows-1):1)';
151 |     arrowColors(:,1) = Rstream;
152 |     delete(quiverHandle);
153 |     colorQuiverHandle = quiver3D(posArray, magnitudeArray, arrowColors);
154 | 

Change of stemRatios

    delete(colorQuiverHandle);
155 |     colorQuiverHandle = quiver3D(posArray, magnitudeArray, arrowColors, 0.9);
156 | 

Helix Example

    radius = 7;   height = 1;  numRotations = 2;  numPoints = 25;  arrowScale = 0.8;
157 |     [posArray1, magnitudeArray1] = helix(radius, height, numRotations, numPoints, arrowScale);
158 |     arrowColors1 = zeros(numPoints, 3);
159 |     BlackToWhite = (0:1/(numPoints-1):1);
160 |     WhiteToBlack = (1:-1/(numPoints-1):0);
161 |     arrowColors1(:,1) = WhiteToBlack';
162 |     arrowColors1(:,2) = BlackToWhite';
163 | 
164 |     radius = 2;   height = 0.66;  numRotations = 3;
165 |     [posArray2, magnitudeArray2] = helix(radius, height, numRotations, numPoints, arrowScale);
166 |     arrowColors2 = zeros(numPoints, 3);
167 |     arrowColors2(:,3) = BlackToWhite';
168 | 
169 |     delete(colorQuiverHandle);
170 |     quiver3D(posArray1, magnitudeArray1, arrowColors1, 0.6);
171 |     quiver3D(posArray2, magnitudeArray2, arrowColors2, 0.6);
172 |     axis equal;
173 |     grid on;
174 |     xlabel('X'); ylabel('Y'); zlabel('Z');
175 |     view(20,10);
176 |     axis tight;
177 |     camlight head;
178 |     lighting phong;
179 | 

Credits

180 |

Author: Shawn Arseneau

181 |

Created: September 15, 2006

182 | 184 | 294 | 295 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/shared_functions/quiver3D_pub/html/demoQuiver3D.png -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_01.png -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_02.png -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_03.png -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_04.png -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanhuang/Stokes-Flow-Simulation/a552e2e249106ff4ea8e60f31a3bad035e9c4d59/scripts/shared_functions/quiver3D_pub/html/demoQuiver3D_05.png -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/quiver3D.m: -------------------------------------------------------------------------------- 1 | function qHandle = quiver3D(posArray, magnitudeArray, arrowColors, stemRatio) 2 | 3 | % qHandle = quiver3D(posArray, magnitudeArray, arrowColors, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % 5 | % Given the posArray (position array) [x1,y1,z1; x2,y2,z2; ...] and 6 | % their relative magnitudes along the x,y,z-axes using magnitudeArray [dx1,dy1,dz1; dx2,dy2,dz2; ...], 7 | % with optional color and stem ratios, output a quiver of arrows. 8 | % 9 | % arrowColors - conforms to 'ColorSpec.' For example, 'r','red',[1 0 0] will all plot a quiver with all arrows as red. 10 | % This can also be in the form of Nx3 where 'N' is the number of arrows, and each column corresponds to the R,G,B values 11 | % stemRatio - ratio of the arrowhead (cone) to the arrowstem (cylinder) [default = 0.75]. For example, setting this value to 0.94 will 12 | % produce arrows with arrowstems 94% of the length and short, 6% cones as arrowheads 13 | % 14 | % Example: 15 | % [X,Y] = meshgrid(1:5, -2:2); 16 | % Z = zeros(size(X)); 17 | % posArray = [X(:),Y(:),Z(:)]; 18 | % 19 | % magnitudeArray = zeros(size(posArray)); 20 | % magnitudeArray(:,1) = 1; 21 | % quiver3D(posArray, magnitudeArray, 'g', 0.6); 22 | % 23 | % 24 | % Forms: 25 | % quiver3D(posArray, magnitudeArray) - plot a quiver of three-dimensional arrows with default color black 26 | % 27 | % quiver3D(posArray, magnitudeArray, arrowColors) 28 | % 29 | % quiver3D(..., arrowColors, stemRatio) - ratio of the arrowhead (cone) to the arrowstem (cylinder) [default = 0.75] 30 | % 31 | % Author: Shawn Arseneau 32 | % Created: September 14, 2006 33 | % Updated: September 18, 2006 34 | % 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | qHandle = []; 37 | 38 | %% ------------------------------------------------------------Initial verification of input parameters 39 | if nargin<2 || nargin>4 40 | error('Invalid number of input arguments. help quiver3D for details'); 41 | end 42 | 43 | numArrows = size(posArray,1); 44 | if numArrows ~= size(magnitudeArray,1) 45 | error('Position and magnitude inputs do not agree. help quiver3D for details'); 46 | end 47 | 48 | %% ----------------------------------------------------------------------------------Default parameters 49 | if nargin<4 50 | stemRatio = 0.75; 51 | end 52 | 53 | if nargin<3 54 | arrowColors = zeros(numArrows, 3); 55 | else 56 | [arrowRow, arrowCol] = size(arrowColors); 57 | 58 | if arrowRow==1 59 | if ischar(arrowColors) %--------------------------------------- in ShortName or LongName color format 60 | if arrowCol==1 61 | RGBvalue = ColorSpec_ShortName_to_RGBvalue(arrowColors); 62 | else 63 | RGBvalue = ColorSpec_LongName_to_RGBvalue(arrowColors); 64 | end 65 | else 66 | if arrowCol~=3 67 | error('arrowColors in RGBvalue must be of the form 1x3'); 68 | end 69 | RGBvalue = arrowColors; 70 | end 71 | arrowColors = []; 72 | arrowColors(1:numArrows,1) = RGBvalue(1); 73 | arrowColors(1:numArrows,2) = RGBvalue(2); 74 | arrowColors(1:numArrows,3) = RGBvalue(3); 75 | 76 | elseif arrowRow~=numArrows 77 | error('arrowColors in RGBvalue must be of the form Nx3'); 78 | end 79 | end 80 | 81 | 82 | %% ---------------------------------------------------------------Loop through all arrows and plot in 3D 83 | hold on; 84 | for i=1:numArrows 85 | qHandle(i,:) = arrow3D(posArray(i,:), magnitudeArray(i,:), arrowColors(i,:), stemRatio); 86 | end 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiver3D_pub/rotatePoints.m: -------------------------------------------------------------------------------- 1 | function rotatedData = rotatePoints(alignmentVector, originalData) 2 | 3 | % rotatedData = rotatePoints(alignmentVector, originalData) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % 5 | % Rotate the 'originalData' in the form of Nx2 or Nx3 about the origin by aligning the x-axis with the alignment vector 6 | % 7 | % Rdata = rotatePoints([1,2,-1], [Xpts(:), Ypts(:), Zpts(:)]) - rotate the (X,Y,Z)pts in 3D with respect to the vector [1,2,-1] 8 | % 9 | % Rotating using spherical components can be done by first converting using [dX,dY,dZ] = cart2sph(theta, phi, rho); alignmentVector = [dX,dY,dZ]; 10 | % 11 | % Example: 12 | % %% Rotate the point [3,4,-7] with respect to the following: 13 | % %%%% Original associated vector is always [1,0,0] 14 | % %%%% Calculate the appropriate rotation requested with respect to the x-axis. For example, if only a rotation about the z-axis is 15 | % %%%% sought, alignmentVector = [2,1,0] %% Note that the z-component is zero 16 | % rotData = rotatePoints(alignmentVector, [3,4,-7]); 17 | % 18 | % Author: Shawn Arseneau 19 | % Created: Feb.2, 2006 20 | % 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | 23 | alignmentDim = numel(alignmentVector); 24 | DOF = size(originalData,2); %---- DOF = Degrees of Freedom (i.e. 2 for two dimensional and 3 for three dimensional data) 25 | 26 | if alignmentDim~=DOF 27 | error('Alignment vector does not agree with originalData dimensions'); 28 | end 29 | if DOF<2 || DOF>3 30 | error('rotatePoints only does rotation in two or three dimensions'); 31 | end 32 | 33 | 34 | if DOF==2 % 2D rotation... 35 | [rad_theta, rho] = cart2pol(alignmentVector(1), alignmentVector(2)); 36 | deg_theta = -1 * rad_theta * (180/pi); 37 | ctheta = cosd(deg_theta); stheta = sind(deg_theta); 38 | 39 | Rmatrix = [ctheta, -1.*stheta;... 40 | stheta, ctheta]; 41 | rotatedData = originalData*Rmatrix; 42 | 43 | else % 3D rotation... 44 | [rad_theta, rad_phi, rho] = cart2sph(alignmentVector(1), alignmentVector(2), alignmentVector(3)); 45 | rad_theta = rad_theta * -1; 46 | deg_theta = rad_theta * (180/pi); 47 | deg_phi = rad_phi * (180/pi); 48 | ctheta = cosd(deg_theta); stheta = sind(deg_theta); 49 | Rz = [ctheta, -1.*stheta, 0;... 50 | stheta, ctheta, 0;... 51 | 0, 0, 1]; %% First rotate as per theta around the Z axis 52 | rotatedData = originalData*Rz; 53 | 54 | [rotX, rotY, rotZ] = sph2cart(-1* (rad_theta+(pi/2)), 0, 1); %% Second rotation corresponding to phi 55 | rotationAxis = [rotX, rotY, rotZ]; 56 | u = rotationAxis(:)/norm(rotationAxis); %% Code extract from rotate.m from MATLAB 57 | cosPhi = cosd(deg_phi); 58 | sinPhi = sind(deg_phi); 59 | invCosPhi = 1 - cosPhi; 60 | x = u(1); 61 | y = u(2); 62 | z = u(3); 63 | Rmatrix = [cosPhi+x^2*invCosPhi x*y*invCosPhi-z*sinPhi x*z*invCosPhi+y*sinPhi; ... 64 | x*y*invCosPhi+z*sinPhi cosPhi+y^2*invCosPhi y*z*invCosPhi-x*sinPhi; ... 65 | x*z*invCosPhi-y*sinPhi y*z*invCosPhi+x*sinPhi cosPhi+z^2*invCosPhi]'; 66 | 67 | rotatedData = rotatedData*Rmatrix; 68 | end 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /scripts/shared_functions/quiverc.m: -------------------------------------------------------------------------------- 1 | function hh = quiverc(varargin) 2 | % Modified version of Quiver to plots velocity vectors as arrows 3 | % with components (u,v) at the points (x,y) using the current colormap 4 | 5 | % Bertrand Dano 3-3-03 6 | % Extended by Stephan Jonas 9/14/12 7 | % Copyright 1984-2002 The MathWorks, Inc. 8 | 9 | %QUIVERC Quiver color plot. 10 | % QUIVERC(X,Y,U,V) plots velocity vectors as arrows with components (u,v) 11 | % at the points (x,y). The matrices X,Y,U,V must all be the same size 12 | % and contain corresponding position and velocity components (X and Y 13 | % can also be vectors to specify a uniform grid). QUIVER automatically 14 | % scales the arrows to fit within the grid. 15 | % 16 | % QUIVERC(U,V) plots velocity vectors at equally spaced points in 17 | % the x-y plane. 18 | 19 | % QUIVERC(U,V,C) plots velocity vectors at equally spaced points in 20 | % the x-y plane colorcoded with the colors givin in C. 21 | % 22 | % QUIVERC(U,V,S), QUIVERC(U,V,C,S), QUIVER(X,Y,U,V,S) or QUIVER(X,Y,U,V,C, S) automatically scales the 23 | % arrows to fit within the grid and then stretches them by S. Use 24 | % S=0 to plot the arrows without the automatic scaling. 25 | % 26 | % QUIVERC(...,LINESPEC) uses the plot linestyle specified for 27 | % the velocity vectors. Any marker in LINESPEC is drawn at the base 28 | % instead of an arrow on the tip. Use a marker of '.' to specify 29 | % no marker at all. See PLOT for other possibilities. 30 | % 31 | % QUIVERC(...,'filled') fills any markers specified. 32 | % 33 | % H = QUIVERC(...) returns a vector of line handles. 34 | % 35 | % Example: 36 | % [x,y] = meshgrid(-2:.2:2,-1:.15:1); 37 | % z = x .* exp(-x.^2 - y.^2); [px,py] = gradient(z,.2,.15); 38 | % contour(x,y,z), hold on 39 | % quiverc(x,y,px,py), hold off, axis image 40 | % 41 | % See also FEATHER, QUIVER3, PLOT. 42 | % Clay M. Thompson 3-3-94 43 | % Copyright 1984-2002 The MathWorks, Inc. 44 | % $Revision: 5.21 $ $Date: 2002/06/05 20:05:16 $ 45 | %------------------------------------------------------------- 46 | 47 | set(gca, 'color', 'blue'); 48 | % Arrow head parameters 49 | alpha = 0.33; % Size of arrow head relative to the length of the vector 50 | beta = 0.23; % Width of the base of the arrow head relative to the length 51 | autoscale = 1; % Autoscale if ~= 0 then scale by this. 52 | plotarrows = 1; % Plot arrows 53 | sym = ''; 54 | 55 | filled = 0; 56 | ls = '-'; 57 | ms = ''; 58 | col = ''; 59 | lw=2; 60 | 61 | nin = nargin; 62 | % Parse the string inputs 63 | while isstr(varargin{nin}), 64 | vv = varargin{nin}; 65 | if ~isempty(vv) & strcmp(lower(vv(1)),'f') 66 | filled = 1; 67 | nin = nin-1; 68 | else 69 | [l,c,m,msg] = colstyle(vv); 70 | if ~isempty(msg), 71 | error(sprintf('Unknown option "%s".',vv)); 72 | end 73 | if ~isempty(l), ls = l; end 74 | if ~isempty(c), col = c; end 75 | if ~isempty(m), ms = m; plotarrows = 0; end 76 | if isequal(m,'.'), ms = ''; end % Don't plot '.' 77 | nin = nin-1; 78 | end 79 | end 80 | 81 | 82 | error(nargchk(2,6,nin)); 83 | if length(varargin{nin})==1 % quiver(u,v,s) or quiver(x,y,u,v,s) 84 | autoscale = varargin{nin}; 85 | nin = nin-1; 86 | end 87 | 88 | % Check numeric input arguments 89 | if nin<4 % quiver(u,v), quiver(u,v,c) or quiver(u,v,c,s) 90 | [msg,x,y,u,v] = xyzchk(varargin{1:2}); 91 | else 92 | [msg,x,y,u,v] = xyzchk(varargin{1:4}); 93 | end 94 | if ~isempty(msg), error(msg); end 95 | 96 | % Scalar expand u,v 97 | if numel(u)==1, u = u(ones(size(x))); end 98 | if numel(v)==1, v = v(ones(size(u))); end 99 | 100 | if autoscale, 101 | % Base autoscale value on average spacing in the x and y 102 | % directions. Estimate number of points in each direction as 103 | % either the size of the input arrays or the effective square 104 | % spacing if x and y are vectors. 105 | if min(size(x))==1, n=sqrt(numel(x)); m=n; else [m,n]=size(x); end 106 | delx = diff([min(x(:)) max(x(:))])/n; 107 | dely = diff([min(y(:)) max(y(:))])/m; 108 | len = sqrt((u.^2 + v.^2)/(delx.^2 + dely.^2)); 109 | autoscale = autoscale*0.9 / max(len(:)); 110 | u = u*autoscale; v = v*autoscale; 111 | end 112 | 113 | %---------------------------------------------- 114 | % Define colormap 115 | if nin==3 || nin==5 116 | vr = varargin{nin}; 117 | else 118 | vr=sqrt(u.^2+v.^2); 119 | end 120 | vrn=round(vr/max(vr(:))*64); 121 | %CC=colormap; 122 | %CC=parula(64); 123 | CC=jet(128); 124 | CC=CC(65:end,:); 125 | %CC=flipud(CC(1:64,:)); 126 | %CC=hot(64); 127 | ax = newplot; 128 | next = lower(get(ax,'NextPlot')); 129 | hold_state = ishold; 130 | 131 | %---------------------------------------------- 132 | % Make velocity vectors and plot them 133 | 134 | x = x(:).';y = y(:).'; 135 | u = u(:).';v = v(:).'; 136 | vrn=vrn(:).'; 137 | uu = [x;x+u;repmat(NaN,size(u))]; 138 | vv = [y;y+v;repmat(NaN,size(u))]; 139 | vrn1= [vrn;repmat(NaN,size(u));repmat(NaN,size(u))]; 140 | 141 | uui=uu(:); vvi=vv(:); vrn1=vrn1(:); imax=size(uui); 142 | hold on 143 | for i= 1:3:imax-1 144 | ii=int8(round(vrn1(i))); 145 | if ii==0; ii=1; end 146 | c1= CC(ii,1); c2= CC(ii,2); c3= CC(ii,3); 147 | plot(uui(i:i+1),vvi(i:i+1),'linewidth',lw,'color',[c1 c2 c3]); 148 | end 149 | 150 | %---------------------------------------------- 151 | % Make arrow heads and plot them 152 | if plotarrows, 153 | 154 | hu = [x+u-alpha*(u+beta*(v+eps));x+u; ... 155 | x+u-alpha*(u-beta*(v+eps));repmat(NaN,size(u))]; 156 | hv = [y+v-alpha*(v-beta*(u+eps));y+v; ... 157 | y+v-alpha*(v+beta*(u+eps));repmat(NaN,size(v))]; 158 | vrn2= [vrn;vrn;vrn;vrn]; 159 | 160 | uui=hu(:); vvi=hv(:); vrn2=vrn2(:); imax=size(uui); 161 | 162 | for i= 1:imax-1 163 | ii=int8(round(vrn2(i))); 164 | if ii==0; ii=1; end 165 | c1= CC(ii,1); c2= CC(ii,2); c3= CC(ii,3); 166 | plot(uui(i:i+1),vvi(i:i+1),'linewidth',lw,'color',[c1 c2 c3]); 167 | end 168 | 169 | else 170 | h2 = []; 171 | end 172 | %---------------------------------------------- 173 | 174 | if ~isempty(ms), % Plot marker on base 175 | hu = x; hv = y; 176 | hold on 177 | h3 = plot(hu(:),hv(:),[col ms]); 178 | if filled, set(h3,'markerfacecolor',get(h1,'color')); end 179 | else 180 | h3 = []; 181 | end 182 | 183 | if ~hold_state, hold off, view(2); set(ax,'NextPlot',next); end 184 | 185 | if nargout>0, hh = [h1;h2;h3]; end 186 | set(gca,'XTick',[]) 187 | set(gca,'YTick',[]) 188 | 189 | %set(gca, 'color', [0 0 0],'Xcolor','w','Ycolor','w'); 190 | %set(gcf, 'color', [0 0 0]); 191 | %set(gcf, 'InvertHardCopy', 'off'); 192 | -------------------------------------------------------------------------------- /scripts/shared_functions/solve_mixedBC.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: solve_mixedBC 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function solves the equation u = G f + T u 32 | % where u is the flow on the boundary, f is the traction on the boundary, G 33 | % is the single layer potential, and T is the double layer potential. Some 34 | % elements of both u and f may be known, while others are unknown. 35 | % The solution is done by collecting all the known coeeficients in one vector and 36 | % all the unknown coefficients in another vector (swapping traction and boundary conditions 37 | % using the matlab deal function, inverting the equation, and then swaping the 38 | % solved for traction and boundary conditions back in. 39 | % 40 | % Inputs: 41 | % BCtotal - known velocity / traction values on boundary, all dimensions (2D 42 | % or 3D) in a single column 43 | % alpha - index specifying which boundary element is traction versus velocity 44 | % SLmat - single layer potential 45 | % DLmat - double layer potential 46 | % visc - viscosity 47 | % dimen - 2D vs. 3D 48 | % 49 | % Outputs: 50 | % u0 velocity values of boundary, all dimensions in a single column 51 | % f0 traction values on boundaries, all dimensions in a single column 52 | % bcu, bcv, [bcw] - u0 split into proper dimensions 53 | % fx, fy, [fz] - f0 split into proper dimensions 54 | % We have a variable out structure depending on the number of dimensions 55 | % For 2D for example, bcu, bcv, fx, and fy are nout 1 - 4 56 | 57 | function [u0,f0,nout1,nout2,nout3,nout4,nout5,nout6] = solve_mixedBC(SLmat,DLmat,BCtotal,visc,alpha,dimen) 58 | 59 | % We start by multiplying our single and double layer potential matrices by 60 | % the proper coefficients 61 | switch dimen 62 | case '2D' 63 | A=1/(2*pi*visc)*SLmat; 64 | B=(1/(2*pi)*DLmat-eye(size(DLmat))); 65 | case '3D' 66 | A=1/(4*pi*visc)*SLmat; 67 | B=(1/(4*pi)*DLmat-eye(size(DLmat))); 68 | end 69 | % Our Boundary Condition vector BCtotal is a long vector that contains 70 | % either values of u or f. Whether the value is u or f is determined by the 71 | % alpha vector. Here, if a boundary condition is a traction one (f), then 72 | % we swap the single and double layer potentials for that element 73 | [A(:,alpha),B(:,alpha)]=deal(-B(:,alpha),-A(:,alpha)); 74 | 75 | % may want to A\B this in the future 76 | f0=inv(A)*B*BCtotal; 77 | u0=BCtotal; 78 | 79 | % f0 is our now solved for coefficients. Most are traction, but the 80 | % elements in BC total that were traction need to be swapped back 81 | [u0(alpha),f0(alpha)]=deal(f0(alpha),u0(alpha)); 82 | 83 | % Split u0 and f0 into respective x,y, [z] dimensions 84 | switch dimen 85 | case '2D' 86 | n1=numel(u0)/2; 87 | nout1=u0(1:n1); 88 | nout2=u0(n1+1:end); 89 | nout3=f0(1:n1); 90 | nout4=f0(n1+1:end); 91 | case '3D' 92 | n1=numel(u0)/3; 93 | nout1=u0(1:n1); 94 | nout2=u0(n1+1:2*n1); 95 | nout3=u0(2*n1+1:end); 96 | nout4=f0(1:n1); 97 | nout5=f0(n1+1:2*n1); 98 | nout6=f0(2*n1+1:end); 99 | end 100 | end -------------------------------------------------------------------------------- /scripts/shared_functions/vis2Dfield_quiver.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: vis2Dfield_quiver 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function plots the flow field simulated in 32 | % two-dimensions by the Stokes-Flow-Simulation. It additionally plots the 33 | % boundary points and the flow on the boundary. Square represent stationary 34 | % points on the boundary 35 | % 36 | % 37 | % 38 | % Inputs: 39 | % x, y: x and y coordinates of interior points 40 | % u, v: flow vector of interior points 41 | % xbc, ybc: x and y coordinates of boundary elements 42 | % ubc, vbc: flow vector of boundary elements 43 | % fignum: optional to specify numbering of Matlab figure 44 | % 45 | 46 | function vis2Dfield_quiver(x,y,u,v,xbc,ybc,ubc,vbc,fignum) 47 | 48 | if nargin<9 49 | fignum=1; 50 | end 51 | 52 | % Find elements where there is flow on the boundary 53 | ind1=bitor(ubc~=0,vbc~=0); 54 | if numel(ubc(ind1))>10 55 | % for visualization sake, we don't plot the flow at every boundary point if 56 | % we have more than 10. We'll use our function reducemat to downsample our 57 | % points 58 | % ds is downsample factor 59 | ds=floor(numel(ubc(ind1))/10); 60 | 61 | % leftover is how many values we omit at the end 62 | leftover=mod(numel(ubc(ind1)),ds); 63 | unz=reducemat(ubc(ind1),ds,leftover); 64 | vnz=reducemat(vbc(ind1),ds,leftover); 65 | xnz=reducemat(xbc(ind1),ds,leftover); 66 | ynz=reducemat(ybc(ind1),ds,leftover); 67 | else 68 | unz=ubc(ind1); 69 | vnz=vbc(ind1); 70 | xnz=xbc(ind1); 71 | ynz=ybc(ind1); 72 | end 73 | 74 | % Find the boundaries of domain 75 | x1=min(x(:)); 76 | x2=max(x(:)); 77 | y1=min(y(:)); 78 | y2=max(y(:)); 79 | xl=x2-x1; 80 | yl=y2-y1; 81 | 82 | % set color of boundary points 83 | boundarycolor=[0 0 0]/255; 84 | figure(fignum); 85 | 86 | % call the color quiver function 87 | quiverc(x(:),y(:),u(:),v(:));hold on; 88 | 89 | % plot the boundaries 90 | plot(xbc(~ind1),ybc(~ind1),'s','MarkerEdgeColor',boundarycolor,'LineWidth',1.5); 91 | axis([x1-0.1*xl, x2+0.1*xl, y1-0.1*yl, y2+0.1*yl]); 92 | 93 | % quiver the moving portion of the boundary 94 | g1=quiver(xnz,ynz,unz,vnz,0.2,'Linewidth',1.5); 95 | set(g1, 'Color',boundarycolor); 96 | hold off; 97 | end 98 | 99 | % reducemat a function to downsample the quiver field if there are too many 100 | % points on the boundary 101 | function zz=reducemat(mat1,ds,leftover) 102 | a2=mat1(1:end-leftover); 103 | a3=mat1(end-leftover:end); 104 | a2=squeeze(mean(reshape(a2,ds,[]),1)); 105 | a3=mean(a3); 106 | zz=[a2,a3]; 107 | end -------------------------------------------------------------------------------- /scripts/shared_functions/vis2Dfield_streamline.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: vis2Dfield_streamline 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function plots the streamfunction simulated in 32 | % two-dimensions by the Stokes-Flow-Simulation. Lines represent contours 33 | % of the streamfunction, which are known as streamlines. It additionally plots 34 | % the boundary points and the flow on the boundary. Square represent stationary 35 | % points on the boundary. 36 | % 37 | % 38 | % 39 | % Inputs: 40 | % x, y: x and y coordinates of interior points 41 | % psi: streamfunction 42 | % xbc, ybc: x and y coordinates of boundary elements 43 | % ubc, vbc: flow vector of boundary elements 44 | % fignum: optional to specify numbering of Matlab figure 45 | 46 | function vis2Dfield_streamline(x,y,psi,xbc,ybc,ubc,vbc,fignum) 47 | 48 | if nargin < 8 49 | fignum=1; 50 | end 51 | 52 | % Find elements where there is flow on the boundary 53 | 54 | ind1=bitor(ubc~=0,vbc~=0); 55 | % for visualization sake, we don't plot the flow at every boundary point if 56 | % we have more than 10. We'll use our function reducemat to downsample our 57 | % points 58 | if numel(ubc(ind1))>10 59 | ds=floor(numel(ubc(ind1))/10); % ds is downsample factor 60 | leftover=mod(numel(ubc(ind1)),ds); % leftover is how many values we omit at the end 61 | unz=reducemat(ubc(ind1),ds,leftover); 62 | vnz=reducemat(vbc(ind1),ds,leftover); 63 | xnz=reducemat(xbc(ind1),ds,leftover); 64 | ynz=reducemat(ybc(ind1),ds,leftover); 65 | else 66 | unz=ubc(ind1); 67 | vnz=vbc(ind1); 68 | xnz=xbc(ind1); 69 | ynz=ybc(ind1); 70 | end 71 | 72 | 73 | % Find the boundaries of domain 74 | x1=min(x(:)); 75 | x2=max(x(:)); 76 | y1=min(y(:)); 77 | y2=max(y(:)); 78 | xl=x2-x1; 79 | yl=y2-y1; 80 | 81 | % set color of boundary points 82 | boundarycolor=[0 0 0]/255; 83 | figure(fignum); 84 | %quiverc(imresize(x,0.3),imresize(y,0.3),imresize(u,0.3),imresize(v,0.3));hold on; 85 | %gg2=parula(64); 86 | contour(x,y,psi,'Linewidth',3); 87 | set(gca,'XTick',[]) 88 | set(gca,'YTick',[]) 89 | hold on; 90 | 91 | plot(xbc(~ind1),ybc(~ind1),'s','MarkerEdgeColor',boundarycolor,'LineWidth',1.5); 92 | axis([x1-0.1*xl, x2+0.1*xl, y1-0.1*yl, y2+0.1*yl]); 93 | 94 | 95 | % quiver the moving portion of the boundary 96 | g1=quiver(xnz,ynz,unz,vnz,0.2,'Linewidth',1.5); 97 | set(g1, 'Color',boundarycolor); 98 | hold off; 99 | end 100 | 101 | % reducemat a function to downsample the quiver field if there are too many 102 | % points on the boundary 103 | function zz=reducemat(mat1,ds,leftover) 104 | a2=mat1(1:end-leftover); 105 | a3=mat1(end-leftover:end); 106 | a2=squeeze(mean(reshape(a2,ds,[]),1)); 107 | a3=mean(a3); 108 | zz=[a2,a3]; 109 | end -------------------------------------------------------------------------------- /scripts/shared_functions/vis3Dfield_cube.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % 3 | % Stokes-Flow-Simulation by Brendan Huang 4 | % Script: vis3Dfield_cube 5 | % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | % 8 | % MIT License 9 | % 10 | % Copyright (c) 2015 Brendan K. Huang 11 | % 12 | % Permission is hereby granted, free of charge, to any person obtaining a copy 13 | % of this software and associated documentation files (the "Software"), to deal 14 | % in the Software without restriction, including without limitation the rights 15 | % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | % copies of the Software, and to permit persons to whom the Software is 17 | % furnished to do so, subject to the following conditions: 18 | % 19 | % The above copyright notice and this permission notice shall be included in all 20 | % copies or substantial portions of the Software. 21 | % 22 | % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | % SOFTWARE. 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | % 31 | % Description: This function plots the flow field simulated in 32 | % three-dimensions by the Stokes-Flow-Simulation. It additionally plots the 33 | % boundaries elements of the surface, and shades the portion 34 | % of the bottom surface that is moving. A 2D quiver plot is generated on 35 | % the moving surface to indicate the magnitude and direction of flow 36 | % 37 | % 38 | % 39 | % Inputs: 40 | % x, y, z: x and y coordinates of interior points 41 | % u, v, w: flow vector of interior points 42 | % bcx, bcy, bcz: x, y, z coordinates of boundary elements 43 | % bcu, bcv, bcw, vbc: flow vector of boundary elements 44 | % vertpts, elemverts: vertices and indices of triangles to plot of cube 45 | % surface 46 | % 47 | % Note, this script calls the 'plotsurface' function from: 48 | % https://www.mathworks.com/matlabcentral/fileexchange/46260-3d-differential-canny-edge-detector 49 | % 50 | % as well as the 'quiver3D' function from: 51 | % https://www.mathworks.com/matlabcentral/fileexchange/12285-3d-quiver-with-volumized-arrows 52 | % 53 | % Original source code for these functions can be downloaded at Mathworks 54 | % file exchange, but have also been included with this function under 55 | % licensing terms. 56 | % 57 | function vis3Dfield_cube(corner1,corner2,x,y,z,u,v,w,bcx,bcy,bcz,bcu,bcv,bcw,vertpts,elemvert) 58 | 59 | % calculate some geometric properties of where the flow is calculated 60 | xmin=corner1(1); 61 | ymin=corner1(2); 62 | zmin=corner1(3); 63 | xmax=corner2(1); 64 | ymax=corner2(2); 65 | zmax=corner2(3); 66 | 67 | cubevert=[xmin,ymin,zmin;xmin,ymin,zmax;xmin,ymax,zmin;xmin,ymax,zmax;... 68 | xmax,ymin,zmin;xmax,ymin,zmax;xmax,ymax,zmin;xmax,ymax,zmax]; 69 | cubevert1=[cubevert(1,:);cubevert(2,:);cubevert(4,:);cubevert(3,:);cubevert(1,:); ... 70 | cubevert(5,:);cubevert(6,:);cubevert(8,:);cubevert(7,:);cubevert(5,:)]; 71 | cubevert2=[cubevert(1,:);cubevert(5,:);cubevert(6,:);cubevert(2,:)]; 72 | cubevert3=[cubevert(3,:);cubevert(7,:);cubevert(8,:);cubevert(4,:)]; 73 | 74 | 75 | bctot_ordered=sqrt(bcu.^2+bcv.^2+bcw.^2); 76 | bcnonzero=bctot_ordered~=0; 77 | bcxnz=bcx(bcnonzero); 78 | bcynz=bcy(bcnonzero); 79 | bcunz=bcu(bcnonzero); 80 | bcvnz=bcv(bcnonzero); 81 | 82 | % bcz and bcw here are not used because we are doing a 2D quiver plot on 83 | % the bottom surface. 84 | 85 | % here we put the vertices and faces in a structure that is called by the 86 | % plotsurface function 87 | wallstl=struct('faces',elemvert,'vertices',vertpts); 88 | 89 | % we can specify the color of the moving portion of the wall 90 | coloring1=ones(size(elemvert,1),1)*0.5; 91 | coloring1(bctot_ordered(:,1)~=0)=3; 92 | 93 | % here we put all our positional information into a long array 94 | posarray=[x(:), y(:), z(:)]; 95 | 96 | % here we calculate our speed so we can use the max to normalize our arrows 97 | speedarray=sqrt(u(:).^2+v(:).^2+w(:).^2); 98 | 99 | % if we just want to display the direction of the arrows without encoding 100 | % total speed in the size, we can use normalize all speeds 101 | % magarray=[u(:)./speedarray, v(:)./speedarray, w(:)./speedarray]; 102 | 103 | % Here, we set the magnitudes of the arrow size to be proprotional to the 104 | % total speed 105 | magarray=[u(:), v(:), w(:)]/3; 106 | 107 | % Here we will also encode speed with color 108 | dc=dopplerColors(64); 109 | colarray=dc(floor(speedarray/max(speedarray(:))*32)+32,:); 110 | n1=norm(corner1-corner2); 111 | 112 | figure(30); 113 | % call the plot surface function to plot the boundary elements 114 | plotsurface(wallstl,coloring1,0.2);hold on; 115 | % plot the edges of the cube for clarity 116 | plot3(cubevert1(:,1),cubevert1(:,2),cubevert1(:,3),... 117 | cubevert2(:,1),cubevert2(:,2),cubevert2(:,3),... 118 | cubevert3(:,1),cubevert3(:,2),cubevert3(:,3),'Linewidth',3,'Color',[0,0,0]) 119 | 120 | % call the quiver3D function 121 | quiver3D(posarray,magarray/max(speedarray(:))*n1,colarray); 122 | 123 | % plot the 2D quiver field of the moving surface 124 | quiver(bcxnz,bcynz,bcunz,bcvnz);axis off; 125 | hold off; 126 | camlight('headlight') 127 | 128 | % Depending on your computer, you may have issues with this rendering. You 129 | % can also try to not set this renderer, try 'zbuffer' (deprecated), or try 130 | % 'painters' 131 | set(gcf,'Renderer','opengl'); 132 | drawnow; --------------------------------------------------------------------------------