void compute() { const int M = 256; const int N = 256; cmatrix h_naught(M, N, true, complex(0.0f, 0.0f)); for (int row = 0; row < M; row++) { for (int col = 0; col < N; col++) { int n = col; int m = row; matrix3x1 K = Pi_2 * matrix3x1((float)n / N, 0, (float)m / M); complex h_0 = height_naught(K); h_naught.set(row, col, h_0); } } cmatrix h_tilde(M, N, true, complex(0, 0)); cmatrix c_heights(M, N, true, complex(0, 0)); fftwf_plan plan = fftwf_plan_dft_2d(M, N, (fftwf_complex *)h_tilde.getData(), (fftwf_complex *)c_heights.getData(), FFTW_BACKWARD, FFTW_ESTIMATE); matrix heights(M, N, true, 0.0f); const int Frames = 1; for (int p = 0; p < Frames; p++) { float t = (float)p / Frames; for (int row = 0; row < M; row++) { for (int col = 0; col < N; col++) { h_tilde.set(row, col, Htilde(h_naught, row, col, t)); } } // complex2complex FFT2D fftwf_execute(plan); // extract the real component for (int row = 0; row < M; row++) { for (int col = 0; col < N; col++) { heights.set(row, col, c_heights.get(row, col).r / 20.0f); } } // save the results { std::stringstream ss; ss << "ocean_" << std::setw(2) << std::setfill('0') << p << ".mat"; std::ofstream file(ss.str().c_str()); file << std::setprecision(10); math::matrix_writeAsText(file, heights); } } fftwf_destroy_plan(plan); }
void FBMReference::diagonalizeBlock( const unsigned int block, const TNT::Array2D<double> &hessian, const std::vector<Vec3> &positions, TNT::Array1D<double> &eval, TNT::Array2D<double> &evec ) { const unsigned int ConservedDegreesOfFreedom = 6; printf( "Diagonalizing Block: %d\n", block ); // 1. Determine the starting and ending index for the block // This means that the upper left corner of the block will be at (startatom, startatom) // And the lower right corner will be at (endatom, endatom) const int startatom = 3 * blockSizes[block]; int endatom = 3 * particleCount - 1 ; if( block != ( blockSizes.size() - 1 ) ) { endatom = 3 * blockSizes[block + 1] - 1; } const int size = endatom - startatom + 1; // 2. Get the block Hessian Hii // Right now I'm just doing a copy from the big Hessian // There's probably a more efficient way but for now I just want things to work.. TNT::Array2D<double> h_tilde( size, size, 0.0 ); for( int j = startatom; j <= endatom; j++ ) { for( int k = startatom; k <= endatom; k++ ) { h_tilde[k - startatom][j - startatom] = hessian[k][j]; } } // 3. Diagonalize the block Hessian only, and get eigenvectors TNT::Array1D<double> di( size, 0.0 ); TNT::Array2D<double> Qi( size, size, 0.0 ); diagonalizeSymmetricMatrix( h_tilde, di, Qi ); // sort eigenvalues by absolute magnitude std::vector<EigenvalueColumn> sortedPairs = sortEigenvalues( di ); // find geometric dof TNT::Array2D<double> Qi_gdof( size, size, 0.0 ); Vec3 pos_center( 0.0, 0.0, 0.0 ); double totalmass = 0.0; for( int j = startatom; j <= endatom; j += 3 ) { double mass = mParticleMass[ j / 3 ]; pos_center += positions[j / 3] * mass; totalmass += mass; } double norm = sqrt( totalmass ); // actual center pos_center *= 1.0 / totalmass; // create geometric dof vectors // iterating over rows and filling in values for 6 vectors as we go for( int j = 0; j < size; j += 3 ) { double atom_index = ( startatom + j ) / 3; double mass = mParticleMass[atom_index]; double factor = sqrt( mass ) / norm; // translational Qi_gdof[j][0] = factor; Qi_gdof[j + 1][1] = factor; Qi_gdof[j + 2][2] = factor; // rotational // cross product of rotation axis and vector to center of molecule // x-axis (b1=1) ja3-ka2 // y-axis (b2=1) ka1-ia3 // z-axis (b3=1) ia2-ja1 Vec3 diff = positions[atom_index] - pos_center; // x Qi_gdof[j + 1][3] = diff[2] * factor; Qi_gdof[j + 2][3] = -diff[1] * factor; // y Qi_gdof[j][4] = -diff[2] * factor; Qi_gdof[j + 2][4] = diff[0] * factor; // z Qi_gdof[j][5] = diff[1] * factor; Qi_gdof[j + 1][5] = -diff[0] * factor; } // normalize first rotational vector double rotnorm = 0.0; for( int j = 0; j < size; j++ ) { rotnorm += Qi_gdof[j][3] * Qi_gdof[j][3]; } rotnorm = 1.0 / sqrt( rotnorm ); for( int j = 0; j < size; j++ ) { Qi_gdof[j][3] = Qi_gdof[j][3] * rotnorm; } // orthogonalize rotational vectors 2 and 3 for( int j = 4; j < ConservedDegreesOfFreedom; j++ ) { // <-- vector we're orthogonalizing for( int k = 3; k < j; k++ ) { // <-- vectors we're orthognalizing against double dot_prod = 0.0; for( int l = 0; l < size; l++ ) { dot_prod += Qi_gdof[l][k] * Qi_gdof[l][j]; } for( int l = 0; l < size; l++ ) { Qi_gdof[l][j] = Qi_gdof[l][j] - Qi_gdof[l][k] * dot_prod; } } // normalize residual vector double rotnorm = 0.0; for( int l = 0; l < size; l++ ) { rotnorm += Qi_gdof[l][j] * Qi_gdof[l][j]; } rotnorm = 1.0 / sqrt( rotnorm ); for( int l = 0; l < size; l++ ) { Qi_gdof[l][j] = Qi_gdof[l][j] * rotnorm; } } // orthogonalize original eigenvectors against gdof // number of evec that survive orthogonalization int curr_evec = ConservedDegreesOfFreedom; for( int j = 0; j < size; j++ ) { // <-- vector we're orthogonalizing // to match ProtoMol we only include size instead of size + cdof vectors // Note: for every vector that is skipped due to a low norm, // we add an additional vector to replace it, so we could actually // use all size original eigenvectors if( curr_evec == size ) { break; } // orthogonalize original eigenvectors in order from smallest magnitude // eigenvalue to biggest int col = sortedPairs.at( j ).second; // copy original vector to Qi_gdof -- updated in place for( int l = 0; l < size; l++ ) { Qi_gdof[l][curr_evec] = Qi[l][col]; } // get dot products with previous vectors for( int k = 0; k < curr_evec; k++ ) { // <-- vector orthog against // dot product between original vector and previously // orthogonalized vectors double dot_prod = 0.0; for( int l = 0; l < size; l++ ) { dot_prod += Qi_gdof[l][k] * Qi[l][col]; } // subtract from current vector -- update in place for( int l = 0; l < size; l++ ) { Qi_gdof[l][curr_evec] = Qi_gdof[l][curr_evec] - Qi_gdof[l][k] * dot_prod; } } //normalize residual vector double norm = 0.0; for( int l = 0; l < size; l++ ) { norm += Qi_gdof[l][curr_evec] * Qi_gdof[l][curr_evec]; } // if norm less than 1/20th of original // continue on to next vector // we don't update curr_evec so this vector // will be overwritten if( norm < 0.05 ) { continue; } // scale vector norm = sqrt( norm ); for( int l = 0; l < size; l++ ) { Qi_gdof[l][curr_evec] = Qi_gdof[l][curr_evec] / norm; } curr_evec++; } // 4. Copy eigenpairs to big array // This is necessary because we have to sort them, and determine // the cutoff eigenvalue for everybody. // we assume curr_evec <= size for( int j = 0; j < curr_evec; j++ ) { int col = sortedPairs.at( j ).second; eval[startatom + j] = di[col]; // orthogonalized eigenvectors already sorted by eigenvalue for( int k = 0; k < size; k++ ) { evec[startatom + k][startatom + j] = Qi_gdof[k][j]; } } }