Page MenuHomec4science

bem_polonski.cpp
No OneTemporary

File Metadata

Created
Tue, Nov 19, 14:54

bem_polonski.cpp

/**
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @section LICENSE
*
* Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de
* Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des
* Solides)
*
* Tamaas is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* Tamaas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Tamaas. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#include "bem_polonski.hh"
#include "fft_plan_manager.hh"
#include "fftransform.hh"
#include "surface.hh"
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
/* -------------------------------------------------------------------------- */
__BEGIN_TAMAAS__
/* -------------------------------------------------------------------------- */
BemPolonski::BemPolonski(Surface<Real>& p)
: BemFFTBase(p), surface_t(p.size(), p.getL()),
surface_r(p.size(), p.getL()), pold(p.size(), p.getL()), p_sat(-1.) {
e_star = 1.;
max_iterations = 2000;
surface_rms_heights = SurfaceStatistics::computeStdev(this->surface);
}
/* -------------------------------------------------------------------------- */
BemPolonski::~BemPolonski() {}
/* -------------------------------------------------------------------------- */
Real BemPolonski::computeEquilibrium(Real epsilon, Real pressure) {
this->computeSpectralInfluenceOverDisplacement();
this->surface_t = 0.;
this->surface_r = 0.;
this->pold = 0.;
this->surface_displacements = 0.;
Real delta = 0.;
Real Gold = 1.;
Real f = 1e300;
Real fPrevious = 1e300;
Real current_pressure = SurfaceStatistics::computeAverage(surface_tractions);
std::cout << "current pressure " << current_pressure << std::endl;
if (current_pressure <= 0.)
surface_tractions = pressure;
this->enforcePressureBalance(pressure);
convergence_iterations.clear();
nb_iterations = 0;
while (f > epsilon && nb_iterations < max_iterations) {
fPrevious = f;
this->computeDisplacementsFromTractions();
this->computeGaps();
Real gbar = this->computeMeanGapsInContact();
this->gap -= gbar;
Real G = this->computeG();
this->updateT(G, Gold, delta);
Real tau = this->computeTau();
pold = this->surface_tractions;
Gold = G;
delta = this->updateTractions(tau);
// Projection on admissible space
this->enforcePressureBalance(pressure);
// std::cout << std::scientific << std::setprecision(10)
// << SurfaceStatistics::computeAverage(surface_tractions) <<
// std::fixed << std::endl;
//
f = this->computeF();
if (nb_iterations % dump_freq == 0) {
Real A = SurfaceStatistics::computeContactAreaRatio(surface_tractions);
std::cout << std::scientific << std::setprecision(10) << nb_iterations
<< " " << f << " " << f - fPrevious << " " << A << std::fixed
<< std::endl;
}
convergence_iterations.push_back(f);
++nb_iterations;
}
this->computeTrueDisplacements();
return f;
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::computeEquilibriuminit(Real epsilon, Real pressure,
Surface<Real>& init) {
this->computeSpectralInfluenceOverDisplacement();
this->surface_t = 0.;
this->surface_r = 0.;
this->pold = 0.;
this->surface_displacements = 0.;
Real delta = 0.;
Real Gold = 1.;
Real f = 1e300;
Real fPrevious = 1e300;
this->surface_tractions = init;
Real current_pressure = SurfaceStatistics::computeAverage(surface_tractions);
if (current_pressure <= 0.)
surface_tractions = pressure;
this->enforcePressureBalance(pressure);
convergence_iterations.clear();
nb_iterations = 0;
this->computeDisplacementsFromTractions();
f = this->computeF();
std::cout << std::scientific << std::setprecision(10) << " " << f
<< std::endl;
while (f > epsilon && nb_iterations < max_iterations) {
fPrevious = f;
this->computeDisplacementsFromTractions();
this->computeGaps();
Real gbar = this->computeMeanGapsInContact();
this->gap -= gbar;
Real G = this->computeG();
this->updateT(G, Gold, delta);
Real tau = this->computeTau();
pold = this->surface_tractions;
Gold = G;
delta = this->updateTractions(tau);
// Projection on admissible space
this->enforcePressureBalance(pressure);
// std::cout << std::scientific << std::setprecision(10)
// << SurfaceStatistics::computeAverage(surface_tractions) <<
// std::fixed << std::endl;
//
f = this->computeF();
if (nb_iterations % dump_freq == 0) {
Real A = SurfaceStatistics::computeContactAreaRatio(surface_tractions);
std::cout << std::scientific << std::setprecision(10) << nb_iterations
<< " " << f << " " << f - fPrevious << " " << A << std::fixed
<< std::endl;
}
convergence_iterations.push_back(f);
++nb_iterations;
}
this->computeTrueDisplacements();
return f;
}
/* -------------------------------------------------------------------------- */
void BemPolonski::computeGaps() {
UInt size = surface.size();
#pragma omp parallel for
for (UInt i = 0; i < size * size; i++) {
gap(i) = surface_displacements(i) - surface(i);
}
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::computeMeanGapsInContact() {
UInt n = surface.size();
UInt size = n * n;
Real res = 0.;
UInt nb_contact = 0;
#pragma omp parallel for reduction(+ : nb_contact, res)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0 ||
std::abs(this->surface_tractions(i) - p_sat) < 1.0e-10)
continue;
++nb_contact;
res += this->gap(i);
}
res /= nb_contact;
return res;
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::computeG() {
UInt n = surface.size();
UInt size = n * n;
Real res = 0.;
#pragma omp parallel for reduction(+ : res)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0 ||
std::abs(this->surface_tractions(i) - p_sat) < 1.0e-10)
continue;
Real val = this->gap(i);
res += val * val;
}
return res;
}
/* -------------------------------------------------------------------------- */
void BemPolonski::updateT(Real G, Real Gold, Real delta) {
UInt n = surface.size();
UInt size = n * n;
Real factor = delta * G / Gold;
#pragma omp parallel for
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0)
this->surface_t(i) = 0.;
else {
this->surface_t(i) *= factor;
this->surface_t(i) += this->gap(i);
}
}
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::computeTau() {
this->applyInfluenceFunctions(surface_t, surface_r);
const UInt size = surface_t.size() * surface_t.size();
Real rbar = 0;
UInt nb_contact = 0;
#pragma omp parallel for reduction(+ : nb_contact, rbar)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0)
continue;
++nb_contact;
rbar += surface_r(i);
}
rbar /= nb_contact;
surface_r -= rbar;
Real tau_sum1 = 0., tau_sum2 = 0.;
#pragma omp parallel for reduction(+ : tau_sum1, tau_sum2)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0)
continue;
tau_sum1 += this->gap(i) * surface_t(i);
tau_sum2 += surface_r(i) * surface_t(i);
}
Real tau = tau_sum1 / tau_sum2;
return tau;
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::updateTractions(Real tau) {
UInt n = surface.size();
UInt size = n * n;
#pragma omp parallel for
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0)
continue;
this->surface_tractions(i) -= tau * this->surface_t(i);
if (this->surface_tractions(i) < 0.)
this->surface_tractions(i) = 0;
}
// compute number of interpenetration without contact
UInt nb_iol = 0;
#pragma omp parallel for reduction(+ : nb_iol)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) <= 0. && this->gap(i) < 0.) {
this->surface_tractions(i) -= tau * this->gap(i);
++nb_iol;
}
}
// compute number of interpenetration without contact
UInt nb_sl = 0;
#pragma omp parallel for reduction(+ : nb_sl)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) == p_sat && 0. < this->gap(i)) {
this->surface_tractions(i) -= tau * this->gap(i);
++nb_sl;
}
}
Real delta = 0;
if (nb_iol > 0 || nb_sl > 0)
delta = 0.;
else
delta = 1.;
return delta;
}
/* -------------------------------------------------------------------------- */
void BemPolonski::enforcePressureBalance(Real applied_pressure) {
UInt n = surface.size();
UInt size = n * n;
// If we have no saturation, scale to match applied_pressure
if (this->p_sat <= 0. || SurfaceStatistics::computeMaximum(
this->surface_tractions) < this->p_sat) {
Real pressure = 0.;
#pragma omp parallel for reduction(+ : pressure)
for (UInt i = 0; i < size; ++i) {
pressure += this->surface_tractions(i);
}
pressure *= 1. / size;
this->surface_tractions *= applied_pressure / pressure;
}
// If we have saturation, use secant method to find zero of saturationFunction
else {
// Checking if we can find a zero
Real limit = this->p_sat * SurfaceStatistics::computeContactArea(
this->surface_tractions) -
applied_pressure;
if (limit < 0)
SURFACE_FATAL("Saturation pressure is too small for applied pressure");
// Initial points
Real x_n_2 = 0., x_n_1 = 1., x_n = 0.;
Real f_n_2 = 0., f_n_1 = 0., f_n = 0.;
// Secant loop
do {
f_n_2 = saturationFunction(x_n_2, applied_pressure);
f_n_1 = saturationFunction(x_n_1, applied_pressure);
x_n = x_n_1 - f_n_1 * (x_n_1 - x_n_2) / (f_n_1 - f_n_2);
f_n = saturationFunction(x_n, applied_pressure);
x_n_2 = x_n_1;
x_n_1 = x_n;
} while (std::abs(f_n) > 1e-16);
this->surface_tractions *= x_n;
// Truncating pressures
#pragma omp parallel for
for (UInt i = 0; i < size; i++) {
if (this->surface_tractions(i) > this->p_sat)
this->surface_tractions(i) = this->p_sat;
}
// Real mu_I_sat=0.;
// #pragma omp parallel for reduction(+: mu_I_sat)
// for (UInt i = 0; i < size; ++i) {
// if ( this->p_sat< this->surface_tractions(i) ){
// mu_I_sat+=1.;
// }
// }
// Real pc=0.;
// #pragma omp parallel for reduction(+: pc)
// for (UInt i = 0; i < size; ++i) {
// if ( this->surface_tractions(i) < this->p_sat ){
// pc+=this->surface_tractions(i);}
// }
// #pragma omp parallel for
// for (UInt i = 0; i < size; ++i) {
// if ( this->surface_tractions(i) < this->p_sat ){
// this->surface_tractions(i)=
// this->surface_tractions(i)*((size*applied_pressure-this->p_sat*mu_I_sat)/pc);}
// }
// #pragma omp parallel for
// for (UInt i = 0; i < size; ++i) {
// if ( this->p_sat< this->surface_tractions(i) ){
// this->surface_tractions(i)=this->p_sat;
// }
// }
}
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::saturationFunction(Real alpha, Real applied_pressure) {
const UInt n = surface.size();
const UInt size = n * n;
Real sum = 0.;
#pragma omp parallel for reduction(+ : sum)
for (UInt i = 0; i < size; i++) {
Real alpha_p = alpha * this->surface_tractions(i);
Real alpha_p_I = (alpha_p > this->p_sat) ? alpha_p - this->p_sat : 0.;
sum += alpha_p - alpha_p_I;
}
sum /= size;
return sum - applied_pressure;
}
/* -------------------------------------------------------------------------- */
Real BemPolonski::computeF() {
UInt n = surface.size();
UInt size = n * n;
Real res = 0;
Real t_sum = SurfaceStatistics::computeSum(surface_tractions);
computeTrueDisplacements();
#pragma omp parallel for reduction(+ : res)
for (UInt i = 0; i < size; ++i) {
if (this->surface_tractions(i) == this->p_sat)
continue;
res += surface_tractions(i) * (this->true_displacements(i) - surface(i));
// res +=
// this->surface_tractions[i].real()
// *(surface_displacements[i].real() - surface[i].real());
}
return std::abs(res / t_sum / surface_rms_heights / size);
}
/* -------------------------------------------------------------------------- */
void BemPolonski::computeTrueDisplacements() {
this->applyInfluenceFunctions(this->surface_tractions,
this->surface_displacements);
this->true_displacements = this->surface_displacements;
UInt n = surface.size();
UInt size = n * n;
Real shift = 1e300;
#pragma omp parallel for reduction(min : shift)
for (UInt i = 0; i < size; ++i) {
if (surface_displacements(i) - shift - surface(i) < 0. &&
(this->p_sat < 0 || this->surface_tractions(i) < this->p_sat)) {
shift = surface_displacements(i) - surface(i);
}
}
#pragma omp parallel for
for (UInt i = 0; i < size; ++i) {
true_displacements(i) = surface_displacements(i) - shift;
}
}
/* -------------------------------------------------------------------------- */
__END_TAMAAS__

Event Timeline