#include #include # include #include # include # include # include # include # include # include "AztecOO_config.h" # include "mpi.h" # include "Epetra_MpiComm.h" # include "Epetra_Map.h" # include "AztecOO.h" # include "Epetra_CrsMatrix.h" # include "Epetra_CrsGraph.h" # include "Epetra_FECrsMatrix.h" # include "Epetra_FECrsGraph.h" #include "Epetra_BlockMap.h" # include "Epetra_FEVector.h" # include "Epetra_Time.h" #include "Epetra_SerialDenseVector.h" #include "Epetra_SerialDenseMatrix.h" #include "ml_include.h" #include "ml_MultiLevelPreconditioner.h" #include "Teuchos_ParameterList.hpp" //#include "PrecondOperator.h" using namespace std; //prototypes for subs/functions ect. int main ( int argc, char *argv[] ); void assemble_jac(double psir_new[], double psii_new[],double a1_new[],double a2_new[],double xc[],double yc[], int indx[], int node[], double basis_der_vertex, double basis_der_midpt, double quad_weight[], int nx, int ny, int n_band, int n_triangles, int n_local, int n_nodes, int n_quad, int n_unknowns, int unknowns_node, int lde, int ldn, double xi, double lambda, double dt ,int tau, int nnz_row[], int ncc,const Epetra_MpiComm Comm , Epetra_FECrsMatrix &K, int iam ,int flag, int eps ) ; void eval_space_qdpt( int triangle, double psir_new[],double psii_new[], double a1_new[], double a2_new[], double xc[], double yc[],double basis_der_vertex,double basis_der_midpt, int node[],int n_local,int i_quad,int lde, int n_nodes, double& psir,double& psir_x,double& psir_y,double& psii,double& psii_x,double& psii_y, double& a1,double& a1_x,double& a1_y,double& a2,double& a2_x,double& a2_y ) ; void eval_space_time_qdpt( int triangle,double psir_old[],double psii_old[], double a1_old[],double a2_old[],double psir_new[], double psii_new[],double a1_new[],double a2_new[], double xc[],double yc[],double basis_der_vertex,double basis_der_midpt, int node[],int n_local,int i_quad,int lde, int n_nodes, double& psir,double& psir_x,double& psir_y, double& psir_t,double& psii,double& psii_x,double& psii_y,double& psii_t, double& a1,double& a1_x,double& a1_y,double& a1_t, double& a2,double& a2_x,double& a2_y,double& a2_t) ; void four_to_one(double a[],double b[],double c[],double d[], int indx[],int n_nodes,int n_unknowns,int ldn, double e[], int iam); void geometry (double x_length,double y_length, int nx, int ny,int flag_write, int lde,int ldn,int n_local,double n_quad,int& unknowns_node, double xc[],double yc[],double& basis_der_vertex,double& basis_der_midpt, double quad_weight[],int indx[],int node[], int& n_band,int& n_triangles,int& n_nodes,int& n_unknowns, int& ind_num, int *&nnz_row, double &jac); void ind_find(int &count,int nnz_row[], int num, int i_nodes, int indx[]); void st_set_up(int indx[],int node[],int n_triangles,int unknowns_node,int n_unknowns,int n_local, int n_nodes,int n_quad,int ldn,int lde, Epetra_CrsGraph & Graph, int iam); void st_set_up_2(int indx[],int node[],int n_triangles,int unknowns_node,int n_unknowns,int n_local, int n_nodes,int n_quad,int ldn,int lde,Epetra_FECrsMatrix& K); void init( int ldn, double psir[],double psii[],double a1[],double a2[] ); void nonlinear_solver(int nx,int ny,int n_band,int n_triangles,int n_local,int n_nodes, int n_quad,int n_unknowns,int unknowns_node,int lde,int ldn, double xi,double lambda,double h_external,double tol_newton,double n_newton,double time_cur, double &dt,double dt_min,double dt_max,int flag_jacobian,int flag_write,double xc[],double yc[], double basis_der_vertex,double basis_der_midpt,double quad_weight[],int indx[],int node[], double psir_old[],double psii_old[],double a1_old[],double a2_old[], double psir_new[],double psii_new[],double a1_new[],double a2_new[],int& n_nonlinear,double tau,int nnz_row[], int ncc, const Epetra_MpiComm Comm ,int iam , int &flag,Epetra_FECrsMatrix &K,Epetra_Vector &F, Epetra_Vector &x,AztecOO &solver, double &s_st_t,double &j_st_t, int eps, Epetra_Map &Map); void one_to_four (double f[],int indx[],int n_nodes,int n_unknowns,int ldn, double a[],double b[],double c[],double d[]); void output (double psir_new[],double psii_new[],double a1_new[],double a2_new[],int *node,int lde,int nx,int ny, double xi,double lambda,double h_external,double time_cur,int n_count,double quad_weight[], double basis_der_midpt,double basis_der_vertex,int n_triangles,int n_local,int n_nodes,int n_quad, double xc[], double yc[],int &flag, string s,double jac ); void quad_basis_fn(int it,int i_local,int i_quad, double basis_der_vertex,double basis_der_midpt,double& basis,double& basis_x,double& basis_y ) ; void residual (double psir_old[],double psii_old[],double a1_old[],double a2_old[], double psir_new[],double psii_new[],double a1_new[],double a2_new[], double xc[],double yc[],int indx[],int node[], double basis_der_vertex,double basis_der_midpt,double quad_weight[],int nx,int ny, int n_triangles,int n_local,int n_nodes,int n_quad,int n_unknowns, int unknowns_node,int lde,int ldn,double xi,double lambda,double h_external, double dt,double resid_psir[],double resid_psii[],double resid_a1[], double resid_a2[],double tau,int eps, double time_cur ) ; void r8ge_fs ( int n, double a[], double x[] ); double r8_abs ( double x ); int st_to_cc_size ( int nst, int ist[], int jst[] ); void st_to_cc_index ( int nst, int ist[], int jst[], int ncc, int n, int icc[], int ccc[] ); int *i4vec_copy_new ( int n, int a1[] ); void i4vec2_sort_a ( int n, int a1[], int a2[] ); void i4vec2_sorted_uniquely ( int n1, int a1[], int b1[], int n2, int a2[], int b2[] ); void sort_heap_external ( int n, int &indx, int &i, int &j, int isgn ); int i4vec2_compare ( int n, int a1[], int a2[], int i, int j ); int i4vec2_sorted_unique_count ( int n, int a1[], int a2[] ); void qbf (int q_point, int element, int inode, double xc[],double yc[], int element_node[], int element_num, int nnodes, int node_num, double &b, double &dbdx, double &dbdy ); int main ( int argc, char *argv[]) //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // TIME-DEPENDENT SUPERCONDUCTIVTY PROGRAM // 2-D, RECTANGULAR DOMAIN // ZERO ELECTRIC POTENTIAL GAUGE // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // MODELS INCLUDED: // 1. GINZBURG-LANDAU // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // DISCRETIZATION: FINITE ELEMENT METHOD IN SPACE // USING QUADRATICS ON TRIANGLES // AND BACKWARD EULER IN TIME // SOLUTION: NEWTON'S METHOD or Fixed Jacobian // // // // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // // INPUT // { MPI_Init(&argc,&argv); Epetra_MpiComm Comm( MPI_COMM_WORLD ); double x_length = 10., y_length = 10.; // size of the box double lambda = 0.5 ; // coherence length double xi = 0.05;//0.1 // penetration depth double kappa = lambda/xi ; // Ginzburg Landau parameter double h_external= 0.15*kappa;//1.0;//2.0;//0.5;//0.5*kappa // External field double tau=1.0;//0.4; double eps=1.0; double time_init=0.0, time_final= 5000000.0; // initial and final times double dt_max = 50.;//5000. ; // maximum time step allowed double dt_init = 0.1 ; // initial time step double dt_min = 0.001 ; // minimum time step allowed double dt_factor = 1.5 ; // factor to increase time step double tol_newton_loose = .1e-6;//6 ; // Newton tolerance (initial) double tol_newton_tight = .1e-11 ; // Newton tolerance (final) int n_newton = 8 ; // maximum allowable newton steps int n_timesteps=10000000 ; // maximum number of allowable timesteps int nx = 721, ny =721; // number of nodes in x and y directions int lde = (nx-1) * (ny-1) * 2 ; // leading dimension of arrays dimensioned by element number int ldn = (2* nx-1)*(2* ny-1) ; // leading dimension of arrays dimensioned by node number int n_local = 6 ; // number of local nodes per element int n_quad = 3;//3 ; // number of quadrature points per element int unknowns_node = 4 ; // number of unknowns per node (psi real, imag, A1, A2) int flag_write = 4 ; // flag for write statements (=0 least, =5 most) int flag_init = 0 ; // flag for initialization (=0 generate initial conditions, // = 1 read from file) int flag_output = 25;//25 ; // flag for writing data to file every # of time steps int flag_jacobian = 1 ; // update jacobian every # of iterations (=1 => Newton) int flag_steady = 15 ; // flag for determining steady state // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // GEOMETRY // double xc[ldn],yc[ldn]; // x and y coordinates of nodes double quad_weight[n_quad]; // area of triangles * quadrature weight (1/3) for Midpoint rule double basis_der_vertex;//value of derivative of basis fn centered at vertex at qd pt double basis_der_midpt; //value of derivative of basis fn centered at midpt at qd pt int indx[ldn*4]; // unknown numbering array int node[lde*n_local]; // array associating local and global nodes int n_band; // half bandwidth +1 int n_triangles; // number of triangles int n_nodes; // number of global nodes int n_unknowns; // number of unknowns int ind_num,ncc; int *ia, *ja; int *icc; int *ccc; int *nnz_row; double s_st_t,j_st_t; double jac; // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // SOLUTION // double psir_old[ldn], psii_old[ldn]; // order PARAMETER at previous timestep double a1_old[ldn], a2_old[ldn]; // magnetic potential at previous timestep double psir_new[ldn], psii_new[ldn]; // order PARAMETER at current Newton step double a1_new[ldn], a2_new[ldn]; // magnetic potential at current Newton step double dt; double tol_newton; // current Newton tolerance int n_nonlinear; // number of nonlinear iterations required to solve at given timestep int n_steady; // counter for reaching steady state //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // LOCAL VARIABLES // int i, k; int n_count; // count for number of time steps in a row that nonlinear solver converged in < criteria int n_call_output,flag; // number of calls to output double time_cur; ifstream output1; ofstream output2; ofstream output3; ofstream output4; ofstream output5; ofstream output6; int sum; int iam; double nlt_st,nlt_fin,nlt, start,finish; stringstream ss; string s; // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // MPI_Comm_rank(MPI_COMM_WORLD, &iam); //h_external=atof(argv[1]); if (iam==0){ //ss <> s; s="hey"; output1.open ( "init_out.data" , std::ifstream::in); output2.open ( "order_test.data", std::ofstream::out | std::ofstream::trunc); output3.open ( "current_test.data", std::ofstream::out | std::ofstream::trunc); output4.open ( "magnetic_test.data", std::ofstream::out | std::ofstream::trunc); output5.open ( "init_out_test.data", ofstream::out | ofstream::trunc); output6.open ( "time_step_test.data", ofstream::out | ofstream::trunc); } n_nonlinear=0; n_count = 0; nlt=0.0; flag=1;//0 s_st_t=0.0; j_st_t=0.0; // // SET UP GEOMETRY // start=MPI_Wtime(); geometry( x_length, y_length, nx, ny, flag_write, lde, ldn, n_local, n_quad, unknowns_node, xc, yc, basis_der_vertex, basis_der_midpt, quad_weight, indx, node, n_band, n_triangles, n_nodes, n_unknowns, ind_num,nnz_row,jac ); sum=0; for ( i= 0; i < n_unknowns; i++ ){ sum+=nnz_row[i]; } Epetra_Map Map(n_unknowns,0,Comm); Epetra_CrsGraph Graph(Copy,Map,nnz_row); st_set_up( indx,node,n_triangles,unknowns_node,n_unknowns,n_local, n_nodes,n_quad,ldn,lde, Graph, iam); Epetra_FECrsMatrix K(Copy,Graph); Epetra_Vector F(Map); Epetra_Vector x(Map); Epetra_LinearProblem problem(&K, &x, &F); AztecOO solver(problem); solver.SetAztecOption(AZ_output, AZ_warnings); // if (iam==0){ cout<< "number of nodes = "<< n_nodes <>psir_old[k]; output1>>psii_old[k]; output1>>a1_old[k] ; output1>>a2_old[k] ; } } // for ( i= 0; i < n_nodes; i++ ){ // set initial guess for nonlinear system to be solution at previous timestep psir_new[i] = psir_old[i]; psii_new[i] = psii_old[i]; a1_new[i] = a1_old[i]; a2_new[i] = a2_old[i] ; } // // * * TIMESTEPPING LOOP * * // dt = dt_init ; n_call_output = 0; // counter for calls to output tol_newton = tol_newton_loose; // for ( k= 0; k< n_timesteps; k++ ){ // begin time step loop time_cur = time_cur + dt; if ( time_cur > time_final ) time_cur = time_final; if (iam ==0){ cout<< "^^^^^^^^^^^^^^^^^*"<= 0 ){ for ( l= 0; l < unknowns_node; l++ ){ column_number = indx[j_global*4+l]; //i1 = max ( 1, j-n_band-1 ); if ( column_number >= 0 ) { indices[0]=row_number; indices[1]=column_number; local_indices_r(0)=indices[0]; local_indices_c(0)=indices[1]; k_local(0,0)=temp[k*4+l]; temp2[0]=temp[k*4+l]; if( flag==0)K.InsertGlobalValues(local_indices_r,local_indices_c,k_local); if( flag==1) K.SumIntoGlobalValues(local_indices_r,local_indices_c,k_local); } } } // } } // } // } // } if (iam==0) cout<<"before global asseble"<= 0) { //e[kk-1] = c[k] ; e[kk-1] = c[k] ; } else{ kk=kk-1; } // if( indx[k*4+3] >= 0){ //e[kk] = d[k] ; e[kk] = d[k] ;// migth have issues with skipping indc } else{ kk=kk-1; } // } // return; } // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // void geometry (double x_length,double y_length, int nx, int ny,int flag_write, int lde,int ldn,int n_local,double n_quad,int& unknowns_node, double xc[],double yc[],double& basis_der_vertex,double& basis_der_midpt, double quad_weight[],int indx[],int node[], int& n_band,int& n_triangles,int& n_nodes,int& n_unknowns, int& ind_num,int *&nnz_row, double &jac) { //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // ROUTINE TO SET UP GEOMETRIC INFORMATION // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // // Local variables int i_triangle, i_nodes, i_unknowns, n_col, j, midpt_col, n_row, i, midpt_row, i_triangle_plus_one,node_plus_nrow, node1, node2, node3, node4, node5, node6, node_plus_two_nrow, it, i_local, i_global, i_unknown, j_local, j_global, j_unknown, j_minus_i, ip, n, k, i1, i2, i3, j1, j2, j3,counter; double dx, dy, yy, xx, x1, x2, x3, y1, y2, y3, xm1, xm2, xm3, ym1, ym2, ym3, det, b, c, s, t, x, y; // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // n_row = nx + nx -1; n_col = ny + ny -1; ; // number of nodes in row and column dx = x_length/double(nx-1); dy = y_length/double(ny-1) ; // delta x, delta y for quadratics // yy = -dy/2. ; i_triangle = -2;//-1 ; // counter for triangles i_nodes = -1;//0 ; // counter for global nodes i_unknowns = 0 ; // counter for unknown number ind_num=0; // // counter=0; for ( j= 0; j< n_col; j++ ) { midpt_col = (j+1)%2 ; // flag to determine if at vertical midpoint node (when midpt_col=0) //cout<= 0 ) { // for ( j_local= 0; j_local< n_local; j_local++ ){ j_global = node[i_triangle*n_local+ j_local]; // for ( j_unknown= 0; j_unknown< unknowns_node; j_unknown++ ){ j = indx[j_global*4+j_unknown] ; if (j>=0) ind_num+=1; if(i <= j) { // only use upper half j_minus_i = j - i ; if( j_minus_i > n_band ) n_band = j_minus_i ; } // } // } // } // } // } // } // n_band=n_band + 1 ; // n_band computed is number of upper diagonals // return; } ///////////////////////////////////////////////////////////////////////////////////////////////// void ind_find(int &counter,int nnz_row[], int num, int i_nodes, int indx[]) { nnz_row[counter]=0; nnz_row[counter]+=num*2; if ( indx[i_nodes*4+2]>=0){ nnz_row[counter]+=num; } if ( indx[i_nodes*4+3]>=0){ nnz_row[counter]+=num; } counter+=1; //////////////////////////////////// nnz_row[counter]=0; nnz_row[counter]+=num*2; if ( indx[i_nodes*4+2]>=0){ nnz_row[counter]+=num ; } if ( indx[i_nodes*4+3]>=0){ nnz_row[counter]+=num; } counter+=1; ////////////////////// if ( indx[i_nodes*4+2]>=0){ nnz_row[counter]=0; nnz_row[counter]+=num*3; if ( indx[i_nodes*4+3]>=0){ nnz_row[counter]+=num ; } counter+=1; } ////////////////////////////// if ( indx[i_nodes*4+3]>=0){ nnz_row[counter]=0; nnz_row[counter]+=num*3; if ( indx[i_nodes*4+2]>=0){ nnz_row[counter]+=num; } counter+=1; } return; } // // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* void st_set_up(int indx[],int node[],int n_triangles,int unknowns_node,int n_unknowns,int n_local, int n_nodes,int n_quad,int ldn,int lde, Epetra_CrsGraph & Graph, int iam) { ////////////////////////////////////////////////////////////// //Local variables int i_triangle, i_nodes, i_unknowns, n_col, j, midpt_col, n_row, i, i_local, i_global, i_unknown, j_local, j_global, j_unknown, j_minus_i, k; int counter; ////////////////////////////////////////////////////////////// counter=0; for ( i_triangle= 0; i_triangle< n_triangles; i_triangle++ ){ // for ( i_local= 0; i_local< n_local; i_local++ ){ i_global = node[i_triangle*n_local+ i_local]; // for ( i_unknown = 0; i_unknown < unknowns_node; i_unknown ++ ){ i = indx[i_global*4+i_unknown]; if( i >=0 ) { // for ( j_local= 0; j_local< n_local; j_local++ ){ j_global = node[i_triangle*n_local+ j_local]; // for ( j_unknown= 0; j_unknown< unknowns_node; j_unknown++ ){ j = indx[j_global*4+j_unknown] ; if( j >= 0 ) { Graph.InsertGlobalIndices(i,1,&j); } } // } // } // } // } // } // Graph.FillComplete(); Graph.OptimizeStorage(); return; } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // void st_set_up_2(int indx[],int node[],int n_triangles,int unknowns_node,int n_unknowns,int n_local, int n_nodes,int n_quad,int ldn,int lde,Epetra_FECrsMatrix &K) { ////////////////////////////////////////////////////////////// //Local variables int i_triangle, i_nodes, i_unknowns, n_col, j, midpt_col, n_row, i, i_local, i_global, i_unknown, j_local, j_global, j_unknown, j_minus_i, k; int counter; ////////////////////////////////////////////////////////////// Epetra_SerialDenseMatrix k_local(1,1);// maybe (0,0)? Epetra_IntSerialDenseVector local_indices_r(1); //maybe (0)? Epetra_IntSerialDenseVector local_indices_c(1); //maybe (0)? counter=0; for ( i_triangle= 0; i_triangle< n_triangles; i_triangle++ ){ // for ( i_local= 0; i_local< n_local; i_local++ ){ i_global = node[i_triangle*n_local+ i_local]; // for ( i_unknown = 0; i_unknown < unknowns_node; i_unknown ++ ){ i = indx[i_global*4+i_unknown]; if( i >=0 ) { // for ( j_local= 0; j_local< n_local; j_local++ ){ j_global = node[i_triangle*n_local+ j_local]; // for ( j_unknown= 0; j_unknown< unknowns_node; j_unknown++ ){ j = indx[j_global*4+j_unknown] ; if( j >= 0 ) { local_indices_r(0)=i; local_indices_c(0)=j; k_local(0,0)=0.0; K.ReplaceGlobalValues(local_indices_r,local_indices_c,k_local);//(row_number,1,temp[k*4+l], column_number); } } // } // } // } // } // } // K.GlobalAssemble(); K.OptimizeStorage (); return; } void init( int ldn, double psir[],double psii[],double a1[],double a2[] ) { // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // SET-UP INITIAL CONDITIONS // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // // INPUT //int ldn; // leading dimension of array dimensioned by global nodes // // OUTPUT //double psir[ldn], psii[ldn]; // order parameter at previous timestep //double a1[ldn], a2[ldn]; // magnetic potential at previous timestep int i; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // Set magnetic potential to zero and order PARAMETER so that (psi)^2 = 1 // for ( i = 0; i < ldn; i ++ ){ psir[i] = 0.8000000000000000; psii[i] = 0.600000000000000; a1[i] = 0.000000000000000000000000000; a2[i] = 0.00000000000000000000000000; } return; } // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // void nonlinear_solver(int nx,int ny,int n_band,int n_triangles,int n_local,int n_nodes, int n_quad,int n_unknowns,int unknowns_node,int lde,int ldn, double xi,double lambda,double h_external,double tol_newton,double n_newton,double time_cur, double &dt,double dt_min,double dt_max,int flag_jacobian,int flag_write,double xc[],double yc[], double basis_der_vertex,double basis_der_midpt,double quad_weight[],int indx[],int node[], double psir_old[],double psii_old[],double a1_old[],double a2_old[], double psir_new[],double psii_new[],double a1_new[],double a2_new[],int& n_nonlinear,double tau, int nnz_row[],int ncc, const Epetra_MpiComm Comm , int iam , int &flag , Epetra_FECrsMatrix &K,Epetra_Vector &F, Epetra_Vector &x,AztecOO &solver, double &s_st_t,double &j_st_t, int eps, Epetra_Map &Map ) { // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // NEWTON ITERATION // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // // // // Allocatable variables //double *a_coeff; // coefficient matrix //double *a_lu; // coefficient matrix double rhs[n_unknowns]; // right hand side vector //double *rhs_new; // right hand side vector double resid_a1[n_nodes], resid_a2[n_nodes]; // residual for magnetic potential double resid_psir[n_nodes], resid_psii[n_nodes]; // residual for order potential double delta_a1[n_nodes], delta_a2[n_nodes]; // increment for magnetic potential double delta_psir[n_nodes], delta_psii[n_nodes]; // increment for order potential // // Local variables int k, kk, n_rhs, info, n_lband, i,ii,array1[4],array2[4],indi[n_unknowns]; double norm_resid_psi, norm_resid_a, norm_resid, s_st,s_fin,j_st,j_fin,nl_st,nl_fin,nl_per_it ; double temp1, temp2,*temp; // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* start:; //CONTINUE nl_st=MPI_Wtime(); // // Newton iteration loop // Teuchos::ParameterList MLList; // keep here not above /*ML_Epetra::SetDefaults("DD", MLList); MLList.set("max levels",2); MLList.set("increasing or decreasing","increasing"); MLList.set("aggregation: type", "ParMETIS");//metis doesnt work with DD (i guess) MLList.set("aggregation: nodes per aggregate", 16); MLList.set("smoother: pre or post", "both"); MLList.set("coarse: type","Gauss-Seidel"); // gS works better //MLList.set("smoother: type", "Gauss-Seidel"); MLList.set("smoother: type", "Aztec"); */ //PrecondOperator PrecondOp(Comm,&Map); /* // set default values for smoothed aggregation in MLList ML_Epetra::SetDefaults("SA",MLList); // DD-ML gets iter from 96 to 65 at start. WAS SA.. DD-ML-LU take more iters but it QUICK IN TImE!!!!! // overwrite with user’s defined parameters // although fast i think it used alot of mem. MLList.set("max levels",6);//2 was 6 for SA //MLList.set("PDE equations",4); // new MLList.set("increasing or decreasing","decreasing"); MLList.set("aggregation: type", "ParMETIS");//MIS// but metis works here?? // ^ I NEED TO SET THIS TO MIS OR SOMETHING BESIDES PARMETIS TO AVOID KEY PROBLEEM... altealst for SA //MLList.set("aggregation: smoothing sweeps", 3);//new //MLList.set("repartition: partitioner","ParMETIS"); // new MLList.set("coarse: type","Gauss-Seidel");//"Amesos-KLU"); MLList.set("smoother: type","Aztec");// seems to work good! WAS NOT HERE */ // gets 30 fucking iters on start.... ML_Epetra::SetDefaults("DD-ML",MLList); // DD-ML gets iter from 96 to 65 at start. WAS SA.. DD-ML-LU take more iters but it QUICK IN TImE!!!!! // overwrite with user’s defined parameters // although fast i think it used alot of mem. MLList.set("max levels",3);//2 was 6 for SA MLList.set("PDE equations",4); // lowered iters tremendously.. MLList.set("increasing or decreasing","decreasing"); MLList.set("aggregation: type", "METIS");//MIS// but metis works here?? // ^ I NEED TO SET THIS TO MIS OR SOMETHING BESIDES PARMETIS TO AVOID KEY PROBLEEM... altealst for SA //MLList.set("aggregation: smoothing sweeps", 3);//new //MLList.set("repartition: partitioner","ParMETIS"); // new MLList.set("coarse: type","Gauss-Seidel");//"Amesos-KLU"); MLList.set("smoother: type","Aztec");// seems to work good! WAS NOT HERE //for DD and DD-ML and DD-ML-LU Teuchos::RCP> options = Teuchos::rcp(new vector(AZ_OPTIONS_SIZE)); Teuchos::RCP> params = Teuchos::rcp(new vector(AZ_PARAMS_SIZE)); //AZ_defaults(options,params); // complains about rcp vectors... AZ_defaults(&(*options)[0],&(*params)[0]); (*options)[AZ_precond] = AZ_dom_decomp; (*options)[AZ_subdomain_solve] = AZ_icc; MLList.set("smoother: Aztec options", options); MLList.set("smoother: Aztec params", params); //ML_Epetra::SetDefaults("DD",MLList,options,params); you might need this as well // create the preconditioner ML_Epetra::MultiLevelPreconditioner* MLPrec = new ML_Epetra::MultiLevelPreconditioner(K, MLList, false); for ( k = 0; k < n_newton; k ++ ){ norm_resid_psi=0.000000000000000; norm_resid_a = 0.000000000000000; norm_resid = 0.000000000000000; // should be elements lde not ncc ??? //Epetra_Map Map(-1, n_unknowns, 0, Comm);// worked with 4*lde so tri nunk //Epetra_Vector F(Map); j_st=MPI_Wtime(); // // compute residual -- right hand side of Newton linear system residual ( psir_old, psii_old, a1_old, a2_old, psir_new, psii_new, a1_new, a2_new, xc, yc, indx, node, basis_der_vertex, basis_der_midpt, quad_weight, nx, ny, n_triangles, n_local, n_nodes, n_quad, n_unknowns, unknowns_node, lde, ldn, xi, lambda, h_external, dt, resid_psir, resid_psii, resid_a1, resid_a2,tau,eps,time_cur) ; // // calculate norm of residual for ( ii = 0; ii < n_nodes; ii ++ ){ norm_resid_psi += ( resid_psir[ii]*resid_psir[ii] + resid_psii[ii]*resid_psii[ii] ) ; norm_resid_a +=( resid_a1[ii]*resid_a1[ii] + resid_a2[ii]*resid_a2[ii] ) ; //print *, "norm residuals", norm_resid_psi, norm_resid_a } norm_resid_psi=sqrt(norm_resid_psi / double(n_nodes) ); norm_resid_a = sqrt(norm_resid_a / double(n_nodes) ) ; norm_resid = max ( norm_resid_psi, norm_resid_a ); // // output Newton residual information if(flag_write >= 2) { if (iam==0){ cout<< " After "<< k<< "Nonlinear iterates "< 10^4 ) GO TO 100 ; // residual too large so reduce time step // //check to see if solution is good enough; if so, output; if not, do a Newton step // // if ( norm_resid < tol_newton ){ // solution good enough so write out GFE, etc. nl_fin=MPI_Wtime(); nl_per_it=nl_fin-nl_st; if (iam==0){ cout<< " NONLINEAR ITERATION CONVERGED in "<< k<< " steps "<ComputePreconditioner(); solver.SetPrecOperator(MLPrec); if( iam==0) cout<<"Past compute Precond"<DestroyPreconditioner(); s_fin=MPI_Wtime() ; /*for (ii=0; ii= 0) { k = k+1; c[kk] = f[k]; } // if( indx[kk*4+3] >= 0) { k = k+1; d[kk] = f[k]; } // k = k + 1; } // return; } // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* void output (double psir_new[],double psii_new[],double a1_new[],double a2_new[],int *node,int lde,int nx,int ny, double xi,double lambda,double h_external,double time_cur,int n_count,double quad_weight[], double basis_der_midpt,double basis_der_vertex,int n_triangles,int n_local,int n_nodes,int n_quad, double xc[], double yc[],int &flag, string s,double jac) { // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*c // COMPUTE MAGNITUDE OF THE ORDER PARAMETER, THE GIBBS FREE ENERGY, AVERAGE // FIELD, BULK MAGNETIZATION, MAGNETIC FIELD,AND COMPONENTS OF THE CURRENT // // // LOCAL VARIABLES int i_triangle, i_quad, i, j, k, i_start, i_end; int n_row, n_col,ii; double order_parameter[n_nodes]; double current_1[n_triangles], current_2[n_triangles], magnetic_field[n_triangles]; double psir, psir_x, psir_y, psii, psii_x, psii_y, a1, a1_x, a1_y, a2, a2_x, a2_y, psi_sq, a_sq, curl_a, grad_psir_sq,grad_psii_sq, a_dot_grad_psir, a_dot_grad_psii, gibbs_free_energy, average_magnetic_field, bulk_magnetization, one_over_lambda, area_triangle, total_area,one_over_lambdasq; ifstream output1; ofstream output2; ofstream output3; ofstream output4; ofstream output5; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* // output1.open ( "init_out.data" , ofstream::out | ofstream::app); output2.open ( "order_test.data", ofstream::out | ofstream::app); output3.open ( "current_test.data", ofstream::out | ofstream::app); output4.open ( "magnetic_test.data", ofstream::out | ofstream::app); output5.open ( "init_out_test.data", ofstream::out | ofstream::trunc); //flag=1; one_over_lambda = 1. / lambda; one_over_lambdasq = one_over_lambda * one_over_lambda; area_triangle =jac;// quad_weight * 3.0; // // compute magnitude of order parameter for ( ii = 0; ii < n_nodes; ii ++ ){ order_parameter[ii] = sqrt( psir_new[ii]*psir_new[ii] + psii_new[ii]*psii_new[ii] ); } // // compute Gibbs free energy, bulk magnetic field, bulk magnetization // gibbs_free_energy = 0.0; average_magnetic_field = 0.0; bulk_magnetization = 0.0; // for ( i_triangle = 0; i_triangle < n_triangles ;i_triangle++ ){ magnetic_field[i_triangle] = 0.0; current_1[i_triangle] = 0.0; current_2[i_triangle] = 0.0; // for ( i_quad = 0; i_quad < n_quad ;i_quad++ ){ eval_space_qdpt( i_triangle, psir_new, psii_new, a1_new, a2_new, xc, yc, basis_der_vertex, basis_der_midpt, node, n_local, i_quad, lde, n_nodes, psir, psir_x, psir_y, psii, psii_x, psii_y, a1, a1_x, a1_y, a2, a2_x, a2_y ) ; psi_sq = psir*psir + psii*psii; a_sq = a1*a1 + a2*a2 ; curl_a = a2_x - a1_y; grad_psir_sq = psir_x * psir_x + psir_y * psir_y; grad_psii_sq = psii_x * psii_x + psii_y * psii_y; a_dot_grad_psir = a1 * psir_x + a2 * psir_y; a_dot_grad_psii = a1 * psii_x + a2 * psii_y; // gibbs_free_energy = gibbs_free_energy +( psi_sq * ( .5 * psi_sq + a_sq * one_over_lambdasq - 1. ) + curl_a * ( curl_a - 2. * h_external ) + xi * ( xi * ( grad_psir_sq + grad_psii_sq ) + 2. * one_over_lambda * ( psii * a_dot_grad_psir - psir * a_dot_grad_psii ) ) )* quad_weight[i_quad]; // magnetic_field[i_triangle] = magnetic_field[i_triangle] + curl_a* quad_weight[i_quad]; current_1[i_triangle] = current_1[i_triangle] + (xi * ( psir * psii_x - psii * psir_x ) - psi_sq * a1 * one_over_lambda) * quad_weight[i_quad]; current_2[i_triangle] = current_2 [i_triangle] + (xi * ( psir * psii_y - psii * psir_y ) - psi_sq * a2 * one_over_lambda) * quad_weight[i_quad]; // } // // set magnetic field and current over an element // and also contributions to average field // magnetic_field[i_triangle] = magnetic_field[i_triangle] / area_triangle; current_1[i_triangle] = current_1[i_triangle] / area_triangle; current_2[i_triangle] = current_2[i_triangle] / area_triangle; average_magnetic_field = average_magnetic_field + magnetic_field[i_triangle]; // } // // set average field over region and bulk magnetization // total_area = area_triangle * double(n_triangles); average_magnetic_field = average_magnetic_field / double(n_triangles) ; bulk_magnetization = h_external - average_magnetic_field; // // print out results & write psi_sq, current and magnetic field vectors to file cout<< "Gibbs free energy = "<< gibbs_free_energy<= 0 ) resid_a1[i_global] = resid_a1[i_global] +sqrt(dt)*quad_weight[i_quad]*( -(h_external) * basis_y - eps*(a1_x + a2_y ) * basis_x + ( a2_x - a1_y ) * basis_y + test_term_a1); // // residual for A-2 test function if ( indx[i_global*4+3] >= 0 ) resid_a2[i_global] = resid_a2[i_global] +sqrt(dt)*quad_weight[i_quad]*( h_external * basis_x - eps*(a1_x + a2_y ) * basis_y - ( a2_x - a1_y ) * basis_x + test_term_a2) ; // } // } // } // /*for ( ii = 0; ii < n_nodes; ii ++ ){ resid_psir[ii] = resid_psir[ii] * quad_weight; resid_psii[ii] = resid_psii[ii] * quad_weight; resid_a1[ii] = resid_a1[ii] * quad_weight; resid_a2[ii] = resid_a2[ii] * quad_weight; }*/ // return; } // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^* //****************************************************************************80 int st_to_cc_size ( int nst, int ist[], int jst[] ) //****************************************************************************80 // // Purpose: // // ST_TO_CC_SIZE sizes CC indexes based on ST data. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 15 July 2014 // // Author: // // John Burkardt // // Parameters: // // Input, int NST, the number of ST elements. // // Input, int IST[NST], JST[NST], the ST rows and columns. // // Output, int ST_TO_CC_SIZE, the number of CC elements. // { int *ist2; int *jst2; int ncc; // // Make copies so the sorting doesn't confuse the user. // ist2 = i4vec_copy_new ( nst, ist ); jst2 = i4vec_copy_new ( nst, jst ); // // Sort by column first, then row. // i4vec2_sort_a ( nst, jst2, ist2 ); // // Count the unique pairs. // ncc = i4vec2_sorted_unique_count ( nst, jst2, ist2 ); delete [] ist2; delete [] jst2; return ncc; } void st_to_cc_index ( int nst, int ist[], int jst[], int ncc, int n, int icc[], int ccc[] ) //****************************************************************************80 // // Purpose: // // ST_TO_CC_INDEX creates CC indices from ST data. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 15 July 2014 // // Author: // // John Burkardt // // Parameters: // // Input, int NST, the number of ST elements. // // Input, int IST[NST], JST[NST], the ST rows and columns. // // Input, int NCC, the number of CC elements. // // Input, int N, the number of columns in the matrix. // // Output, int ICC[NCC], the CC rows. // // Output, int CCC[N+1], the compressed CC columns. // // IM GOING TO FLIP thiS SO IT COMPRESSES row not CC, need to know convention you can get non zeros { int *ist2; int j; int *jcc; int jhi; int jlo; int *jst2; int k; // // Make copies so the sorting doesn't confuse the user. // ist2 = i4vec_copy_new ( nst, ist ); jst2 = i4vec_copy_new ( nst, jst ); // // Sort the elements. // i4vec2_sort_a ( nst, jst2, ist2 ); // // Get the unique elements. // jcc = new int[ncc]; i4vec2_sorted_uniquely ( nst, jst2, ist2, ncc, jcc, ccc ); // // Compress the \x column x\ -> row index. // icc[0] = 0; jlo = 0; for ( k = 0; k < ncc; k++ ) { jhi = jcc[k]; if ( jhi != jlo ) { for ( j = jlo + 1; j <= jhi; j++ ) { icc[j] = k; } jlo = jhi; } } jhi = n; for ( j = jlo + 1; j <= jhi; j++ ) { icc[j] = ncc; } delete [] ist2; delete [] jcc; delete [] jst2; return; } //****************************************************************************80 int *i4vec_copy_new ( int n, int a1[] ) //****************************************************************************80 // // Purpose: // // I4VEC_COPY_NEW copies an I4VEC. // // Discussion: // // An I4VEC is a vector of I4's. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 04 July 2008 // // Author: // // John Burkardt // // Parameters: // // Input, int N, the number of entries in the vectors. // // Input, int A1[N], the vector to be copied. // // Output, int I4VEC_COPY_NEW[N], the copy of A1. // { int *a2; int i; a2 = new int[n]; for ( i = 0; i < n; i++ ) { a2[i] = a1[i]; } return a2; } //****************************************************************************80 void i4vec2_sort_a ( int n, int a1[], int a2[] ) //****************************************************************************80 // // Purpose: // // I4VEC2_SORT_A ascending sorts an I4VEC2. // // Discussion: // // Each item to be sorted is a pair of integers (I,J), with the I // and J values stored in separate vectors A1 and A2. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 11 September 2003 // // Author: // // John Burkardt // // Parameters: // // Input, int N, the number of items of data. // // Input/output, int A1[N], A2[N], the data to be sorted.. // { int i; int indx; int isgn; int j; int temp; // // Initialize. // i = 0; indx = 0; isgn = 0; j = 0; // // Call the external heap sorter. // for ( ; ; ) { sort_heap_external ( n, indx, i, j, isgn ); // // Interchange the I and J objects. // if ( 0 < indx ) { temp = a1[i-1]; a1[i-1] = a1[j-1]; a1[j-1] = temp; temp = a2[i-1]; a2[i-1] = a2[j-1]; a2[j-1] = temp; } // // Compare the I and J objects. // else if ( indx < 0 ) { isgn = i4vec2_compare ( n, a1, a2, i, j ); } else if ( indx == 0 ) { break; } } return; } //****************************************************************************80 void i4vec2_sorted_uniquely ( int n1, int a1[], int b1[], int n2, int a2[], int b2[] ) //****************************************************************************80 // // Purpose: // // I4VEC2_SORTED_UNIQUELY keeps the unique elements in an I4VEC2. // // Discussion: // // Item I is stored as the pair A1(I), A2(I). // // The items must have been sorted, or at least it must be the // case that equal items are stored in adjacent vector locations. // // If the items were not sorted, then this routine will only // replace a string of equal values by a single representative. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 15 July 2014 // // Author: // // John Burkardt // // Parameters: // // Input, int N1, the number of items. // // Input, int A1[N1], B1[N1], the input array. // // Input, int N2, the number of unique items. // // Input, int A2[N2], B2[N2], the output array of unique items. // { int i1; int i2; i1 = 0; i2 = 0; if ( n1 <= 0 ) { return; } a2[i2] = a1[i1]; b2[i2] = b1[i1]; for ( i1 = 1; i1 < n1; i1++ ) { if ( a1[i1] != a2[i2] || b1[i1] != b2[i2] ) { i2 = i2 + 1; a2[i2] = a1[i1]; b2[i2] = b1[i1]; } } return; } //****************************************************************************80 void sort_heap_external ( int n, int &indx, int &i, int &j, int isgn ) //****************************************************************************80 // // Purpose: // // SORT_HEAP_EXTERNAL externally sorts a list of items into ascending order. // // Discussion: // // The actual list is not passed to the routine. Hence it may // consist of integers, reals, numbers, names, etc. The user, // after each return from the routine, will be asked to compare or // interchange two items. // // The current version of this code mimics the FORTRAN version, // so the values of I and J, in particular, are FORTRAN indices. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 06 January 2013 // // Author: // // Original FORTRAN77 version by Albert Nijenhuis, Herbert Wilf. // C++ version by John Burkardt // // Reference: // // Albert Nijenhuis, Herbert Wilf, // Combinatorial Algorithms, // Academic Press, 1978, second edition, // ISBN 0-12-519260-6. // // Parameters: // // Input, int N, the length of the input list. // // Input/output, int &INDX. // The user must set INDX to 0 before the first call. // On return, // if INDX is greater than 0, the user must interchange // items I and J and recall the routine. // If INDX is less than 0, the user is to compare items I // and J and return in ISGN a negative value if I is to // precede J, and a positive value otherwise. // If INDX is 0, the sorting is done. // // Output, int &I, &J. On return with INDX positive, // elements I and J of the user's list should be // interchanged. On return with INDX negative, elements I // and J are to be compared by the user. // // Input, int ISGN. On return with INDX negative, the // user should compare elements I and J of the list. If // item I is to precede item J, set ISGN negative, // otherwise set ISGN positive. // { static int i_save = 0; static int j_save = 0; static int k = 0; static int k1 = 0; static int n1 = 0; // // INDX = 0: This is the first call. // if ( indx == 0 ) { i_save = 0; j_save = 0; k = n / 2; k1 = k; n1 = n; } // // INDX < 0: The user is returning the results of a comparison. // else if ( indx < 0 ) { if ( indx == -2 ) { if ( isgn < 0 ) { i_save = i_save + 1; } j_save = k1; k1 = i_save; indx = -1; i = i_save; j = j_save; return; } if ( 0 < isgn ) { indx = 2; i = i_save; j = j_save; return; } if ( k <= 1 ) { if ( n1 == 1 ) { i_save = 0; j_save = 0; indx = 0; } else { i_save = n1; j_save = 1; n1 = n1 - 1; indx = 1; } i = i_save; j = j_save; return; } k = k - 1; k1 = k; } // // 0 < INDX: the user was asked to make an interchange. // else if ( indx == 1 ) { k1 = k; } for ( ; ; ) { i_save = 2 * k1; if ( i_save == n1 ) { j_save = k1; k1 = i_save; indx = -1; i = i_save; j = j_save; return; } else if ( i_save <= n1 ) { j_save = i_save + 1; indx = -2; i = i_save; j = j_save; return; } if ( k <= 1 ) { break; } k = k - 1; k1 = k; } if ( n1 == 1 ) { i_save = 0; j_save = 0; indx = 0; i = i_save; j = j_save; } else { i_save = n1; j_save = 1; n1 = n1 - 1; indx = 1; i = i_save; j = j_save; } return; } //****************************************************************************80 int i4vec2_compare ( int n, int a1[], int a2[], int i, int j ) //****************************************************************************80 // // Purpose: // // I4VEC2_COMPARE compares pairs of integers stored in two vectors. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 11 September 2003 // // Author: // // John Burkardt // // Parameters: // // Input, int N, the number of data items. // // Input, int A1[N], A2[N], contain the two components of each item. // // Input, int I, J, the items to be compared. These values will be // 1-based indices for the arrays A1 and A2. // // Output, int I4VEC2_COMPARE, the results of the comparison: // -1, item I < item J, // 0, item I = item J, // +1, item J < item I. // { int isgn; isgn = 0; if ( a1[i-1] < a1[j-1] ) { isgn = -1; } else if ( a1[i-1] == a1[j-1] ) { if ( a2[i-1] < a2[j-1] ) { isgn = -1; } else if ( a2[i-1] < a2[j-1] ) { isgn = 0; } else if ( a2[j-1] < a2[i-1] ) { isgn = +1; } } else if ( a1[j-1] < a1[i-1] ) { isgn = +1; } return isgn; } //****************************************************************************80 int i4vec2_sorted_unique_count ( int n, int a1[], int a2[] ) //****************************************************************************80 // // Purpose: // // I4VEC2_SORTED_UNIQUE_COUNT counts unique elements in an I4VEC2. // // Discussion: // // Item I is stored as the pair A1(I), A2(I). // // The items must have been sorted, or at least it must be the // case that equal items are stored in adjacent vector locations. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 12 July 2014 // // Author: // // John Burkardt // // Parameters: // // Input, int N, the number of items. // // Input, int A1[N], A2[N], the array of N items. // // Output, int I4VEC2_SORTED_UNIQUE_COUNT, the number of unique items. // { int i; int iu; int unique_num; unique_num = 0; if ( n <= 0 ) { return unique_num; } iu = 0; unique_num = 1; for ( i = 1; i < n; i++ ) { if ( a1[i] != a1[iu] || a2[i] != a2[iu] ) { iu = i; unique_num = unique_num + 1; } } return unique_num; } //****************************************************************************80 void qbf (int q_point, int element, int inode, double xc[],double yc[], int element_node[], int element_num, int nnodes, int node_num, double &b, double &dbdx, double &dbdy ) //What i need to do is just read in quad number and figure out which thing i should be doing. // I.e. skip all the crap with x and y and just do r and s on the unit triangle. //****************************************************************************80 // // Purpose: // // QBF evaluates the quadratic basis functions. // // Discussion: // // This routine assumes that the "midpoint" nodes are, in fact, // exactly the average of the two extreme nodes. This is NOT true // for a general quadratic triangular element. // // Assuming this property of the midpoint nodes makes it easy to // determine the values of (R,S) in the reference element that // correspond to (X,Y) in the physical element. // // Once we know the (R,S) coordinates, it's easy to evaluate the // basis functions and derivatives. // // The physical element T6: // // In this picture, we don't mean to suggest that the bottom of // the physical triangle is horizontal. However, we do assume that // each of the sides is a straight line, and that the intermediate // points are exactly halfway on each side. // // | // | // | 3 // | / \ // | / \ // Y 6 5 // | / \ // | / \ // | 1-----4-----2 // | // +--------X--------> // // Reference element T6: // // In this picture of the reference element, we really do assume // that one side is vertical, one horizontal, of length 1. // // | // | // 1 3 // | |\ // | | \ // S 6 5 // | | \ // | | \ // 0 1--4--2 // | // +--0--R--1--------> // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 23 September 2008 // // Author: // // John Burkardt // // Parameters: // // Input, double X, Y, the (global) coordinates of the point // at which the basis function is to be evaluated. // // Input, int ELEMENT, the index of the element which contains the point. // // Input, int INODE, the local index (between 1 and 6) that // specifies which basis function is to be evaluated. // // Input, double NODE_XY[2*NODE_NUM], the nodes. // // Input, int ELEMENT_NODE[NNODES*ELEMENT_NUM]; // ELEMENT_NODE(I,J) is the global index of local node I in element J. // // Input, int ELEMENT_NUM, the number of elements. // // Input, int NNODES, the number of nodes used to form one element. // // Input, int NODE_NUM, the number of nodes. // // Output, double *B, *DBDX, *DBDY, the value of the basis function // and its X and Y derivatives at (X,Y). // { double dbdr; double dbds; double det; double drdx; double drdy; double dsdx; double dsdy; int i; double r; double s; double xn[6]; double yn[6]; for ( i = 0; i < 6; i++ ) { xn[i] = xc[(element_node[i+(element)*nnodes])]; yn[i] = yc[(element_node[i+(element)*nnodes])]; } // // Determine the (R,S) coordinates corresponding to (X,Y). // // What is happening here is that we are solving the linear system: // // ( X2-X1 X3-X1 ) * ( R ) = ( X - X1 ) // ( Y2-Y1 Y3-Y1 ) ( S ) ( Y - Y1 ) // // by computing the inverse of the coefficient matrix and multiplying // it by the right hand side to get R and S. // // The values of dRdX, dRdY, dSdX and dSdY are easily from the formulas // for R and S. // //3 pooint if (q_point==0){ r= 0.50000000000000000000; s=0.000000000000000000000; } if (q_point==1){ r=0.500000000000000000000; s= 0.50000000000000000000; } if (q_point==2){ r= 0.00000000000000000000; s= 0.50000000000000000000; } /* // 6 point 3rd order if (q_point==0){ r=0.659027622374092; s=0.231933368553031; } if (q_point==1){ r=0.659027622374092; s= 0.109039009072877; } if (q_point==2){ r=0.231933368553031; s=0.659027622374092; } if (q_point==3){ r=0.231933368553031; s= 0.109039009072877; } if (q_point==4){ r=0.109039009072877; s= 0.659027622374092; } if (q_point==5){ r=0.109039009072877; s= 0.231933368553031; } */ // 7 point 5th order /*if (q_point==0){ r=0.33333333333333333; s=0.33333333333333333; } if (q_point==1){ r= 0.79742698535308720; s= 0.10128650732345633; } if (q_point==2){ r=0.10128650732345633; s=0.79742698535308720; } if (q_point==3){ r=0.10128650732345633; s= 0.10128650732345633; } if (q_point==4){ r=0.05971587178976981; s= 0.47014206410511505; } if (q_point==5){ r=0.47014206410511505; s=0.05971587178976981; } if (q_point==6){ r=0.47014206410511505; s=0.47014206410511505; } */ det = ( xn[1] - xn[0] ) * ( yn[2] - yn[0] ) - ( xn[2] - xn[0] ) * ( yn[1] - yn[0] ); // r = ( ( yn[2] - yn[0] ) * ( x - xn[0] ) // + ( xn[0] - xn[2] ) * ( y - yn[0] ) ) / det; drdx = ( yn[2] - yn[0] ) / det; drdy = ( xn[0] - xn[2] ) / det; //s = ( ( yn[0] - yn[1] ) * ( x - xn[0] ) //+ ( xn[1] - xn[0] ) * ( y - yn[0] ) ) / det; dsdx = ( yn[0] - yn[1] ) / det; dsdy = ( xn[1] - xn[0] ) / det; // // The basis functions can now be evaluated in terms of the // reference coordinates R and S. It's also easy to determine // the values of the derivatives with respect to R and S. // if ( inode == 0 ) { b = 2.0E+00 * ( 1.0E+00 - r - s ) * ( 0.5E+00 - r - s ); dbdr = - 3.0E+00 + 4.0E+00 * r + 4.0E+00 * s; dbds = - 3.0E+00 + 4.0E+00 * r + 4.0E+00 * s; } else if ( inode == 1 ) { b = 2.0E+00 * r * ( r - 0.5E+00 ); dbdr = - 1.0E+00 + 4.0E+00 * r; dbds = 0.0E+00; } else if ( inode == 2 ) { b = 2.0E+00 * s * ( s - 0.5E+00 ); dbdr = 0.0E+00; dbds = - 1.0E+00 + 4.0E+00 * s; } else if ( inode == 3 ) { b = 4.0E+00 * r * ( 1.0E+00 - r - s ); dbdr = 4.0E+00 - 8.0E+00 * r - 4.0E+00 * s; dbds = - 4.0E+00 * r; } else if ( inode == 4 ) { b = 4.0E+00 * r * s; dbdr = 4.0E+00 * s; dbds = 4.0E+00 * r; } else if ( inode == 5 ) { b = 4.0E+00 * s * ( 1.0E+00 - r - s ); dbdr = - 4.0E+00 * s; dbds = 4.0E+00 - 4.0E+00 * r - 8.0E+00 * s; } else { cout << "\n"; cout << "QBF - Fatal error!\n"; cout << " Request for local basis function INODE = " << inode << "\n"; exit ( 1 ); } // // We need to convert the derivative information from (R(X,Y),S(X,Y)) // to (X,Y) using the chain rule. // dbdx = dbdr * drdx + dbds * dsdx; dbdy = dbdr * drdy + dbds * dsdy; return; } //****************************************************************************80