///Calculate Exp[I*m] LaGenMatComplex snake::math::expm2(LaGenMatDouble &m) { //std::cout<<m<<std::endl; int dim = m.size(0); LaGenMatComplex r(dim,dim); LaGenMatDouble eigvec(dim,dim); LaGenMatComplex eigvecC(dim,dim); LaVectorDouble eigval(dim); LaVectorComplex eigvalim(dim); eigvec = m; snake::math::SSMED(eigvec.addr(),dim,eigval.addr()); for(int i = 0;i<dim;i++) eigvalim(i) = LaComplex(cos(eigval(i)),sin(eigval(i))); LaGenMatComplex temp(dim,dim); temp = LaComplex(0,0); for(int i = 0;i<dim;i++) temp(i,i) = eigvalim(i); chop(temp,1e-15); //std::cout<<temp<<std::endl; eigvecC = eigvec.to_LaGenMatComplex(); LaGenMatComplex tempx(dim,dim); Blas_Mat_Mat_Trans_Mult(temp,eigvecC,tempx); Blas_Mat_Mat_Mult(eigvecC,tempx,r); chop(r,1e-15); return r; }
int main(int argc, char *argv[]) { std::string library_routine(rokko::serial_dense_solver::default_solver()); std::string library, routine; unsigned int dim = 10; if (argc >= 2) library_routine = argv[1]; if (argc >= 3) dim = boost::lexical_cast<int>(argv[2]); rokko::split_solver_name(library_routine, library, routine); std::cout.precision(5); std::cout << "Eigenvalue decomposition of Frank matrix" << std::endl << "library:routine = " << library_routine << std::endl << "library = " << library << std::endl << "routine = " << routine << std::endl << "dimension = " << dim << std::endl; rokko::serial_dense_solver solver(library); solver.initialize(argc, argv); rokko::localized_matrix<double, matrix_major> mat(dim, dim); rokko::frank_matrix::generate(mat); std::cout << "Frank matrix:\n" << mat << std::endl; rokko::localized_vector<double> eigval(dim); rokko::localized_matrix<double, matrix_major> eigvec(dim, dim); rokko::parameters params; params.set("upper_value", 1.2); params.set("lower_value", 0.1); //params.set("upper_index", 5); //params.set("lower_index", 3); params.set("uplow", 'L'); //params.set("uplow", 'lower'); params.set("verbose", true); try { default_diagonalize(mat, eigval, eigvec, params); //default_diagonalize(mat, eigval, params); } catch (const char *e) { std::cout << "Exception : " << e << std::endl; exit(22); } rokko::frank_matrix::generate(mat); bool sorted = true; for (unsigned int i = 1; i < dim; ++i) sorted &= (eigval(i-1) <= eigval(i)); if (!sorted) std::cout << "Warning: eigenvalues are not sorted in ascending order!\n"; std::cout << "eigenvalues:\n" << eigval.transpose() << std::endl << "eigvectors:\n" << eigvec << std::endl; std::cout << "orthogonality of eigenvectors:" << std::endl << eigvec.transpose() * eigvec << std::endl; std::cout << "residual of the smallest eigenvalue/vector (A x - lambda x):" << std::endl << (mat * eigvec.col(0) - eigval(0) * eigvec.col(0)).transpose() << std::endl; solver.finalize(); }
Real RankTwoScalarAux::calcEigenValues() { std::vector<Real> eigval(LIBMESH_DIM); Real val = 0.0; unsigned int max_index = 2; unsigned int mid_index = 1; unsigned int min_index = 0; if (LIBMESH_DIM == 2) max_index = 1; _tensor[_qp].symmetricEigenvalues(eigval); switch (_scalar_type) { case 4: val = eigval[max_index]; break; case 5: if (LIBMESH_DIM == 2) mooseError("RankTwoScalarAux Error: No Mid Principal value when LIBMESH_DIM is 2"); val = eigval[mid_index]; break; case 6: val = eigval[min_index]; break; default: mooseError("RankTwoScalarAux Error: Pass valid scalar type - VonMisesStress, EquivalentPlasticStrain, Hydrostatic, L2norm MaxPrincipal MidPrincipal MinPrincipal"); } return val; }
void ClassicalScaling::run( PointWiseMapping* mymap ){ // Retrieve the distances from the dimensionality reduction object double half=(-0.5); Matrix<double> distances( half*mymap->modifyDmat() ); // Apply centering transtion unsigned n=distances.nrows(); double sum; // First HM for(unsigned i=0;i<n;++i){ sum=0; for(unsigned j=0;j<n;++j) sum+=distances(i,j); for(unsigned j=0;j<n;++j) distances(i,j) -= sum/n; } // Now (HM)H for(unsigned i=0;i<n;++i){ sum=0; for(unsigned j=0;j<n;++j) sum+=distances(j,i); for(unsigned j=0;j<n;++j) distances(j,i) -= sum/n; } // Diagonalize matrix std::vector<double> eigval(n); Matrix<double> eigvec(n,n); diagMat( distances, eigval, eigvec ); // Pass final projections to map object for(unsigned i=0;i<n;++i){ for(unsigned j=0;j<mymap->getNumberOfProperties();++j) mymap->setProjectionCoordinate( i, j, sqrt(eigval[n-1-j])*eigvec(n-1-j,i) ); } }
int main(int argc, char *argv[]) { std::string solver_name(rokko::serial_dense_solver::default_solver()); std::string lattice_file("xyz.dat"); if (argc >= 2) solver_name = argv[1]; if (argc >= 3) lattice_file = argv[2]; std::cout.precision(5); int num_sites; std::vector<std::pair<int, int> > lattice; std::vector<boost::tuple<double, double, double> > coupling; rokko::read_lattice_file(lattice_file, num_sites, lattice, coupling); int dim = 1 << num_sites; rokko::serial_dense_solver solver(solver_name); solver.initialize(argc, argv); std::cout << "Eigenvalue decomposition of XYZ model" << std::endl << "solver = " << solver_name << std::endl << "lattice file = " << lattice_file << std::endl << "number of sites = " << num_sites << std::endl << "number of bonds = " << lattice.size() << std::endl << "matrix dimension = " << dim << std::endl; rokko::localized_matrix<double, matrix_major> mat(dim, dim); rokko::xyz_hamiltonian::generate(num_sites, lattice, coupling, mat); rokko::localized_vector<double> eigval(dim); rokko::localized_matrix<double, matrix_major> eigvec(dim, dim); try { solver.diagonalize(mat, eigval, eigvec); } catch (const char *e) { std::cout << "Exception : " << e << std::endl; exit(22); } rokko::xyz_hamiltonian::generate(num_sites, lattice, coupling, mat); std::cout << "smallest eigenvalues:"; for (int i = 0; i < std::min(dim, 10); ++i) std::cout << ' ' << eigval(i); std::cout << std::endl; std::cout << "residual of the smallest eigenvalue/vector: |x A x - lambda| = " << std::abs(eigvec.col(0).transpose() * mat * eigvec.col(0) - eigval(0)) << std::endl; solver.finalize(); }
///Calculate square matrix exponent LaGenMatDouble snake::math::expm(LaGenMatDouble &m) { //std::cout<<m<<std::endl; int dim = m.size(0); LaGenMatDouble r(dim,dim); LaGenMatDouble eigvec(dim,dim); LaVectorDouble eigval(dim); eigvec = m; snake::math::SSMED(eigvec.addr(),dim,eigval.addr()); for(int i = 0;i<dim;i++) eigval(i) = exp(eigval(i)); LaGenMatDouble temp(dim,dim); temp = temp.from_diag(eigval); //std::cout<<temp<<std::endl; Blas_Mat_Mat_Trans_Mult(temp,eigvec,m); Blas_Mat_Mat_Mult(eigvec,m,r); chop(r,1e-15); return r; }
arma::rowvec rmvnormx(arma::mat R, arma::rowvec Z){ Rcpp::RNGScope scope; int m = R.n_rows; arma::vec eigval(m); arma::mat eigvec(m, m); arma::mat temp(m, m); arma::eig_sym(eigval, eigvec, R); arma::rowvec ans(m); temp = ( eigvec * arma::diagmat( arma::sqrt( eigval ) ) * arma::inv( eigvec ) ); ans = Z * temp; return ans; }
armapca::pca_result<T> pca(const arma::Mat<T>& data, bool compute_eigenvectors) { EXPECTS(data.n_rows >= 2); EXPECTS(data.n_cols >= 1); const auto n_vars = data.n_cols; armapca::pca_result<T> result; arma::Mat<T> eigvec; if (compute_eigenvectors) { result.eigenvectors.set_size(n_vars, n_vars); eigvec.set_size(n_vars, n_vars); } result.eigenvalues.set_size(n_vars); arma::Col<T> eigval(n_vars); const auto cov_mat = armapca::covariance_matrix(data); if (compute_eigenvectors) { arma::eig_sym(eigval, eigvec, cov_mat); } else { arma::eig_sym(eigval, cov_mat); } const arma::uvec indices = arma::sort_index(eigval, 1); for (std::size_t i=0; i < n_vars; ++i) { result.eigenvalues(i) = eigval(indices(i)); } if (compute_eigenvectors) { for (std::size_t i=0; i < n_vars; ++i) { result.eigenvectors.col(i) = eigvec.col(indices(i)); } armapca::enforce_positive_sign_by_column(&result.eigenvectors); } result.energy = arma::sum(result.eigenvalues); result.eigenvalues *= T {1} / result.energy; return result; }
void pca::solve() { assert_num_vars_(); printf("%i", num_records_); if (num_records_ < 2) throw std::logic_error("Number of records smaller than two."); data_.resize(num_records_, num_vars_); mean_ = utils::compute_column_means(data_); //mean_ = utils::compute_column_means(data_, w_); utils::remove_column_means(data_, mean_); mean_.print(); sigma_ = utils::compute_column_rms(data_); if (do_normalize_) utils::normalize_by_column(data_, sigma_); arma::Col<double> eigval(num_vars_); arma::Mat<double> eigvec(num_vars_, num_vars_); arma::Mat<double> cov_mat = utils::make_covariance_matrix(data_); arma::eig_sym(eigval, eigvec, cov_mat, solver_.c_str()); arma::uvec indices = arma::sort_index(eigval, 1); for (long i=0; i<num_vars_; ++i) { eigval_(i) = eigval(indices(i)); eigvec_.col(i) = eigvec.col(indices(i)); } utils::enforce_positive_sign_by_column(eigvec_); proj_eigvec_ = eigvec_; proj_eigvec_.print(); princomp_ = data_ * eigvec_; energy_(0) = arma::sum(eigval_); eigval_ *= 1./energy_(0); if (do_bootstrap_) bootstrap_eigenvalues_(); }
void pca::bootstrap_eigenvalues_() { std::srand(bootstrap_seed_); arma::Col<double> eigval(num_vars_); arma::Mat<double> dummy(num_vars_, num_vars_); for (long b=0; b<num_bootstraps_; ++b) { const arma::Mat<double> shuffle = utils::make_shuffled_matrix(data_); const arma::Mat<double> cov_mat = utils::make_covariance_matrix(shuffle); arma::eig_sym(eigval, dummy, cov_mat, solver_.c_str()); eigval = arma::sort(eigval, 1); energy_boot_(b) = arma::sum(eigval); eigval *= 1./energy_boot_(b); eigval_boot_.row(b) = eigval.t(); } }
int main () { // Define symmetric matrix PLMD::Matrix<double> mat1(3,3); PLMD::OFile out; out.open("output"); mat1(0,0)=1.0; mat1(0,1)=0.2; mat1(0,2)=0.3; mat1(1,0)=0.2; mat1(1,1)=0.2; mat1(1,2)=0.6; mat1(2,0)=0.3; mat1(2,1)=0.6; mat1(2,2)=0.4; // Test diagonalize std::vector<double> eigval(3); PLMD::Matrix<double> eigvec(3,3); diagMat( mat1, eigval, eigvec ); out<<"Eigenvalues "<<eigval[0]<<" "<<eigval[1]<<" "<<eigval[2]<<"\n"; out<<"Eigenvectors : \n"; for(unsigned i=0;i<3;++i){ out<<eigvec(i,0)<<" "<<eigvec(i,1)<<" "<<eigvec(i,2)<<"\n"; } // Test inverse out<<"Inverse : \n"; PLMD::Matrix<double> inverse(3,3); Invert( mat1, inverse ); for(unsigned i=0;i<3;++i){ for(unsigned j=0;j<3;++j) out<<inverse(i,j)<<" "; out<<"\n"; } // Test pseudoinverse out<<"Pseudoinverse : \n"; PLMD::Matrix<double> mat(3,2); mat(0,0)=0.1; mat(0,1)=0.2; mat(1,0)=0.3; mat(1,1)=0.5; mat(2,0)=0.4; mat(2,1)=0.6; PLMD::Matrix<double> pseu(2,3); pseudoInvert( mat, pseu ); for(unsigned i=0;i<pseu.nrows();++i){ for(unsigned j=0;j<pseu.ncols();++j) out<<" "<<pseu(i,j); out<<"\n"; } out.close(); return 0; }
PCA& PCA::fit( const std::vector< std::vector< double > >& data ) { const size_t nSamples = data.size(); const size_t nFeatures = data.front().size(); // Calculate the means vector arma::mat meansVector( nFeatures, 1 ); for ( size_t iFeature = 0; iFeature < nFeatures; ++iFeature ) { double sx = 0; for ( size_t iSample = 0; iSample < nSamples; ++iSample ) { const double value = data[iSample][iFeature]; if ( std::isnan(value) ) throw std::runtime_error( "PCA::fit : nan value encountered at input!" ); sx += value; } meansVector(iFeature, 0) = sx / nSamples; } // Construct the covariance matrix from the scatter matrix arma::mat covMatrix( nFeatures, nFeatures, arma::fill::zeros ); for ( size_t iSample = 0; iSample < nSamples; ++iSample ) { arma::mat sampleData( data[iSample ] ); arma::mat d = sampleData - meansVector; covMatrix += d * d.t(); } covMatrix /= nSamples; // Now find the eigenvalues and eigenvectors arma::cx_vec eigval; arma::cx_mat eigvec; bool result = arma::eig_gen(eigval, eigvec, covMatrix ); if (! result ) { throw std::runtime_error("PCA::fit : eigenvalue decomposition failed!"); } // Normalise the eigenvalues m_eigPairs.clear(); m_eigPairs.reserve( nFeatures ); double eigSum = 0; for ( size_t iFeature = 0; iFeature < nFeatures; ++iFeature ) { const double eigMagnitude = std::abs( eigval(iFeature) ); arma::cx_vec eigenVectorFromCalculation = eigvec.row( iFeature ); std::vector<double> eigenVector( nFeatures, 0.0 ); for (size_t j = 0; j < nFeatures; ++j ) eigenVector[j] = eigenVectorFromCalculation(j).real(); m_eigPairs.push_back( std::make_pair( eigMagnitude, eigenVector ) ); eigSum += eigMagnitude; } for ( size_t iFeature = 0; iFeature < nFeatures; ++iFeature ) { m_eigPairs[iFeature].first /= eigSum; } // Sort the eigenValues std::sort( m_eigPairs.begin(), m_eigPairs.end(), [] (const std::pair<double, std::vector<double> >&a, const std::pair<double, std::vector<double> >&b ) { return a.first > b.first; } ); return *this; }
int main(int argc, char *argv[]) { int provided; MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); MPI_Comm comm = MPI_COMM_WORLD; std::string solver_name(rokko::parallel_dense_solver::default_solver()); int L = 8; if (argc >= 2) solver_name = argv[1]; if (argc >= 3) L = boost::lexical_cast<int>(argv[2]); rokko::grid g(comm); int myrank = g.get_myrank(); std::cout.precision(5); int dim = 1 << L; std::vector<std::pair<int, int> > lattice; for (int i = 0; i < L; ++i) { lattice.push_back(std::make_pair(i, (i+1) % L)); } rokko::parallel_dense_solver solver(solver_name); solver.initialize(argc, argv); if (myrank == 0) std::cout << "Eigenvalue decomposition of antiferromagnetic Heisenberg chain" << std::endl << "num_procs = " << g.get_nprocs() << std::endl #ifdef _OPENMP << "num_threads per process = " << omp_get_max_threads() << std::endl #endif << "solver = " << solver_name << std::endl << "L = " << L << std::endl << "dimension = " << dim << std::endl; rokko::distributed_matrix<double, matrix_major> mat(dim, dim, g, solver); rokko::heisenberg_hamiltonian::generate(L, lattice, mat); rokko::localized_matrix<double, matrix_major> mat_loc(dim, dim); rokko::gather(mat, mat_loc, 0); rokko::localized_vector<double> eigval(dim); rokko::distributed_matrix<double, matrix_major> eigvec(dim, dim, g, solver); try { solver.diagonalize(mat, eigval, eigvec); } catch (const char *e) { if (myrank == 0) std::cout << "Exception : " << e << std::endl; MPI_Abort(MPI_COMM_WORLD, 22); } rokko::localized_matrix<double, matrix_major> eigvec_loc(dim, dim); rokko::gather(eigvec, eigvec_loc, 0); if (myrank == 0) { std::cout << "smallest eigenvalues:"; for (int i = 0; i < std::min(dim, 10); ++i) std::cout << ' ' << eigval(i); std::cout << std::endl; std::cout << "residual of the smallest eigenvalue/vector: |x A x - lambda| = " << std::abs(eigvec_loc.col(0).transpose() * mat_loc * eigvec_loc.col(0) - eigval(0)) << std::endl; } solver.finalize(); MPI_Finalize(); }
/** \brief Compute the eigenvalues of a real symmetric matrix A. \param a = pointer to array of symmetric n by n input matrix A. The computation alters these values. \param ev = pointer to array of the output eigenvalues \param n = dimension parameter (dim(a)= n*n, dim(ev)= n) */ void G_math_eigval(double **a,double *ev,int n) { eigval(a[0], ev, n); return; }
//------------------------------------------------------------------------------ void PD_LPS_porosity_adrmc::evaluateStatic(int id, int i) { if (m_data(i, m_indexUnbreakable) >= 1) return; #if CALCULATE_NUMMERICAL_PRINCIPAL_STRESS arma::vec eigval(m_dim); #endif vector<pair<int, vector<double>>> &PDconnections = m_particles.pdConnections(id); const double shearCrit = m_C0 - m_ks * m_T; // const double s_crit = 3.*m_T/40.e9; bool broken = false; if (m_dim == 2) { for (auto &con : PDconnections) { const int id_j = con.first; const int j = m_idToCol_v[id_j]; if (m_data(j, m_indexUnbreakable) >= 1) continue; if (con.second[m_indexConnected] <= 0.5) continue; // const double s = con.second[m_iStretch]; const double sx = 0.5 * (m_data(i, m_indexStress[0]) + m_data(j, m_indexStress[0])); const double sy = 0.5 * (m_data(i, m_indexStress[1]) + m_data(j, m_indexStress[1])); const double sxy = 0.5 * (m_data(i, m_indexStress[2]) + m_data(j, m_indexStress[2])); const double first = 0.5 * (sx + sy); const double second = sqrt(0.25 * (sx - sy) * (sx - sy) + sxy * sxy); const double p_1 = first + second; // max const double p_2 = first - second; // min #if USE_PRINCIPAL_STRESS const int criticalShear = p_2 <= m_C0 - m_ks * p_1; #else const double shear_max = 0.5 * (p_1 - p_2); const double shear = shear_max * m_cos_theta; const double normal = 0.5 * (p_1 + p_2) + shear_max * m_sin_theta; const double criticalShear = shear > m_S0 - m_d * normal; // const double criticalShear = shear + m_d*normal - m_S0; // const double criticalTensile = p_1 - m_T; #endif const int MC_valid = p_2 < shearCrit; const int criticalTensile = p_1 >= m_T; // const int criticalTensile = s >= s_crit; if (MC_valid) { if (criticalShear) { m_data(i, m_indexBrokenNow) = 1; con.second[m_indexConnected] = 0; m_continueState = true; broken = true; // cout << "Shear\t " << id << " - " << id_j << // "\tp1:" << p_1 << ", " << p_2 << endl; } } // } else { // } if (criticalTensile) { m_data(i, m_indexBrokenNow) = 1; con.second[m_indexConnected] = 0; m_continueState = true; broken = true; // cout << "Tensile\t " << id << " - " << id_j << // "\tp1:" << p_1 << ", " << p_2 << endl; } } } else if (m_dim == 3) { arma::mat S(m_dim, m_dim); for (auto &con : PDconnections) { const int id_j = con.first; const int j = m_idToCol_v[id_j]; if (m_data(j, m_indexUnbreakable) >= 1) continue; if (con.second[m_indexConnected] <= 0.5) continue; S(0, 0) = 0.5 * (m_data(i, m_indexStress[0]) + m_data(j, m_indexStress[0])); S(1, 1) = 0.5 * (m_data(i, m_indexStress[1]) + m_data(j, m_indexStress[1])); S(0, 1) = 0.5 * (m_data(i, m_indexStress[2]) + m_data(j, m_indexStress[2])); S(1, 0) = S(0, 1); S(2, 2) = 0.5 * (m_data(i, m_indexStress[3]) + m_data(j, m_indexStress[3])); S(0, 2) = 0.5 * (m_data(i, m_indexStress[4]) + m_data(j, m_indexStress[4])); S(2, 0) = S(0, 2); S(1, 2) = 0.5 * (m_data(i, m_indexStress[5]) + m_data(j, m_indexStress[5])); S(2, 1) = S(1, 2); #if CALCULATE_NUMMERICAL_PRINCIPAL_STRESS arma::eig_sym(eigval, S); const double p_1 = eigval(2); const double p_2 = eigval(0); #else const double I1 = S(0, 0) + S(1, 1) + S(2, 2); const double I2 = S(0, 0) * S(1, 1) + S(1, 1) * S(2, 2) + S(3, 3) * S(0, 0) - pow(S(0, 1), 2) - pow(S(1, 2), 2) - pow(S(0, 2), 2); const double I3 = S(0, 0) * S(1, 1) * S(2, 2) - S(0, 0) * pow(S(1, 2), 2) - S(1, 1) * pow(S(0, 2), 2) - S(2, 2) * pow(S(0, 1), 2) + 2 * S(0, 1) * S(1, 2) * S(0, 2); const double phi = 1. / 3. * acos(0.5 * (2 * pow(I1, 3) - 9 * I1 * I2 + 27 * I3) / pow(pow(I1, 2) - 3 * I2, 1.5)); const double core = 2. / 3. * (sqrt(I1 * I1 - 3 * I2)); const double s1 = I1 / 3. + core * cos(phi); const double s2 = I1 / 3. + core * cos(phi - 2. * M_PI / 3.); const double s3 = I1 / 3. + core * cos(phi - 4. * M_PI / 3.); double p_1 = s1; double p_2 = s2; if (s2 > p_1) { p_1 = s2; p_2 = s1; } if (s3 > p_1) { p_1 = s3; } if (p_2 < s3) { p_2 = s3; } #endif const int criticalShear = p_2 <= m_C0 - m_ks * p_1; const int MC_valid = p_2 < shearCrit; const int criticalTensile = p_1 >= m_T; if (MC_valid) { if (criticalShear) { m_data(i, m_indexBrokenNow) = 1; con.second[m_indexConnected] = 0; broken = true; } } else { if (criticalTensile) { m_data(i, m_indexBrokenNow) = 1; con.second[m_indexConnected] = 0; broken = true; } } } } if (broken) { updateWeightedVolume(id, i); computeK(id, i); m_data(i, m_indexBrokenNow) = 0; } }
void usp_eval_print(struct beads *b, struct usp *usp) { if (usp == NULL) return; int i, j, k; int idx = 0; double xrel[3]; const int dim[3] = {TANG1,TANG2,NORMAL}; for (j=0 ; j<2 ; j++) for (k=0 ; k<9 ; k++) usp->tt[j][k]=0.; //DETERMINE ORIENTATION for (i = 0; i < b->local_n; i++) { //FOR EACH ATOM CHECK IF THE BLOCK IS SUBJECT TO THE UMBRELLA POTENTIAL int thisblock = b->local_n_b[i]; int N = b->N[thisblock]; if (thisblock==usp->blocks[0] || thisblock==usp->blocks[1]) { int blck=1; //IDENTIFY BLOCK AS 2nd OR 1st OF THE SPECIFIED BLOCKS IN THE HEADER if (thisblock==usp->blocks[0]) blck=0; for (j = idx; j < idx + N; j++) { for (k=0 ; k<3 ; k++) { //dimension, 3d xrel[k] = b->x_intra[j][dim[k]] - usp->coms[3*blck+k]; // Transformation to relative coordinates //fprintf(stderr,"block:%d bead:%d xrel[%d]=%lg\n",blck,j,k,xrel[k]); } usp->tt[blck][0*3+0] += ((xrel[1]*xrel[1]) + (xrel[2]*xrel[2])); // Traegheitstensor usp->tt[blck][0*3+1] -= (xrel[0]*xrel[1]); usp->tt[blck][0*3+2] -= (xrel[0]*xrel[2]); usp->tt[blck][1*3+1] += ((xrel[0]*xrel[0]) + (xrel[2]*xrel[2])); usp->tt[blck][1*3+2] -= (xrel[1]*xrel[2]); usp->tt[blck][2*3+2] += ((xrel[0]*xrel[0]) + (xrel[1]*xrel[1])); } } idx += N; } if(ismaster) fprintf(usp->fh,"%lg",b->time); for (k=0 ; k<2 ; k++) { //blocks MPI_Allreduce(MPI_IN_PLACE, usp->tt[k], 9, MPI_DOUBLE, MPI_SUM, comm_grid); usp->tt[k][1*3+0] = usp->tt[k][0*3+1]; //symmetry usp->tt[k][2*3+0] = usp->tt[k][0*3+2]; usp->tt[k][2*3+1] = usp->tt[k][1*3+2]; //tt[k] is now complete! //for (i=0 ; i<3 ; i++) { // for (j=0 ; j<3 ; j++) { // fprintf(stderr,"block:%d tt[%d][%d]:%lg\n",k,i,j,usp->tt[k][3*i+j]); // } //} // Diagonalisieren des Tr??heitstensors durch L??ung einer kubischen Gleichung // kubische cardanische Gleichung: // x^3 + ra*x^2 + sa*x + ta = 0 /* double ra,sa,ta,p,q,rho,phi; ra = -(usp->tt[k][0*3+0] + usp->tt[k][1*3+1] + usp->tt[k][2*3+2]); sa = (usp->tt[k][0*3+0] * (usp->tt[k][1*3+1] + usp->tt[k][2*3+2]) - usp->tt[k][1*3+0]*usp->tt[k][0*3+1] - usp->tt[k][2*3+0]*usp->tt[k][0*3+2] + usp->tt[k][1*3+1]*usp->tt[k][2*3+2] - usp->tt[k][2*3+1]*usp->tt[k][1*3+2]); ta = -(usp->tt[k][1*3+0]*(usp->tt[k][2*3+1]*usp->tt[k][0*3+2] - usp->tt[k][0*3+1]*usp->tt[k][2*3+2]) + usp->tt[k][2*3+0]*(usp->tt[k][0*3+1]*usp->tt[k][1*3+2] - usp->tt[k][1*3+1]*usp->tt[k][0*3+2]) + usp->tt[k][0*3+0]*(usp->tt[k][1*3+1]*usp->tt[k][2*3+2] - usp->tt[k][2*3+1]*usp->tt[k][1*3+2]) ); // reduzierte Form der kubischen Gleichung y^3 + p*y + q = 0 // rho = sqrt(-p^3/27.) cos phi = -q/(2*rho) p = (3.*sa - ra*ra)/3.; q = ((2.*ra*ra*ra)/27.) - (ra*sa/3.) + ta; rho = sqrt(-(p*p*p)/27.); phi = acos(-q/(2.*rho)); //fprintf(stderr,"ra:%lg sa:%lg ta:%lg p:%lg q:%lg rho:%lg phi:%lg\n",ra,sa,ta,p,q,rho,phi); double y[3]; double lambda[3]; double maxlambda[3]; double evec[3]; y[0] = 2.*pow(rho,1./3.)*cos(phi/3.); y[1] = 2.*pow(rho,1./3.)*cos(phi/3. + 2.*M_PI/3.); y[2] = 2.*pow(rho,1./3.)*cos(phi/3. + 4.*M_PI/3.); */ double evec[3]; double lambda2[3]; double maxlambda[3]; eigval(usp->tt[k],lambda2); // get Eigenvalues maxlambda[0] = MAX(lambda2[0], MAX(lambda2[1],lambda2[2])); // groesstes Tragheitsmoment if (maxlambda[0] == lambda2[0]) { maxlambda[1] = MAX(lambda2[1],lambda2[2]); maxlambda[2] = MIN(lambda2[1],lambda2[2]); } else if (maxlambda[0] == lambda2[1]) { maxlambda[1] = MAX(lambda2[0],lambda2[2]); maxlambda[2] = MIN(lambda2[0],lambda2[2]); } else { maxlambda[1] = MAX(lambda2[0],lambda2[1]); maxlambda[2] = MIN(lambda2[0],lambda2[1]); } //fprintf(stderr,"block %d has eigenvalues in descending order %lg %lg %lg\n",k,maxlambda[0],maxlambda[1],maxlambda[2]); //for (i=0;i<3;i++) { // for (j=0;j<3;j++) { // fprintf(stderr,"%lg ",usp->tt[k][i*3+j]); // } // fprintf(stderr,"\n"); //} //fprintf(stderr,"y:%lg %lg %lg\n",y[0],y[1],y[2]); /* for(j=0; j<3; j++) lambda[j] = y[j] - ra/3.; // Eigenwerte (Haupttraegheitsmomente) //fprintf(stderr,"lambda:%lg %lg %lg\n",lambda[0],lambda[1],lambda[2]); maxlambda[0] = MAX(lambda[0], MAX(lambda[1],lambda[2])); // groesstes Tragheitsmoment if (maxlambda[0] == lambda[0]) { maxlambda[1] = MAX(lambda[1],lambda[2]); maxlambda[2] = MIN(lambda[1],lambda[2]); } else if (maxlambda[0] == lambda[1]) { maxlambda[1] = MAX(lambda[0],lambda[2]); maxlambda[2] = MIN(lambda[0],lambda[2]); } else { maxlambda[1] = MAX(lambda[0],lambda[1]); maxlambda[2] = MIN(lambda[0],lambda[1]); } */ //fprintf(stderr,"maxlambda:%lg %lg %lg\n",maxlambda[0],maxlambda[1],maxlambda[2]); // Bestimmung des Eigenvektors zum gr??ten Eigenwert, e.g. oblates Objekt //evec[2] = 1.; //evec[1] = ((usp->tt[k][0*3+0]-maxlambda[0])*usp->tt[k][1*3+2]*evec[2] - usp->tt[k][1*3+0]*usp->tt[k][0*3+2]*evec[2]); //evec[1] = evec[1] / (usp->tt[k][1*3+0]*usp->tt[k][0*3+1] + (maxlambda[0]-usp->tt[k][0*3+0])*(usp->tt[k][1*3+1]-maxlambda[0])); //evec[0] = (usp->tt[k][0*3+1]*evec[1] + usp->tt[k][0*3+2]*evec[2]) / (maxlambda[0]-usp->tt[k][0*3+0]); // Bestimmung des Eigenvektors zum kleinsten Eigenwert, e.g. prolates Objekt evec[2] = 1.; evec[1] = ((usp->tt[k][0*3+0]-maxlambda[2])*usp->tt[k][1*3+2]*evec[2] - usp->tt[k][1*3+0]*usp->tt[k][0*3+2]*evec[2]); evec[1] = evec[1] / (usp->tt[k][1*3+0]*usp->tt[k][0*3+1] + (maxlambda[2]-usp->tt[k][0*3+0])*(usp->tt[k][1*3+1]-maxlambda[2])); evec[0] = (usp->tt[k][0*3+1]*evec[1] + usp->tt[k][0*3+2]*evec[2]) / (maxlambda[2]-usp->tt[k][0*3+0]); double xlen = sqrt(evec[0]*evec[0]+evec[1]*evec[1]+evec[2]*evec[2]); for(j=0; j<3; j++) evec[j] /= xlen; // normierter Eigenvektor = Richtungsvektor der Haupttr??heitsachse //OUTPUT if(ismaster) fprintf(usp->fh," %lg %lg %lg %lg %lg %lg",usp->coms[3*k],usp->coms[3*k+1],usp->coms[3*k+2],evec[0],evec[1],evec[2]); } if(ismaster) fprintf(usp->fh,"\n"); }
//------------------------------------------------------------------------------ void ADRmohrCoulombFracture::evaluateStepTwo(const pair<int, int> &id_col) { // First calculating the total stress on an material point. The stress is averaged // all its bonds, and the stress state on a bond is the mean of the // stress at each material point. const int id_i = id_col.first; const int col_i = id_col.second; if((*m_data)(col_i, m_indexUnbreakable) >= 1) return; vector<pair<int, vector<double>>> & PDconnections = m_particles->pdConnections(id_i); /* if(m_dim == 2) { arma::mat S_i(2, 2); arma::mat S(2, 2); S_i(0, 0) = (*m_data)(col_i, m_indexStress[0]); S_i(1, 1) = (*m_data)(col_i, m_indexStress[1]); S_i(0, 1) = (*m_data)(col_i, m_indexStress[3]); S_i(1, 0) = S_i(0, 1); arma::vec eigval; for(auto &con:PDconnections) { const int id_j = con.first; const int j = (*m_pIds)[id_j]; if((*m_data)(j, m_indexUnbreakable) >= 1) continue; if(con.second[m_indexConnected] <= 0.5) continue; S(0, 0) = 0.5*(S_i(0, 0) + (*m_data)(j, m_indexStress[0])); S(1, 1) = 0.5*(S_i(1, 1) + (*m_data)(j, m_indexStress[1])); S(0, 1) = 0.5*(S_i(0, 1) + (*m_data)(j, m_indexStress[3])); // S(0, 0) = max(S_i(0, 0), (*m_data)(j, m_indexStress[0])); // S(1, 1) = max(S_i(1, 1), (*m_data)(j, m_indexStress[1])); // S(0, 1) = max(S_i(0, 1), (*m_data)(j, m_indexStress[3])); S(1, 0) = S(0, 1); const double first = 0.5*(S(0, 0) + S(1, 1)); const double second = sqrt(0.25*(S(0, 0) - S(1, 1))*(S(0, 0) - S(1, 1)) + S(0, 1)*S(0, 1)); const double s1 = first + second; const double s2 = first - second; const double p_1 = max(s1, s2); const double p_2 = min(s1, s2); // arma::eig_sym(eigval, S); // const double p_1 = eigval(1); // const double p_2 = eigval(0); // if(m_d*p_1 - p_2 - m_C > 0) // { // con.second[m_indexConnected] = 0; // m_maxPId = pair<int, pair<int, vector<double>> *>(id_i, &con); // } // else if(p_1 > m_T) if(p_1 > m_T) { // con.second[m_indexConnected] = 0; if(p_1 > m_maxStress) { m_maxPId = pair<int, pair<int, vector<double>> *>(id_i, &con); m_maxStress = p_1; } } } } */ arma::vec eigval(m_dim); arma::mat S_i(m_dim, m_dim); arma::mat S(m_dim, m_dim); if(m_dim == 2) { S_i(0, 0) = (*m_data)(col_i, m_indexStress[0]); S_i(1, 1) = (*m_data)(col_i, m_indexStress[1]); S_i(0, 1) = (*m_data)(col_i, m_indexStress[3]); S_i(1, 0) = S_i(0, 1); for(auto &con:PDconnections) { const int id_j = con.first; const int j = (*m_pIds)[id_j]; if((*m_data)(j, m_indexUnbreakable) >= 1) continue; if(con.second[m_indexConnected] <= 0.5) continue; S(0, 0) = 0.5*(S_i(0, 0) + (*m_data)(j, m_indexStress[0])); S(1, 1) = 0.5*(S_i(1, 1) + (*m_data)(j, m_indexStress[1])); S(0, 1) = 0.5*(S_i(0, 1) + (*m_data)(j, m_indexStress[3])); S(1, 0) = S(0, 1); #if 0 arma::eig_sym(eigval, S); const double p_1 = eigval(1); const double p_2 = eigval(0); #else const double first = 0.5*(S(0, 0) + S(1, 1)); const double second = sqrt(0.25*(S(0, 0) - S(1, 1))*(S(0, 0) - S(1, 1)) + S(0, 1)*S(0, 1)); const double s1 = first + second; const double s2 = first - second; const double p_1 = max(s1, s2); const double p_2 = min(s1, s2); #endif if(m_d*p_1 - p_2 - m_C > 0) { con.second[m_indexConnected] = 0; m_maxPId = pair<int, pair<int, vector<double>> *>(id_i, &con); } else if(p_1 > m_T) { con.second[m_indexConnected] = 0; m_maxPId = pair<int, pair<int, vector<double>> *>(id_i, &con); } } } else if(m_dim == 3) { S_i(0, 0) = (*m_data)(col_i, m_indexStress[0]); S_i(1, 1) = (*m_data)(col_i, m_indexStress[1]); S_i(2, 2) = (*m_data)(col_i, m_indexStress[2]); S_i(0, 1) = (*m_data)(col_i, m_indexStress[3]); S_i(1, 0) = S_i(0, 1); S_i(0, 2) = (*m_data)(col_i, m_indexStress[4]); S_i(2, 0) = S_i(0, 2); S_i(1, 2) = (*m_data)(col_i, m_indexStress[5]); S_i(2, 1) = S_i(1, 2); for(auto &con:PDconnections) { const int id_j = con.first; const int col_j = (*m_pIds)[id_j]; if((*m_data)(col_j, m_indexUnbreakable) >= 1) continue; if(con.second[m_indexConnected] <= 0.5) continue; S(0, 0) = 0.5*(S_i(0, 0) + (*m_data)(col_j, m_indexStress[0])); S(1, 1) = 0.5*(S_i(1, 1) + (*m_data)(col_j, m_indexStress[1])); S(2, 2) = 0.5*(S_i(2, 2) + (*m_data)(col_j, m_indexStress[2])); S(0, 1) = 0.5*(S_i(0, 1) + (*m_data)(col_j, m_indexStress[3])); S(1, 0) = S(0, 1); S(0, 2) = 0.5*(S_i(0, 2) + (*m_data)(col_j, m_indexStress[4])); S(2, 0) = S(0, 2); S(1, 2) = 0.5*(S_i(1, 2) + (*m_data)(col_j, m_indexStress[5])); S(2, 1) = S(1, 2); #if 0 arma::eig_sym(eigval, S); const double p_1 = eigval(2); const double p_2 = eigval(0); #else const double I1 = S(0, 0) + S(1, 1) + S(2, 2); const double I2 = S(0, 0)*S(1, 1) + S(1, 1)*S(2, 2) + S(3, 3)*S(0, 0) - pow(S(0, 1), 2) - pow(S(1, 2), 2) - pow(S(0, 2), 2); const double I3 = S(0, 0)*S(1, 1)*S(2, 2) - S(0, 0)*pow(S(1, 2), 2) - S(1, 1)*pow(S(0, 2), 2) - S(2, 2)*pow(S(0, 1), 2) + 2*S(0, 1)*S(1, 2)*S(0, 2); const double phi = 1./3.*acos(0.5*(2*pow(I1, 3) -9*I1*I2 + 27*I3)/pow(pow(I1, 2) - 3*I2, 1.5)); const double core = 2./3.*(sqrt(I1*I1 - 3*I2)); const double s1 = I1/3. + core*cos(phi); const double s2 = I1/3. + core*cos(phi + 2.*M_PI/3.); const double s3 = I1/3. + core*cos(phi + 4.*M_PI/3.); double p_1 = s1; double p_2 = s2; if(s2>p_1) { p_1 = s2; p_2 = s1; } if(s3>p_1) { p_1 = s3; } else if(p_2 < s3) { p_2 = s3; } #endif if(m_d*p_1 - p_2 - m_C > 0) { con.second[m_indexConnected] = 0; m_maxPId = pair<int, pair<int, vector<double>> *>(id_i, &con); } else if(p_1 > m_T) { con.second[m_indexConnected] = 0; m_maxPId = pair<int, pair<int, vector<double>> *>(id_i, &con); } } } //-------------------------------------------------------------------------- }
void perform_main_computation (const bool fast, const bool verbose, const arma::mat & coord, const arma::mat & param, const std::string & cfname, const std::string & qfname, pca::pcafitter & fitter) { // ordered arma::vec eigval; // by row or by column ? arma::mat eigvec; if (!fast) { std::cout << "Perform PCA " << std::endl; // projection arma::mat score; arma::princomp(eigvec, score, eigval, coord); std::cout << score.n_rows << " " << score.n_cols << std::endl; std::cout << "Writing Scoreplot" << std::endl; std::ofstream myfilesc("scoreplot.txt"); for (int i=0; i<(int)score.n_rows; ++i) { myfilesc << score(i,0) << " " << score(i,1) << " " << score(i,2) << std::endl; if (verbose) { double mainr = 0.0e0; for (int j=1; j<5; ++j) mainr += score(i,j) * score(i,j); double residue = 0.0; for (int j=5; j<fitter.get_coordim(); ++j) residue += score(i,j) * score(i,j); std::cout << "Track " << i+1 << " residue " << residue << " mainr " << mainr << std::endl; } } myfilesc.close(); } else { std::cout << "Compute correlation mtx" << std::endl; arma::mat coordm = arma::zeros<arma::mat>(fitter.get_coordim()); arma::mat hca = arma::zeros<arma::mat>(fitter.get_coordim(), fitter.get_coordim()); arma::vec eigvaltmp = arma::zeros<arma::vec>(fitter.get_coordim()); eigvec = arma::zeros<arma::mat>(fitter.get_coordim(), fitter.get_coordim()); eigval = arma::zeros<arma::vec>(fitter.get_coordim()); hca = arma::cov(coord); /* double check double sum = 1.0e0; for (int l=0; l<(int)coord.n_rows; ++l) { sum += 1.0e0; for (int i=0; i<fitter.get_coordim(); ++i) coordm(i) += (coord(l,i)-coordm(i))/sum; for (int i=0; i<fitter.get_coordim(); ++i) { for (int j=0; j<fitter.get_coordim(); ++j) { hca(i,j) += ((coord(l,i) - coordm(i))* (coord(l,j) - coordm(j))- (sum-1.0e0)*hca(i,j)/sum)/(sum-1.0e0); } } } */ std::cout << "Eigensystem" << std::endl; arma::eig_sym(eigvaltmp, eigvec, hca); for (int i=0; i<fitter.get_coordim(); ++i) eigval(i) = eigvaltmp(fitter.get_coordim()-i-1); } double totval = 0.0e0; for (int i=0; i<fitter.get_coordim(); ++i) totval += eigval(i); std::cout << "Eigenvalues: " << std::endl; double totvar = 0.0e0; for (int i=0; i<fitter.get_coordim(); ++i) { if (i < fitter.get_paramdim()) totvar += 100.0e0*(eigval(i)/totval); std::cout << i+1 << " ==> " << 100.0e0*(eigval(i)/totval) << "% value: " << eigval(i) << std::endl; } std::cout << "PARAMDIM eigenvalues: " << totvar << std::endl; std::cout << fitter.get_paramdim() << " X " << fitter.get_coordim() << std::endl; arma::mat cmtx = arma::zeros<arma::mat>(fitter.get_paramdim(), fitter.get_coordim()); arma::rowvec q = arma::zeros<arma::rowvec>(fitter.get_paramdim()); std::cout << "Compute PCA constants " << std::endl; fitter.compute_pca_constants (param, coord, cmtx, q); std::cout << "Write constant to file" << std::endl; pca::write_armmat(cfname.c_str(), cmtx); pca::write_armvct(qfname.c_str(), q); }
void ComputeSmearedCrackingStress::computeCrackStrainAndOrientation( RealVectorValue & strain_in_crack_dir) { // The rotation tensor is ordered such that directions for pre-existing cracks appear first // in the list of columns. For example, if there is one existing crack, its direction is in the // first column in the rotation tensor. const unsigned int num_known_dirs = getNumKnownCrackDirs(); if (num_known_dirs == 0) { std::vector<Real> eigval(3, 0.0); RankTwoTensor eigvec; _elastic_strain[_qp].symmetricEigenvaluesEigenvectors(eigval, eigvec); // If the elastic strain is beyond the cracking strain, save the eigen vectors as // the rotation tensor. Reverse their order so that the third principal strain // (most tensile) will correspond to the first crack. _crack_rotation[_qp].fillColumn(0, eigvec.column(2)); _crack_rotation[_qp].fillColumn(1, eigvec.column(1)); _crack_rotation[_qp].fillColumn(2, eigvec.column(0)); strain_in_crack_dir(0) = eigval[2]; strain_in_crack_dir(1) = eigval[1]; strain_in_crack_dir(2) = eigval[0]; } else if (num_known_dirs == 1) { // This is easily the most complicated case. // 1. Rotate the elastic strain to the orientation associated with the known // crack. // 2. Extract the lower 2x2 block into a separate tensor. // 3. Run the eigen solver on the result. // 4. Update the rotation tensor to reflect the effect of the 2 eigenvectors. // 1. const RankTwoTensor & R = _crack_rotation[_qp]; RankTwoTensor ePrime(_elastic_strain[_qp]); ePrime.rotate(R.transpose()); // elastic strain in crack coordinates // 2. ColumnMajorMatrix e2x2(2, 2); e2x2(0, 0) = ePrime(1, 1); e2x2(1, 0) = ePrime(2, 1); e2x2(0, 1) = ePrime(1, 2); e2x2(1, 1) = ePrime(2, 2); // 3. ColumnMajorMatrix e_val2x1(2, 1); ColumnMajorMatrix e_vec2x2(2, 2); e2x2.eigen(e_val2x1, e_vec2x2); // 4. RankTwoTensor eigvec( 1.0, 0.0, 0.0, 0.0, e_vec2x2(0, 1), e_vec2x2(1, 1), 0.0, e_vec2x2(0, 0), e_vec2x2(1, 0)); _crack_rotation[_qp] = _crack_rotation_old[_qp] * eigvec; // Roe implementation strain_in_crack_dir(0) = ePrime(0, 0); strain_in_crack_dir(1) = e_val2x1(1, 0); strain_in_crack_dir(2) = e_val2x1(0, 0); } else if (num_known_dirs == 2 || num_known_dirs == 3) { // Rotate to cracked orientation and pick off the strains in the rotated // coordinate directions. const RankTwoTensor & R = _crack_rotation[_qp]; RankTwoTensor ePrime(_elastic_strain[_qp]); ePrime.rotate(R.transpose()); // elastic strain in crack coordinates strain_in_crack_dir(0) = ePrime(0, 0); strain_in_crack_dir(1) = ePrime(1, 1); strain_in_crack_dir(2) = ePrime(2, 2); } else mooseError("Invalid number of known crack directions"); }
void ATO::ModalObjective<PHAL::AlbanyTraits::Residual, Traits>:: evaluateFields(typename Traits::EvalData workset) { Albany::MDArray F = (*workset.stateArrayPtr)[FName]; Albany::MDArray dEdp = (*workset.stateArrayPtr)[dFdpName]; Albany::MDArray topo = (*workset.stateArrayPtr)[topology->getName()]; std::vector<int> dims; gradX.dimensions(dims); int size = dims.size(); int numCells = dims[0]; int numQPs = dims[1]; int numDims = dims[2]; int numNodes = topo.dimension(1); if( size == 4 ){ for(int cell=0; cell<numCells; cell++){ double dE = 0.0; double dmass_term = 0.; double dstiffness_term = 0.; for(int qp=0; qp<numQPs; qp++){ double topoVal = 0.0; for(int node=0; node<numNodes; node++) topoVal += topo(cell,node)*BF(cell,node,qp); double P = topology->Penalize(functionIndex,topoVal); double dP = topology->dPenalize(functionIndex,topoVal); double dE = 0.0; double dmass_term = 0.; double dstiffness_term = 0.; for(int i=0; i<numDims; i++) { dmass_term += val_qp(cell,qp,i)*val_qp(cell,qp,i) * qp_weights(cell,qp); for(int j=0; j<numDims; j++) dstiffness_term += dP*gradX(cell,qp,i,j)*workConj(cell,qp,i,j)*qp_weights(cell,qp); } for(int node=0; node<numNodes; node++) dEdp(cell,node) = -(dstiffness_term - dmass_term*eigval(0))*BF(cell,node,qp); } //tevhack std::cout << "dEdp(" << cell << ") = " << dEdp(cell) << std::endl; } } else { TEUCHOS_TEST_FOR_EXCEPTION(true, Teuchos::Exceptions::InvalidParameter, "Unexpected array dimensions in StiffnessObjective:" << size << std::endl); } /* if( size == 3 ){ for(int cell=0; cell<numCells; cell++){ double dE = 0.0; double P = topology->Penalize(topo(cell)); for(int qp=0; qp<numQPs; qp++) { for(int i=0; i<numDims; i++) { dE += val_qp(cell,qp,i) * val_qp(cell,qp,i); } for(int node=0; node<numNodes; node++) dEdp(cell,node) = dE/P*BF(cell,node,qp); } std::cout << "dEdp(" << cell << ") = " << dEdp(cell) << std::endl; } } else { TEUCHOS_TEST_FOR_EXCEPTION( true, Teuchos::Exceptions::InvalidParameter, "Unexpected array dimensions in ModalObjective:" << size << std::endl ); } */ F(0) = -eigval(0); }