// generic 2D physics environment, with support for lateral and vertical advection and mixing, // sinking, variable light profiles, and boundary inputs. // this + a method for calculating the velocity field = tonicella. class Slice extends Environment { int M,K; float[] dx, dy, dz, z_rho, z_w, x_rho, x_u; int[] kbot, kbotu; float[][] Axy, Ayz, V; float[][] u, w, kappa; float[] KH; float[] sinkingRate, benthicLossFrac, benthicRecyclingFrac; BoundaryCondition leftBC = new BoundaryCondition(this); BoundaryCondition rightBC = new BoundaryCondition(this); BoundaryCondition[] lateralInputs = new BoundaryCondition[0]; int[] lateralInputM = new int[0]; Slice() {} Slice(Ecosystem eco, int M, int K, float Ltot, float Htot) { createDomain(M,K,Ltot,Htot); linkToEcosystem(eco); addParam("surface PAR","PAR0","W/m2", 150, 0, 300); allocateStorageForPhysics(); } Slice(Ecosystem eco, int M, int K, float Ltot, float Hhead, float Hmouth, float Bhead, float Bmouth) { createDomain(M,K,Ltot,Hhead,Hmouth,Bhead,Bmouth); linkToEcosystem(eco); addParam("surface PAR","PAR0","W/m2", 150, 0, 300); allocateStorageForPhysics(); } void allocateStorageForPhysics() { // define physical fluxes for (int vi=0; vi float archive.addNameValuePair("kbot",kbotf); float[] kbotuf = new float[M+1]; for (int i=0; i float archive.addNameValuePair("kbotu",kbotuf); } // geometry ------------------------------------------------------------------------ void createDomain(int M, int K, float Ltot, float Htot) { dx = new float[M]; for (int m=0; m=0; k--) { z_w[k] = z_w[k+1] - dz[k]; z_rho[k] = z_w[k+1] - dz[k]/2; } kbot = new int[M]; for (int m=0; m ind conversion internally. Statevar uvar = getVar("u"); Statevar wvar = getVar("w"); for (int m=0; m 0) { if (m==0) {upstreamConc = leftConc[k];} else {upstreamConc = vars[vi].current[km2ind(k,m-1)];} } else { if (m==M) {upstreamConc = rightConc[k];} else {upstreamConc = vars[vi].current[km2ind(k,m)];} } F[k][m] = Ayz[k][m] * u[k][m] * upstreamConc; // u must be 0 below kbot, otherwise this will be nonzero } } // extensive -> intensive Flux theFlux = getFlux("hAdv-" + vars[vi].shortname); for (int m=0; m 0) { F[k] = Axy[k][m] * w[k][m] * vars[vi].current[km2ind(k-1,m)]; } else { F[k] = Axy[k][m] * w[k][m] * vars[vi].current[km2ind(k,m)]; } } // convert to intensive fluxes for each grid cell Flux theFlux = getFlux("vAdv-" + vars[vi].shortname); for (int k=kbot[m]; k= kbotu[m]) { F[k][m] = -2 * Ayz[k][m] * KH[m] * (vars[vi].current[km2ind(k,m)] - vars[vi].current[km2ind(k,m-1)]) / (dx[m] + dx[m-1]); } } F[k][M] = - Ayz[k][M] * KH[M] * (rightConc[k] - vars[vi].current[km2ind(k,M-1)]) / dx[M-1]; } // extensive -> intensive Flux theFlux = getFlux("hDiff-" + vars[vi].shortname); for (int m=0; m intensive Flux theFlux = getFlux("sink-" + vars[vi].shortname); for (int k=kbot[m]; k= kbot[m]; k--) { float att = attTot(k,m); running_par *= exp(att * (z_rho[k] - z_w[k+1])); // attenuate down to cell center PAR.current[km2ind(k,m)] = running_par; running_par *= exp(att * (z_w[k] - z_rho[k])); // attenuate to bottom of cell } } } }