diff --git a/src/Science.hpp b/src/Science.hpp index 4110a58d0829a8b2d315efbdda1ae0fa66156d8b..24b459c0b039755d14cb37db5eec7fa9ead1b304 100644 --- a/src/Science.hpp +++ b/src/Science.hpp @@ -183,8 +183,6 @@ inline double nleos_inline(double T, double S){ } BZ_DECLARE_FUNCTION2(nleos_inline) - - void nleos(TArrayn::DTArray & rho, TArrayn::DTArray & T, TArrayn::DTArray & S); @@ -229,8 +227,6 @@ void quadeos(TArrayn::DTArray & rho, TArrayn::DTArray & T); void eos(const string eos_type, TArrayn::DTArray & rho, TArrayn::DTArray & T, TArrayn::DTArray & S, double T0 = -10, double S0 = -2); - - /* inline double fresh_quad(double T){ // Returns the density (kg/m^3) for water using simple quadratic fit to @@ -246,6 +242,13 @@ inline double fresh_quad(double T){ BZ_DECLARE_FUNCTION(fresh_quad) */ +// lambda2, second eigenvalue of S^2+Omega^2 +void compute_lambda2(TArrayn::DTArray & lambda2, TArrayn::DTArray & u, + TArrayn::DTArray & v, TArrayn::DTArray & w, TArrayn::DTArray & temp1, + TArrayn::DTArray & temp2, TArrayn::Grad * gradient_op, + const string * grid_type, TArrayn::DTArray & A11, TArrayn::DTArray & A12, + TArrayn::DTArray & A13, TArrayn::DTArray & A22, TArrayn::DTArray & A23, + TArrayn::DTArray & A33); // Equation of state for seawater, polynomial fit from // Brydon, Sun, Bleck (1999) (JGR) diff --git a/src/Science/compute_lambda2.cpp b/src/Science/compute_lambda2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abd08d62d940c41c535bfe9a72b3e48cc179ff42 --- /dev/null +++ b/src/Science/compute_lambda2.cpp @@ -0,0 +1,161 @@ +#include "../Science.hpp" +#include <blitz/array.h> +#include <string> +#include <math.h> + +using namespace Transformer; +using namespace blitz; + +// Calculates the second largest eigenvalue of S^2+Omega^2 +// S and Omega are the symmetric and antisymmetric components of u_i,j, respectively +// Note: S^2+Omega^2 = 0.5*(u_{i,k}u_{k,j}+u_{k,i}u_{j,k}) +// This is used to find coherent structures correlated with eddies in turbulent flow +void compute_lambda2(TArrayn::DTArray & lambda2, TArrayn::DTArray & u, + TArrayn::DTArray & v, TArrayn::DTArray & w, TArrayn::DTArray & temp1, + TArrayn::DTArray & temp2, TArrayn::Grad * gradient_op, + const string * grid_type, TArrayn::DTArray & A11, TArrayn::DTArray & A12, + TArrayn::DTArray & A13, TArrayn::DTArray & A22, TArrayn::DTArray & A23, + TArrayn::DTArray & A33) { + // Set-up + S_EXP expan[3]; + assert(gradient_op); + TArrayn::DTArray * A_ref; //This will hold references to the components + TArrayn::DTArray * vel_mm; //This will hold the velocities + TArrayn::DTArray * vel_nn; //This will hold the velocities + std::string vel_labs[3] = {"u","v","w"}; + + int ctr = 0; + // Construct S^2+Omega^2 + for (int mm=0; mm<3; mm++){ + for (int nn=mm; nn<3; nn++){ + // Choose which component will be constructed + if (ctr==0){A_ref = &A11;} + else if (ctr==1){A_ref = &A12;} + else if (ctr==2){A_ref = &A13;} + else if (ctr==3){A_ref = &A22;} + else if (ctr==4){A_ref = &A23;} + else if (ctr==5){A_ref = &A33;} + + // A switch for the velocities + // Useful for computing the u_{i,k}u_{j,k} terms + + if (mm==0){vel_mm = &u;} + else if (mm==1){vel_mm = &v;} + else if(mm==2){vel_mm = &w;} + if (nn==0){vel_nn = &u;} + else if (nn==1){vel_nn = &v;} + else if (nn==2){vel_nn = &w;} + + // u_{i,k}u_{k,j} + // Get u_{i,x} + find_expansion(grid_type, expan, vel_labs[mm]); + gradient_op->setup_array(vel_mm,expan[0],expan[1],expan[2]); + gradient_op->get_dx(&temp1,false); + // Get u_{x,j} + find_expansion(grid_type, expan, "u"); + gradient_op->setup_array(&u,expan[0],expan[1],expan[2]); + if (nn==0) { gradient_op->get_dx(&temp2,false); } + else if (nn==1) { gradient_op->get_dy(&temp2,false); } + else if (nn==2) { gradient_op->get_dz(&temp2,false); } + *A_ref = temp1 * temp2; + // Get u_{i,y} + find_expansion(grid_type, expan, vel_labs[mm]); + gradient_op->setup_array(vel_mm,expan[0],expan[1],expan[2]); + gradient_op->get_dy(&temp1,false); + // Get u_{y,j} + find_expansion(grid_type, expan, "v"); + gradient_op->setup_array(&v,expan[0],expan[1],expan[2]); + if (nn==0) { gradient_op->get_dx(&temp2,false); } + else if (nn==1) { gradient_op->get_dy(&temp2,false); } + else if (nn==2) { gradient_op->get_dz(&temp2,false); } + *A_ref = temp1 * temp2; + // Get u_{i,z} + find_expansion(grid_type, expan, vel_labs[mm]); + gradient_op->setup_array(vel_mm,expan[0],expan[1],expan[2]); + gradient_op->get_dz(&temp1,false); + // Get u_{z,j} + find_expansion(grid_type, expan, "w"); + gradient_op->setup_array(&w,expan[0],expan[1],expan[2]); + if (nn==0) { gradient_op->get_dx(&temp2,false); } + else if (nn==1) { gradient_op->get_dy(&temp2,false); } + else if (nn==2) { gradient_op->get_dz(&temp2,false); } + *A_ref = temp1 * temp2; + + + // u_{k,i}u_{j,k} + // Get u_{x,i} + find_expansion(grid_type, expan, "u"); + gradient_op->setup_array(&u,expan[0],expan[1],expan[2]); + if (mm==0) { gradient_op->get_dx(&temp1,false); } + else if (mm==1) { gradient_op->get_dy(&temp1,false); } + else if (mm==2) { gradient_op->get_dz(&temp1,false); } + // Get u_{j,x} + find_expansion(grid_type, expan, vel_labs[nn]); + gradient_op->setup_array(vel_nn,expan[0],expan[1],expan[2]); + gradient_op->get_dx(&temp2,false); + *A_ref = temp1 * temp2; + // Get u_{y,i} + find_expansion(grid_type, expan, "v"); + gradient_op->setup_array(&v,expan[0],expan[1],expan[2]); + if (mm==0) { gradient_op->get_dx(&temp1,false); } + else if (mm==1) { gradient_op->get_dy(&temp1,false); } + else if (mm==2) { gradient_op->get_dz(&temp1,false); } + // Get u_{j,y} + find_expansion(grid_type, expan, vel_labs[nn]); + gradient_op->setup_array(vel_nn,expan[0],expan[1],expan[2]); + gradient_op->get_dy(&temp2,false); + *A_ref = temp1 * temp2; + // Get u_{z,i} + find_expansion(grid_type, expan, "w"); + gradient_op->setup_array(&w,expan[0],expan[1],expan[2]); + if (mm==0) { gradient_op->get_dx(&temp1,false); } + else if (mm==1) { gradient_op->get_dy(&temp1,false); } + else if (mm==2) { gradient_op->get_dz(&temp1,false); } + // Get u_{j,z} + find_expansion(grid_type, expan, vel_labs[nn]); + gradient_op->setup_array(vel_nn,expan[0],expan[1],expan[2]); + gradient_op->get_dz(&temp2,false); + *A_ref = temp1 * temp2; + + *A_ref = (*A_ref)*0.5; + ctr++; + } + } + + // Now for the eigenvalue algorithm from: + // https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3%C3%973_matrices + + // In the above article, we transform A into B=(1/p)*(A-qI) + // Then, lambda2 = q + 2*p*cos(arccos(det(B)/2)/3 + k*pi/3), k=0,1,2 + // Define q + temp1 = (A11+A22+A33)/3.0; + // Define p + temp2 = pow2(A11-temp1) + pow2(A22-temp1) + pow2(A33-temp1) +2.0*(pow2(A12)+pow2(A13)+pow2(A23)); + temp2 = sqrt(temp2/6.0); + + // Transform A + A11 = (A11-temp1)/temp2; + A22 = (A22-temp1)/temp2; + A33 = (A33-temp1)/temp2; + A12 = A12/temp2; + A13 = A13/temp2; + A23 = A23/temp2; + + // Calculate the determinant, using lambda2 as a dummy array + lambda2 = 0.5*(A11*(A22*A33-A23*A23)-A12*(A12*A33-A13*A23)+A13*(A12*A23-A13*A22)); + + // Since det(B)/2 feeds into acos, make sure it's between -1 and 1 + for (int i = lambda2.lbound(blitz::firstDim); i <= lambda2.ubound(blitz::firstDim); i++) { // outer loop over slowest-varying dimension + for (int k = lambda2.lbound(blitz::thirdDim); k <= lambda2.ubound(blitz::thirdDim); k++) { // middle loop over next-slowest varying dimension + for (int j = lambda2.lbound(blitz::secondDim); j <= lambda2.ubound(blitz::secondDim); j++) { // inner loop over fastest varying dimeion + if (isnan(lambda2(i,j,k))) {lambda2(i,j,k) = 0;} + else if (lambda2(i,j,k) < -1.0) {lambda2(i,j,k) = -1.0;} + else if (lambda2(i,j,k) > 1.0) {lambda2(i,j,k) = 1.0;} + // first conditional works as a safety check because the det is NaN iff temp2=0; in this case the 2nd eig is temp1 + }}} + + // Now calculate the actual lamba2. + lambda2 = temp1+2.0*temp2*cos(acos(lambda2)/3.0+4.0*M_PI/3.0); + + +} diff --git a/src/VERSION b/src/VERSION index 882b025b720b8ddb68732c2992c7484ee47f79f2..ae8b19475b67f0169e4f6057b5c5728ce674b540 100644 --- a/src/VERSION +++ b/src/VERSION @@ -1,3 +1,3 @@ MAJOR_VERSION=2 MINOR_VERSION=1 -PATCH_VERSION=7 +PATCH_VERSION=8 diff --git a/src/cases/derivatives/derivatives.cpp b/src/cases/derivatives/derivatives.cpp index 21657117390cfa421e678a6415cd0468558fe3d6..e34cf225c1f576bd8c7423d00db8723d79d3b4fb 100644 --- a/src/cases/derivatives/derivatives.cpp +++ b/src/cases/derivatives/derivatives.cpp @@ -52,6 +52,7 @@ bool do_enst_stretch; // Do enstrophy production term from vortex bool do_Q; // Do second invariant of grad(u,v,w)? bool do_R; // Do third invariant/det of grad(u,v,w)? bool do_Q_and_R; // Do the second and third invariants? +bool do_lambda2; // Do lambda2/Hussain's Lambda? bool v_exist; // Does the v field exist? /* ------------------ Adjust the class --------------------- */ @@ -63,6 +64,7 @@ class userControl : public BaseCase { DTArray deriv_var; // array for derivative DTArray *temp1, *temp2, *temp3; // arrays for vortex stretching / enstrophy production DTArray *temp4; // array for storing temporary array for baroclinic vorticity + DTArray *A11, *A12, *A13, *A22, *A23, *A33; //Arrays for components of S^2+Omega^2 /* Size of domain */ double length_x() const { return Lx; } @@ -114,7 +116,7 @@ class userControl : public BaseCase { //string prev_deriv, base_field; vector<string> fields; // vector of fields to take derivatives split(deriv_filenames.c_str(), ' ', fields); // populate that vector - if ( do_vort_stretch or do_enst_stretch or do_Q or do_R or do_Q_and_R ) { + if ( do_vort_stretch or do_enst_stretch or do_Q or do_R or do_Q_and_R or do_lambda2 ) { temp1 = alloc_array(Nx,Ny,Nz); temp2 = alloc_array(Nx,Ny,Nz); if ( do_enst_stretch ) @@ -125,6 +127,14 @@ class userControl : public BaseCase { temp4 = alloc_array(Nx,Ny,Nz); } + if ( do_lambda2 ) { + A11 = alloc_array(Nx,Ny,Nz); + A12 = alloc_array(Nx,Ny,Nz); + A13 = alloc_array(Nx,Ny,Nz); + A22 = alloc_array(Nx,Ny,Nz); + A23 = alloc_array(Nx,Ny,Nz); + A33 = alloc_array(Nx,Ny,Nz); + } // Compute derivatives at each requested output for ( plotnum = start_sequence; plotnum <= final_sequence; plotnum = plotnum + step_sequence ) { @@ -231,7 +241,7 @@ class userControl : public BaseCase { write_array(deriv_var,"barx",plotnum); if (master()) fprintf(stdout,"Completed the write for barx.%d\n",plotnum); } - + compute_baroclinic_vort_y(deriv_var, u, gradient_op, grid_type); deriv_var=deriv_var*g; write_array(deriv_var,"bary",plotnum); @@ -245,7 +255,7 @@ class userControl : public BaseCase { if ( do_vor_x or do_vor_y or do_vor_z or do_enstrophy or do_dissipation or do_vort_stretch or do_enst_stretch or - do_Q or do_R or do_Q_and_R ) { + do_Q or do_R or do_Q_and_R or do_lambda2 ) { // u init_tracer_restart("u",u); // v @@ -372,6 +382,17 @@ class userControl : public BaseCase { write_array(deriv_var,"R",plotnum); if (master()) fprintf(stdout,"Completed the write for R.%d\n",plotnum); } + + // Calculate lambda2/second eigenvalue of S^2+Omega^2 + if ( do_lambda2 ){ + compute_lambda2( deriv_var, u, v, w, *temp1, *temp2, gradient_op, + grid_type, *A11, *A12, *A13, *A22, *A23, *A33); + double max_var = psmax(max(abs(deriv_var))); + if (master()) fprintf(stdout,"Max lam2: %.6g\n",max_var); + write_array(deriv_var,"lam2",plotnum); + if (master()) fprintf(stdout,"Completed the write for lam2.%d\n",plotnum); + + } } } @@ -419,7 +440,7 @@ int main(int argc, char ** argv) { add_option("type_z",&zgrid_type,"Grid type in Z"); option_category("Physical parameters"); - add_option("visco",&visco,0.0,"Viscosity"); + add_option("visco",&visco,1.0,"Viscosity"); add_option("rho_0",&rho_0,1000.0,"Reference Density"); add_option("g",&g,9.81,"Acceleration due to gravity"); @@ -443,6 +464,7 @@ int main(int argc, char ** argv) { add_option("do_Q",&do_Q,false,"Calculate Q?"); add_option("do_R",&do_R,false,"Calculate R?"); add_option("do_Q_and_R",&do_Q_and_R,false,"Calculate Q and R?"); + add_option("do_lambda2",&do_lambda2,false,"Calculate Lambda2?"); add_option("v_exist",&v_exist,"Does the v field exist?"); // Parse the options from the command line and config file options_parse(argc,argv); @@ -465,6 +487,17 @@ int main(int argc, char ** argv) { fprintf(stdout,"Simulation is 2 dimensional, " "Ly has been changed to 1.0 for normalization.\n"); } + if (visco==1.0){ + if (master()) + fprintf(stdout,"You may have forgotten to specify viscosity, " + "Using default value visco = 1.\n"); + } + + if (rho_0==1000.0){ + if (master()) + fprintf(stdout,"You may have forgotten to specify reference density, " + "Using default value rho_0 = 1000.\n"); + } /* ------------------ Do stuff --------------------- */ userControl mycode; // Create an instantiated object of the above class diff --git a/src/cases/derivatives/spins.conf b/src/cases/derivatives/spins.conf index 352e07a7d058b22f19f66eb1deb0da4c008cb935..8b53d2d202b4df0f4f8e2952e8768967c15ba688 100644 --- a/src/cases/derivatives/spins.conf +++ b/src/cases/derivatives/spins.conf @@ -40,4 +40,5 @@ do_enst_stretch = false do_barvor = false do_Q = false do_R = false -do_Q_and_R = true +do_Q_and_R = false +do_lambda2 = false