time | calls | line |
---|
< 0.01 | 1 | 12 | d0 = fileparts([pwd, filesep]);
|
| 1 | 13 | d0 = d0(1 : strfind(d0,'trunk')+4);
|
| | 14 |
|
| 1 | 15 | if ~isfield(app, 'savemat'), app.savemat = 'Save/mat/Bottom_Gravity_Current'; end;
|
| 1 | 16 | if ~exist(sprintf('%s/%s', d0, app.savemat), 'dir')
|
| 1 | 17 | mkdir(sprintf('%s/%s', d0, app.savemat));
|
| 1 | 18 | end;
|
| 1 | 19 | if ~isfield(app, 'NoPlot'), app.NoPlot = false; end;
|
< 0.01 | 1 | 20 | if ~app.NoPlot
|
| | 21 | if ~isfield(app, 'saveimg'), app.saveimg = 'Save/img/Bottom_Gravity_Current'; end;
|
| | 22 | if ~exist(sprintf('%s/%s', d0, app.saveimg), 'dir')
|
| | 23 | mkdir(sprintf('%s/%s', d0, app.saveimg));
|
| | 24 | end;
|
| | 25 | end;
|
| | 26 |
|
| | 27 | %keyboard
|
| | 28 |
|
| | 29 | %% Set up primitive parameters of the bottom gravity current.
|
| | 30 |
|
| 1 | 31 | if isfield (app, 'pass_params')
|
| 1 | 32 | A = app.pass_params.A; % Horizontal size of solution domain (unit: m)
|
| 1 | 33 | B = app.pass_params.B; % Vertical size of solution domain (unit: m)
|
| 1 | 34 | A1 = app.pass_params.A1; % Length of the initial plateau (unit: m)
|
| 1 | 35 | B1 = app.pass_params.B1; % Height of the initial plateau (unit: m)
|
| 1 | 36 | A2 = app.pass_params.A2; % Length of salinity forcing region (unit: m)
|
| | 37 |
|
| 1 | 38 | h = app.pass_params.h; % Length scale of thickness of grivity current (unit: m)
|
| | 39 | % (The paper does not directly provide this value.)
|
| 1 | 40 | rhoinitflag = app.pass_params.rhoinitflag;
|
| | 41 | else
|
| | 42 | A = 10e3; % Horizontal size of solution domain (unit: m)
|
| | 43 | B = 1e3; % Vertical size of solution domain (unit: m)
|
| | 44 | A1 = 1e3; % Length of the initial plateau (unit: m)
|
| | 45 | B1 = 0.8e3; % Height of the initial plateau (unit: m)
|
| | 46 | A2 = 0.6e3; % Length of salinity forcing region (unit: m)
|
| | 47 |
|
| | 48 | h = 500; % Length scale of thickness of grivity current (unit: m)
|
| | 49 | % (The paper does not directly provide this value.)
|
| | 50 | rhoinitflag = 'cosine';
|
| | 51 | end;
|
| | 52 |
|
| | 53 | % Maximum variation of salinity (unit: psu(nondimensional))
|
| 1 | 54 | if isfield(app, 'DelS'), DelS = app.DelS; else DelS = 1.5; end;
|
| | 55 |
|
| | 56 | % Slope angle of the inclined plane (unit: degree, not radian!)
|
| 1 | 57 | if isfield(app, 'theta'), theta = app.theta; else theta = 2.5; end;
|
| | 58 |
|
| 1 | 59 | nu_x = 7; % Eddy viscosity in horizontal direction (unit: m^2/s)
|
| 1 | 60 | r = 1e-5; % Ratio of vertical to horizontal diffusivity (nu_z / nu_x)
|
| 1 | 61 | Pr = 7; % Turbulent Prandtl number (nu_x / K_x)
|
| 1 | 62 | k = 1/21600; % Salinity forcing relaxation frequency (unit: Hz)
|
| | 63 |
|
| 1 | 64 | Ra = 506 * DelS; % Rayleigh number
|
| 1 | 65 | kappa = k*h^2/nu_x; % Nondimensional relaxation frequency
|
| | 66 |
|
| | 67 |
|
| | 68 | %% Set up physical properties and forcing terms
|
| | 69 |
|
| | 70 | % Define momentum forcing terms
|
| | 71 | % 'XY' is a 2-D array.
|
| | 72 | % XY(:, 1) contains x coordinates, XY(:, 2) contains y coordinates.
|
| | 73 | % 't' is just the current time (initial time is t = 0).
|
| | 74 | % Fu and Fv are required functions that need to be set for the solver
|
| 1 | 75 | Fu = @(t, XY) 0;
|
| 1 | 76 | Fv = @(t, XY) 0;
|
| | 77 |
|
| 1 | 78 | if ~isfield(app, 'nu'), app.nu = 1; end;
|
| 1 | 79 | if ~isfield(app, 'nu2'), app.nu2 = r; end;
|
| 1 | 80 | if ~isfield(app, 'kappa'), app.kappa = 1/Pr; end;
|
| 1 | 81 | if ~isfield(app, 'kappa2'), app.kappa2 = r/Pr; end;
|
| 1 | 82 | if ~isfield(app, 'g'), app.g = Ra; end;
|
| | 83 |
|
| | 84 |
|
| | 85 | %% Set up mesh and solution domain
|
| | 86 |
|
| | 87 | % Set size of domain
|
| 1 | 88 | a = A/h;
|
| 1 | 89 | b = B/h;
|
| | 90 |
|
| 1 | 91 | a1 = A1/h;
|
| 1 | 92 | b1 = B1/h;
|
| 1 | 93 | a2 = A2/h;
|
| | 94 |
|
| 1 | 95 | tan_theta = tan(theta*pi/180);
|
| | 96 |
|
| 1 | 97 | if ~isfield(app, 'Nx'), app.Nx = 2000; end;
|
| 1 | 98 | if ~isfield(app, 'Ny'), app.Ny = 200; end;
|
| | 99 |
|
| | 100 | % Set number of timesteps.
|
| 1 | 101 | if ~isfield(app, 'T'), app.T = 16200*nu_x/h^2; end;
|
| 1 | 102 | if ~isfield(app, 'dt'), app.dt = 0.1*nu_x/h^2; end;
|
| 1 | 103 | Nt = ceil(app.T/app.dt);
|
| 1 | 104 | if ~isfield(app, 'PlotIntrvl'), app.PlotIntrvl = round((app.T/app.dt)/270); end;
|
| | 105 |
|
| | 106 | % Mesh the domain
|
| | 107 | % This is a standard call and should not require much modification.
|
| | 108 | % [0, a] gives the min/max x coordinates, and [0, b] gives the min/max y coordinates.
|
0.03 | 1 | 109 | [XP, YP, XU, YU, XV, YV, dx, dy] = meshdomain(app, [0, a], [0, b]);
|
| | 110 |
|
| 1 | 111 | app.IP = 1./(dx*dy*(app.sigma_nd.*app.sigma_nd));
|
| | 112 |
|
| | 113 | % want norm to be 1, i.e. (dx*dy*var_nd_rho*rhoi*rhoi)=1
|
| | 114 | % rescale = sqrt(app.IP(3))
|
| | 115 |
|
| | 116 |
|
| | 117 | %% Set up the geometry mask
|
| | 118 |
|
| | 119 | % This mask is user-created. Zeros are unmasked, and non-zero integers
|
| | 120 | % indicate a masked region. The domain sides should not be considered here.
|
| | 121 | % Each interior masked region could have a different number to allow
|
| | 122 | % different boundary conditions.
|
| | 123 | % Create mask of correct size. This is a standard call and should not
|
| | 124 | % require modification.
|
| 1 | 125 | Mask = zeros(app.Ny, app.Nx);
|
| | 126 |
|
| | 127 | % User-defined true-false (boolean) functions that define the mask.
|
| | 128 | % True if masked, false if not masked.
|
| 1 | 129 | forcing = @(x, y) (x <= a2) & (y >= b1);
|
| 1 | 130 | plateau = @(x, y) (x <= a1) & (y <= b1);
|
| 1 | 131 | slope = @(x, y) (x > a1) & (y <= max(0, (a1-x)*tan_theta + b1));
|
| | 132 |
|
| | 133 | % Assign masked region.
|
< 0.01 | 1 | 134 | Mask(plateau(XP, YP)) = 1;
|
< 0.01 | 1 | 135 | Mask(slope(XP, YP)) = 1;
|
| | 136 |
|
| | 137 | % Logical array add_bnd signifies whether to add (add if =true) boundaries for the
|
| | 138 | % [west, east, south, north] sides of the solution domain.
|
| | 139 | % This is almost a standard procedure except when periodic boundaries are used.
|
| 1 | 140 | add_bnd = [true, true, true, true];
|
| | 141 |
|
| | 142 | % Create preliminary node numbering matrices using function "NodePad".
|
| | 143 | % Note: This is a standard procedure and should not be modified.
|
0.05 | 1 | 144 | [NodeP, Nodeu, Nodev, idsP, idsu, idsv] = NodePad(Mask, add_bnd);
|
| | 145 |
|
| | 146 | % Plot the current boundary IDs to facilitate setting up boundary conditions.
|
| 1 | 147 | if ~app.NoPlot
|
| | 148 | plot_bc_ids(NodeP, Mask);
|
| | 149 | fprintf('Paused at boundary id plot. Hit any key to continue.\n\n');
|
| | 150 | pause;
|
| | 151 | end;
|
| | 152 |
|
| | 153 |
|
| | 154 | %% Set up boundary conditions (BCs)
|
| | 155 |
|
| | 156 | % User assigns BC types to each boundary ID for u, v, rho in three cell arrays.
|
| | 157 |
|
| | 158 | % This requires user input. Use the above plot as reference to identify BC IDs.
|
| | 159 | % e.g. Element 1 in cell array bcid2type_u represents the BC type of the boundary
|
| | 160 | % with ID 1 for velocity u.
|
| | 161 |
|
| | 162 | % Note: Only the following four types of BCs can be set for velocities and density:
|
| | 163 | % Single-value Dirichlet BC (='D')
|
| | 164 | % Multiple-value Dirichlet BC (='Dmv')
|
| | 165 | % Single-value Neumann BC (='N')
|
| | 166 | % Multiple-value Neumann BC (='Nmv')
|
| | 167 |
|
| | 168 | % Warning: Open boundary conditions (='O') are not allowed for velocities and density!
|
| | 169 |
|
| 1 | 170 | bcid2type_u = {'D', 'N', 'N', 'D', 'N'};
|
| 1 | 171 | bcid2type_v = {'D', 'N', 'N', 'D', 'D'};
|
| 1 | 172 | bcid2type_rho = {'N', 'N', 'N', 'N', 'N'};
|
| | 173 |
|
| | 174 | % Automatically assign BC types to each boundary ID for q which is an intermediate variable
|
| | 175 | % for which we need to solve a Poisson equation in the projection methods
|
| | 176 | % used by the Navier-Stokes solver.
|
| | 177 | % The BC types of q depends on those of velocities and can be either 'N' or 'O'.
|
| | 178 |
|
| | 179 | % Note: This is a standard procedure and should not be modified.
|
| | 180 |
|
| 1 | 181 | if ~isfield (app,'qBC')
|
| 1 | 182 | app.qBC='Default';
|
| 1 | 183 | end;
|
| | 184 |
|
| 1 | 185 | Nbcs = size(bcid2type_u); Nbcs = Nbcs(2);
|
| 1 | 186 | bcid2type_q = cell(1, Nbcs);
|
| 1 | 187 | for i = 1 : Nbcs
|
| 5 | 188 | if strcmp(bcid2type_u(i), 'D') || strcmp(bcid2type_u(i), 'Dmv')...
|
| | 189 | || strcmp(bcid2type_v(i), 'D') || strcmp(bcid2type_v(i), 'Dmv')
|
| 3 | 190 | bcid2type_q{i} = 'N';
|
| 2 | 191 | else
|
| 2 | 192 | bcid2type_q{i} = 'O';
|
| 2 | 193 | end;
|
| 5 | 194 | end;
|
| | 195 | % Allow over-ride of automatically defined q BC
|
| 1 | 196 | switch(app.qBC)
|
| 1 | 197 | case 'Dinlet'
|
| | 198 | bcid2type_q{1} = 'D';
|
| 1 | 199 | case 'Dinout'
|
| | 200 | bcid2type_q{1} = 'D';
|
| | 201 | bcid2type_q{2} = 'D';
|
| 1 | 202 | case 'Dirichlet'
|
| | 203 | for i=1:Nbcs
|
| | 204 | bcid2type_q{i} = 'D';
|
| | 205 | end;
|
| | 206 | end;
|
| | 207 |
|
| | 208 | % Set up the final node numbering matrix using function "set_bcs".
|
| | 209 | % For each single-value BC ('D', 'N', 'O'), all its boundary cells share one ID,
|
| | 210 | % like in the preliminary node numbering matrices.
|
| | 211 | % For each multiple-value BC ('Dmv', 'Nmv'), now each boundary cell will be assigned
|
| | 212 | % a different ID.
|
| | 213 | % Besides, the IDs are arranged to satisfy:
|
| | 214 | % Dirichlet_BC_IDs < Open_BC_IDs < Neumann_BC_IDs
|
| | 215 |
|
| | 216 | % Note: This is a standard procedure and should not be modified.
|
| | 217 |
|
| | 218 | % Without density equation:
|
| | 219 | % [NodeP, nbcP, Nodeu, nbcu, Nodev, nbcv] = set_bcs(...
|
| | 220 | % bcid2type_P, NodeP, bcid2type_u, Nodeu, bcid2type_v, Nodev);
|
| | 221 |
|
| | 222 | % With density equation:
|
0.07 | 1 | 223 | [NodeP, nbcq, Nodeu, nbcu, Nodev, nbcv, NodeRho, nbcrho] = set_bcs(...
|
| | 224 | bcid2type_q, NodeP, bcid2type_u, Nodeu, bcid2type_v, Nodev, bcid2type_rho, NodeP);
|
| | 225 |
|
| | 226 |
|
| | 227 | % Set preliminary BC values to zero since most BCs are homogeneous.
|
| | 228 | % Some of them can be modified to be non-homogeneous BCs later.
|
| | 229 |
|
| | 230 | % Note: This is a standard procedure and should not be modified.
|
| | 231 |
|
| 1 | 232 | [bcsDq, bcsOq, bcsNq] = init_bcs(nbcq);
|
| 1 | 233 | [bcsDu, bcsOu, bcsNu] = init_bcs(nbcu);
|
| 1 | 234 | [bcsDv, bcsOv, bcsNv] = init_bcs(nbcv);
|
| 1 | 235 | [bcsDrho, bcsOrho, bcsNrho] = init_bcs(nbcrho);
|
| | 236 |
|
| | 237 | % User sets non-zero boundary conditions.
|
| | 238 |
|
| | 239 | % The coordinates of the boundary points on each grid can be obtained...
|
| | 240 | % by function "get_bc_coord".
|
| | 241 | % Each of the three XY arrays contains 2 columns with x coordinates in the first and
|
| | 242 | % y coordinates in the second stored in order of BC IDs.
|
| | 243 | % The three XY arrays correspond to boundary points of type Dirichlet ('D' and 'Dmv'),
|
| | 244 | % open ('O'), and Neumann ('N' and 'Nmv').
|
| | 245 |
|
| | 246 | % [XYD, XYO, XYN] = get_bc_coord('u', XU, YU, Nodeu, bcsDu, bcsOu, bcsNu);
|
| | 247 | % ids = (abs(XYD(:, 1)) < eps);
|
| | 248 | % bcsDu(ids) = 1*h/nu_x;
|
| | 249 |
|
| | 250 | % [XYD, XYO, XYN] = get_bc_coord('P', XP, YP, NodeRho, bcsDrho, bcsOrho, bcsNrho);
|
| | 251 | % ids = (abs(XYD(:, 1)) < eps);
|
| | 252 | % bcsDrho(ids) = 0.5*(1 - cos(pi*(b-XYD(ids, 2)/(b-b1))));
|
| | 253 |
|
| | 254 |
|
| | 255 | %% Set up initial conditions
|
| | 256 |
|
| | 257 | % User specifies the functions that provide initial values at given coordinates.
|
| | 258 |
|
< 0.01 | 1 | 259 | [rhoinit_choice,rhoinit_parms] = strtok (rhoinitflag);
|
| | 260 |
|
| 1 | 261 | switch rhoinit_choice
|
| 1 | 262 | case 'cosine'
|
| | 263 | rho_init = @(X, Y) 0.5*(1 - cos(pi*(b-Y)/(b-b1))).*forcing(X,Y);
|
| | 264 | P_init = @(X, Y) (app.g*0.5)*((b-Y) - ((b-b1)/pi).*sin(pi*(b-Y)/(b-b1))).*forcing(X,Y);
|
| | 265 |
|
| 1 | 266 | case 'linear'
|
| | 267 | rho_init = @(X, Y) (b-Y)./(b-b1).*forcing(X,Y);
|
| | 268 | P_init = @(X, Y) app.g*((b-Y).^2)./(2.*(b-b1)).*forcing(X,Y);
|
| | 269 |
|
| 1 | 270 | case 'exponential'
|
< 0.01 | 1 | 271 | rhodk = str2num(rhoinit_parms);
|
| 1 | 272 | rho_init = @(X, Y) (1-exp(rhodk.*(Y-b)))./(1-exp(rhodk.*(b1-b))).*forcing(X,Y);
|
| 1 | 273 | P_init = @(X, Y) app.g*((b-Y)-(1-exp(rhodk.*(Y-b)))./rhodk)./(1-exp(rhodk.*(b1-b))).*forcing(X,Y);
|
| | 274 |
|
| | 275 | case 'cosine+exponential'
|
| | 276 | rhodk = str2num(rhoinit_parms);
|
| | 277 | rho_init = @(X, Y) 0.5.*( 0.5*(1 - cos(pi*(b-Y)/(b-b1))) + (1-exp(rhodk.*(Y-b)))./(1-exp(rhodk.*(b1-b))) ).*forcing(X,Y);
|
| | 278 | P_init = @(X, Y) (app.g*0.5)*( 0.5*((b-Y) - ((b-b1)/pi).*sin(pi*(b-Y)/(b-b1))) + ((b-Y)-(1-exp(rhodk.*(Y-b)))./rhodk)./(1-exp(rhodk.*(b1-b))) ).*forcing(X,Y);
|
| | 279 |
|
| | 280 | case 'cosine+linear'
|
| | 281 | rho_init = @(X, Y) 0.5.*( 0.5*(1 - cos(pi*(b-Y)/(b-b1))) + (b-Y)./(b-b1) ).*forcing(X,Y);
|
| | 282 | P_init = @(X, Y) (app.g*0.5)*( 0.5*((b-Y) - ((b-b1)/pi).*sin(pi*(b-Y)/(b-b1))) + ((b-Y).^2)./(2.*(b-b1)) ).*forcing(X,Y);
|
| | 283 |
|
| | 284 | case 'linear+exponential'
|
| | 285 | rhodk = str2num(rhoinit_parms);
|
| | 286 | rho_init = @(X, Y) 0.5.*( (b-Y)./(b-b1) + (1-exp(rhodk.*(Y-b)))./(1-exp(rhodk.*(b1-b))) ).*forcing(X,Y);
|
| | 287 | P_init = @(X, Y) (app.g*0.5)*( ((b-Y).^2)./(2.*(b-b1)) + ((b-Y)-(1-exp(rhodk.*(Y-b)))./rhodk)./(1-exp(rhodk.*(b1-b))) ).*forcing(X,Y);
|
| | 288 | end;
|
| 1 | 289 | u_init = @(X, Y) zeros(size(X));
|
| 1 | 290 | v_init = @(X, Y) zeros(size(X));
|
| | 291 |
|
| | 292 | % Initialize the state variables with values from both boundary and internal cells.
|
| | 293 |
|
| | 294 | % Note: This is a standard procedure and should not be modified.
|
| | 295 |
|
< 0.01 | 1 | 296 | rho = [bcsDrho; bcsNrho; rho_init(XP(idsP), YP(idsP))];
|
< 0.01 | 1 | 297 | P = [bcsDq; bcsNq; P_init(XP(idsP), YP(idsP))];
|
| 1 | 298 | u = [bcsDu; bcsNu; u_init(XU(idsu), YU(idsu))];
|
| 1 | 299 | v = [bcsDv; bcsNv; v_init(XV(idsv), YV(idsv))];
|
| | 300 |
|
| | 301 | %keyboard
|
| | 302 |
|
| | 303 |
|
| | 304 | %% Set up density forcing term
|
| | 305 |
|
| | 306 | % Define density forcing term
|
| 1 | 307 | if ~isfield (app,'rhofrc_type')
|
| 1 | 308 | app.rhofrc_type = 'fullvert';
|
| 1 | 309 | end;
|
| 1 | 310 | switch app.rhofrc_type
|
| 1 | 311 | case 'fullvert'
|
| 1 | 312 | app.Frho = @(t, XY, rho) -kappa*(rho - 1).*((XY(:,1) <= a1)&(XY(:,2) >= b1));
|
| | 313 | case 'halfvert'
|
| | 314 | app.Frho = @(t, XY, rho) -kappa*(rho - (XY(:,2)<=(b+b1)*0.5)).*((XY(:,1) <= a1)&(XY(:,2) >= b1));
|
| | 315 | end;
|
| | 316 |
|
| | 317 |
|
| | 318 | %% Save all the setup data in a mat-file.
|
| | 319 |
|
0.48 | 1 | 320 | save(sprintf('%s/%s/setup', d0, app.savemat));
|