//------------------------------------------------------------------------------ double PD_OSP::calculateDilationTerm(const std::pair<int, int> &idCol) { const int pId = idCol.first; const int col_i = idCol.second; const double d_i = m_data(col_i, m_indexD); vector<pair<int, vector<double>>> & PDconnections = m_particles.pdConnections(pId); double r_i[3]; double r0_i[3]; for(int d=0; d<m_dim; d++) { r_i[d] = m_r(d, col_i); r0_i[d] = m_r0(d, col_i); } const int nConnections = PDconnections.size(); double dr_ij[3]; double theta_i = 0; for(int l_j=0; l_j<nConnections; l_j++) { auto &con = PDconnections[l_j]; if(con.second[m_indexConnected] <= 0.5) continue; const int id_j = con.first; const int j = m_pIds[id_j]; const double d_j = m_data(j, m_indexD); const double vol_j = m_data(j, m_indexVolume); const double dr0 = con.second[m_indexDr0]; const double volumeScaling = con.second[m_indexVolumeScaling]; const double d_ij = 0.5*(d_i + d_j); double dr2 = 0; double A_ij = 0; // The lambda-factor for(int d=0; d<m_dim; d++) { dr_ij[d] = m_r(d, j) - r_i[d]; dr2 += dr_ij[d]*dr_ij[d]; A_ij += dr_ij[d]*(m_r0(d, j) - r0_i[d]); } const double dr = sqrt(dr2); A_ij /= (dr0*dr); double ds = dr - dr0; // To avoid roundoff errors if (fabs(ds) < THRESHOLD) ds = 0.0; const double s = ds/dr0; theta_i += d_ij*s*A_ij*vol_j*volumeScaling; } return m_delta*theta_i; }
//------------------------------------------------------------------------------ double PD_LPS::calculatePotentialEnergyDensity(const std::pair<int, int> &idCol) { const int pId = idCol.first; const int i = idCol.second; const double m_i = m_data(i, m_iMass); vector<pair<int, vector<double>>> & PDconnections = m_particles.pdConnections(pId); double r_i[m_dim]; double r0_i[m_dim]; for(int d=0; d<m_dim; d++) { r_i[d] = m_r(d, i); r0_i[d] = m_r0(d, i); } const int nConnections = PDconnections.size(); double dr_ij[m_dim]; double alpha = 0; if(m_dim == 3) alpha = 15*m_mu/m_i; else alpha = 8*m_mu/m_i; double theta_i = this->computeDilation(idCol); double W_i = 0; for(int l_j=0; l_j<nConnections; l_j++) { auto &con = PDconnections[l_j]; if(con.second[m_iConnected] <= 0.5) continue; const int id_j = con.first; const int j = m_pIds[id_j]; const double vol_j = m_data(j, m_iVolume); const double dr0 = con.second[m_iDr0]; const double volumeScaling = con.second[m_iVolumeScaling]; double dr2 = 0; for(int d=0; d<m_dim; d++) { dr_ij[d] = m_r(d, j) - r_i[d]; dr2 += dr_ij[d]*dr_ij[d]; } const double dr = sqrt(dr2); double ds = dr - dr0; const double extension_term = alpha*(pow(ds - theta_i*dr0/m_dim, 2)); W_i += (extension_term)*vol_j*volumeScaling; } W_i += m_k*(pow(theta_i, 2)); return 0.5* W_i; }
//------------------------------------------------------------------------------ void PD_OSP::calculateForces(const std::pair<int, int> &idCol) { const int pId = idCol.first; const int col_i = idCol.second; const double a_i = m_data(col_i, m_indexA); const double b_i = m_data(col_i, m_indexB); const double d_i = m_data(col_i, m_indexD); const double theta_i = m_data(col_i, m_indexTheta); vector<pair<int, vector<double>>> & PDconnections = m_particles.pdConnections(pId); double r_i[3]; double r0_i[3]; double f_i[3]; for(int d=0; d<m_dim; d++) { f_i[d] = 0; r_i[d] = m_r(d, col_i); r0_i[d] = m_r0(d, col_i); } const int nConnections = PDconnections.size(); double dr_ij[3]; double thetaNew = 0; for(int l_j=0; l_j<nConnections; l_j++) { auto &con = PDconnections[l_j]; if(con.second[m_indexConnected] <= 0.5) continue; const int id_j = con.first; const int j = m_pIds[id_j]; const double a_j = m_data(j, m_indexA); const double b_j = m_data(j, m_indexB); const double d_j = m_data(j, m_indexD); const double theta_j = m_data(j, m_indexTheta); const double vol_j = m_data(j, m_indexVolume); const double dr0 = con.second[m_indexDr0]; const double volumeScaling = con.second[m_indexVolumeScaling]; const double a_ij = 0.5*(a_i + a_j); const double b_ij = 0.5*(b_i + b_j); const double d_ij = 0.5*(d_i + d_j); const double Gd_ij = con.second[m_indexForceScalingDilation]; const double Gb_ij = con.second[m_indexForceScalingBond]; double dr2 = 0; double A_ij = 0; // The lambda-factor for(int d=0; d<m_dim; d++) { dr_ij[d] = m_r(d, j) - r_i[d]; dr2 += dr_ij[d]*dr_ij[d]; A_ij += dr_ij[d]*(m_r0(d, j) - r0_i[d]); } const double dr = sqrt(dr2); A_ij /= (dr0*dr); double ds = dr - dr0; // To avoid roundoff errors if (fabs(ds) < THRESHOLD) ds = 0.0; const double s = ds/dr0; const double fbond = (a_ij*d_ij*Gd_ij*A_ij/dr0*(theta_i + theta_j) + b_ij*Gb_ij*s) *vol_j*volumeScaling/dr; for(int d=0; d<m_dim; d++) { f_i[d] += dr_ij[d]*fbond; } thetaNew += d_ij*s*A_ij*vol_j*volumeScaling; con.second[m_indexStretch] = s; } for(int d=0; d<m_dim; d++) { m_F(d, col_i) += m_delta*f_i[d]; } m_data(col_i, m_indexThetaNew) = m_delta*thetaNew; }
//------------------------------------------------------------------------------ void PD_LPS_porosity_adrmc::calculateForces(const int id, const int i) { const double theta_i = m_data(i, m_iTheta); const double m_i = m_data(i, m_iMass); const double a_i = m_data(i, m_iA); const double b_i = m_data(i, m_iA); vector<pair<int, vector<double>>> &PDconnections = m_particles.pdConnections(id); const int nConnections = PDconnections.size(); double dr0_ij[m_dim]; double dr_ij[m_dim]; _F.zeros(); double thetaNew = 0; int nConnected = 0; //---------------------------------- // TMP - standard stress calc from // m_data(i, m_indexStress[0]) = 0; // m_data(i, m_indexStress[1]) = 0; // m_data(i, m_indexStress[2]) = 0; //---------------------------------- for (int l_j = 0; l_j < nConnections; l_j++) { auto &con = PDconnections[l_j]; if (con.second[m_iConnected] <= 0.5) continue; const int id_j = con.first; const int j = m_idToCol_v[id_j]; const double m_j = m_data(j, m_iMass); const double theta_j = m_data(j, m_iTheta); const double vol_j = m_data(j, m_iVolume); const double dr0 = con.second[m_iDr0]; const double volumeScaling = con.second[m_iVolumeScaling]; const double vol = vol_j * volumeScaling; const double w = weightFunction(dr0); const double a_j = m_data(j, m_iA); const double b_j = m_data(j, m_iB); double dr2 = 0; for (int d = 0; d < m_dim; d++) { dr0_ij[d] = m_r0(j, d) - m_r0(i, d); dr_ij[d] = m_r(j, d) - m_r(i, d); dr2 += dr_ij[d] * dr_ij[d]; } const double dr = sqrt(dr2); const double ds = dr - dr0; double bond = (b_i * theta_i / m_i + b_j * theta_j / m_j) * dr0; bond += (a_i / m_i + a_j / m_j) * ds; bond *= w * vol / dr; thetaNew += w * dr0 * ds * vol; for (int d = 0; d < m_dim; d++) { m_F(i, d) += dr_ij[d] * bond; for (int d2 = 0; d2 < m_dim; d2++) { _F(d, d2) += w * dr_ij[d] * dr0_ij[d2] * vol; } } con.second[m_iStretch] = ds / dr0; //---------------------------------- // TMP - standard stres calc from // m_data(i, m_indexStress[0]) += 0.5*dr_ij[0]*dr_ij[0]*bond; // m_data(i, m_indexStress[1]) += 0.5*dr_ij[1]*dr_ij[1]*bond; // m_data(i, m_indexStress[2]) += 0.5*dr_ij[0]*dr_ij[1]*bond; //---------------------------------- nConnected++; } if (nConnections <= 3) { m_data(i, m_iThetaNew) = 0; } else { m_data(i, m_iThetaNew) = m_dim / m_i * thetaNew; } //---------------------------------- // TMP - standard stres calc from //---------------------------------- // if(nConnected > 5) { // computeStress(id, i, nConnected); // } computeStress(id, i, nConnected); //-------------------- m_continueState = false; }
//------------------------------------------------------------------------------ void PD_LPS::applySurfaceCorrection(double strain) { arma::vec3 strainFactor; arma::mat gd = arma::zeros(m_particles.nParticles(), m_dim); // Dilation correction arma::mat gb = arma::zeros(m_particles.nParticles(), m_dim); // Bond correction //-------------------------------------------------------------------------- // Apllying correction to the dilation term //-------------------------------------------------------------------------- // Stretching all particle in the x, y and z-direction strainFactor(0) = strain; strainFactor(1) = 0; strainFactor(2) = 0; for(int a=0; a<m_dim; a++) { if(a == 1) strainFactor.swap_rows(0,1); else if(a == 2) strainFactor.swap_rows(1,2); #ifdef USE_OPENMP # pragma omp parallel for #endif // Applying uniaxial stretch for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); const int col_i = idCol.second; for(int d=0; d<m_dim; d++) { m_r(d, col_i) = (1 + strainFactor(d))*m_r(d, col_i); } } double W_d = strain; #ifdef USE_OPENMP # pragma omp parallel for #endif // Calculating the elastic energy density for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); const int col_i = idCol.second; const double theta_i = computeDilation(idCol); const double factor = W_d/theta_i; gd(col_i, a) = factor; } #ifdef USE_OPENMP # pragma omp parallel for #endif // Resetting the positions for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); int col_i = idCol.second; for(int d=0; d<m_dim; d++) { // m_r(d, col_i) = m_r(d, col_i)/(1 + strainFactor(d)); m_r(d, col_i) = m_r0(d, col_i); } } } //-------------------------------------------------------------------------- // Applying correction to the bond term //-------------------------------------------------------------------------- // Performing a simple shear of all particle in the x, y and z-direction arma::ivec3 axis; strainFactor(0) = strain; strainFactor(1) = 0.*strain; strainFactor(2) = 0; axis(0) = 1; axis(1) = 0; axis(2) = 0; for(int a=0; a<m_dim; a++) { if(a == 1) { strainFactor.swap_rows(1,2); strainFactor.swap_rows(0,1); axis(0) = 2; axis(1) = 0; axis(2) = 1; } else if(a == 2) { strainFactor.swap_rows(2,0); strainFactor.swap_rows(1,2); axis(0) = 2; axis(1) = 0; axis(2) = 0; } //#ifdef USE_OPENMP //# pragma omp parallel for //#endif // Applying uniaxial stretch for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); int col_i = idCol.second; for(int d=0; d<m_dim; d++) { double shear = strainFactor(d)*m_r(axis(d), col_i); m_r(d, col_i) = m_r(d, col_i) + shear; } } double W_s = 0.5*m_mu*strain*strain; //#ifdef USE_OPENMP //# pragma omp parallel for //#endif // Calculating the elastic energy density for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); const int col_i = idCol.second; const double bond_i = calculatePotentialEnergyDensity(idCol); const double factor = W_s/bond_i; gb(col_i, a) = factor; } //#ifdef USE_OPENMP //# pragma omp parallel for //#endif // Resetting the positions for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); int col_i = idCol.second; for(int d=0; d<m_dim; d++) { // m_r(d, col_i) = m_r(d, col_i) - strainFactor(d)*m_r(axis(d), col_i); m_r(d, col_i) = m_r0(d, col_i); } } } //-------------------------------------------------------------------------- // Calculating the scaling //-------------------------------------------------------------------------- //#ifdef USE_OPENMP //# pragma omp parallel for //#endif for(int i=0; i<m_particles.nParticles(); i++) { pair<int, int> idCol(i, i); int pId = idCol.first; int col_i = idCol.second; vector<pair<int, vector<double>>> & PDconnections = m_particles.pdConnections(pId); for(auto &con:PDconnections) { int id_j = con.first; int col_j = m_pIds[id_j]; double dr0Len = con.second[m_iDr0]; arma::vec3 n = (m_r.col(col_i) - m_r.col(col_j))/dr0Len; arma::vec3 gd_mean; arma::vec3 gb_mean; double Gd = 0; double Gb = 0; for(int d=0; d<m_dim; d++) { const double gd_i = gd(col_i, d); const double gd_j = gd(col_j, d); const double gb_i = gb(col_i, d); const double gb_j = gb(col_j, d); gd_mean(d) = 0.5*(gd_i + gd_j); gb_mean(d) = 0.5*(gb_i + gb_j); Gb += pow(n(d)/gb_mean(d), 2); Gd += pow(n(d)/gd_mean(d), 2); } Gd = pow(Gd, -0.5); Gb = pow(Gb, -0.5); con.second[m_iForceScalingDilation] *= Gd; con.second[m_iForceScalingBond] *= Gb; } } }
//------------------------------------------------------------------------------ void PD_LPS::calculateForces(const std::pair<int, int> &idCol) { const int pId = idCol.first; const int i = idCol.second; const double theta_i = m_data(i, m_iTheta); const double m_i = m_data(i, m_iMass); double alpha; if(m_dim == 3) alpha = 15*m_mu; else alpha = 8*m_mu; const double c = (3*m_k - 5*m_mu); vector<pair<int, vector<double>>> & PDconnections = m_particles.pdConnections(pId); double r_i[m_dim]; double r0_i[m_dim]; double f_i[m_dim]; for(int d=0; d<m_dim; d++) { f_i[d] = 0; r_i[d] = m_r(d, i); r0_i[d] = m_r0(d, i); } const int nConnections = PDconnections.size(); double dr_ij[m_dim]; double thetaNew = 0; for(int l_j=0; l_j<nConnections; l_j++) { auto &con = PDconnections[l_j]; if(con.second[m_iConnected] <= 0.5) continue; const int id_j = con.first; const int j = m_pIds[id_j]; const double m_j = m_data(j, m_iMass); const double theta_j = m_data(j, m_iTheta); const double vol_j = m_data(j, m_iVolume); const double dr0 = con.second[m_iDr0]; const double volumeScaling = con.second[m_iVolumeScaling]; const double gb_ij = con.second[m_iForceScalingBond]; const double gd_ij = con.second[m_iForceScalingDilation]; double dr2 = 0; for(int d=0; d<m_dim; d++) { dr_ij[d] = m_r(d, j) - r_i[d]; dr2 += dr_ij[d]*dr_ij[d]; } const double dr = sqrt(dr2); const double ds = dr - dr0; double bond = gd_ij*c*(theta_i/m_i + theta_j/m_j)*dr0; bond += gb_ij*alpha*(1./m_i + 1./m_j)*ds; bond *= vol_j*volumeScaling/dr; thetaNew += dr0*ds*vol_j*volumeScaling; for(int d=0; d<m_dim; d++) { m_F(d, i) += dr_ij[d]*bond; } con.second[m_iStretch] = ds/dr0; } m_data(i, m_iThetaNew) = m_dim/m_i*thetaNew; }
//------------------------------------------------------------------------------ void PD_LPS::calculateStress(const std::pair<int, int> &idCol, const int (&indexStress)[6]) { const int pId = idCol.first; const int i = idCol.second; const double theta_i = m_data(i, m_iTheta); const double m_i = m_data(i, m_iMass); double beta = 0; if(m_dim == 3) beta = 15*m_mu; else beta = 8*m_mu; const double alpha_i = beta/m_i; vector<pair<int, vector<double>>> & PDconnections = m_particles.pdConnections(pId); double r_i[3]; double r0_i[3]; for(int d=0; d<m_dim; d++) { r_i[d] = m_r(d, i); r0_i[d] = m_r0(d, i); } const int nConnections = PDconnections.size(); double dr_ij[m_dim]; for(int l_j=0; l_j<nConnections; l_j++) { auto &con = PDconnections[l_j]; if(con.second[m_iConnected] <= 0.5) continue; const int id_j = con.first; const int j = m_pIds[id_j]; const double m_j = m_data(j, m_iMass); const double theta_j = m_data(j, m_iTheta); const double vol_j = m_data(j, m_iVolume); const double dr0 = con.second[m_iDr0]; const double volumeScaling = con.second[m_iVolumeScaling]; const double alpha_j = beta/m_j; const double gb_ij = con.second[m_iForceScalingBond]; const double gd_ij = con.second[m_iForceScalingDilation]; double dr2 = 0; for(int d=0; d<m_dim; d++) { dr_ij[d] = m_r(d, j) - r_i[d]; dr2 += dr_ij[d]*dr_ij[d]; } const double dr = sqrt(dr2); const double ds = dr - dr0; double bond_ij = gd_ij*(3*m_k - 5*m_mu)*(theta_i/m_i + theta_j/m_j)*dr0; bond_ij += gb_ij*(alpha_i + alpha_j)*ds; bond_ij *= vol_j*volumeScaling/dr; m_data(i, indexStress[0]) += 0.5*bond_ij*dr_ij[X]*dr_ij[X]; m_data(i, indexStress[1]) += 0.5*bond_ij*dr_ij[Y]*dr_ij[Y]; m_data(i, indexStress[3]) += 0.5*bond_ij*dr_ij[X]*dr_ij[Y]; if(m_dim == 3) { m_data(i, indexStress[2]) += 0.5*bond_ij*dr_ij[Z]*dr_ij[Z]; m_data(i, indexStress[4]) += 0.5*bond_ij*dr_ij[X]*dr_ij[Z]; m_data(i, indexStress[5]) += 0.5*bond_ij*dr_ij[Y]*dr_ij[Z]; } } }