1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
#include "CBLattice.h"
#include "CbPotential.h"
#include <fstream>
namespace ATC {
// removes any overlapping atoms (avoid calling because it scales n^2.)
INDEX AtomCluster::remove_overlap()
{
INDEX removed_count = 0;
std::vector<double>::iterator r(cur_bond_len_.begin());
std::vector<DENS_VEC>::iterator R(ref_coords_.begin()), Rp;
const double TOL = 1.0e-6 * R->dot(*R);
for (; R!=ref_coords_.end(); R++, r++) {
for (Rp=R+1; Rp!=ref_coords_.end(); Rp++) {
if (sum_difference_squared(*Rp, *R) < TOL) {
ref_coords_.erase(R--);
cur_bond_len_.erase(r--);
++removed_count;
break;
}
}
}
return removed_count;
}
//=========================================================================
// writes cluster to 3 column data format
//=========================================================================
void AtomCluster::write_to_dat(std::string path, bool current_config)
{
const int npts = int(ref_coords_.size());
if (path.substr(path.size()-5,4) != ".dat") path += ".dat";
std::fstream fid(path.c_str(), std::ios::out);
for (int i=0; i<npts; i++) {
DENS_VEC x (current_config ? r(i):R(i));
for (INDEX j=0; j<x.size(); j++) fid << x(j) << " ";
fid << " " << x.norm() << "\n";
}
}
//=========================================================================
// writes cluster to vtk format, (in either reference or current config)
//=========================================================================
void AtomCluster::write_to_vtk(std::string path, bool current_config)
{
const int npts = int(ref_coords_.size());
if (path.substr(path.size()-5,4) != ".vtk") path += ".vtk";
std::fstream fid(path.c_str(), std::ios::out);
// write header
fid << "# vtk DataFile Version 2.0\nWritten from FE-LAMMPS\n";
fid << "ASCII\nDATASET UNSTRUCTURED_GRID\n";
fid << "POINTS " << npts << " float\n";
for (int i=0; i<npts; i++) {
DENS_VEC x (current_config ? r(i):R(i));
for (INDEX j=0; j<x.size(); j++) fid << x(j) << " ";
fid << ((i+1)%3==0 ? "\n" : " ");
}
fid << "\nCELLS "<<npts<<" "<<2*npts<<"\n";
for (int i=0; i<npts; i++) fid << "1" << " " << i << "\n";
fid << "CELL_TYPES " << npts << "\n";
for (int i=0; i<npts; i++) fid << "1" << "\n";
}
//===========================================================================
// constructor
// @param N 3x3 DenseMatrix with each column as a base vector
// @param B 3xn DenseMatrix with each column being a basis vector
// @param R vector of 3D bond Vectors to representative atom in ref config
// @param r vector of bond lengths to representative atom in current config
// @param RC cutoff radius of bond potential
//===========================================================================
CBLattice::CBLattice(const MATRIX &N, const MATRIX &B)
: n_(N), b_(B), N_(N), B_(B)
{
// builds the default queue
for (int a=-1; a<2; a++)
for (int b=-1; b<2; b++)
for (int c=-1; c<2; c++)
if ( a!=0 || b!=0 || c!=0) queue0_.push(hash(a,b,c));
}
//=============================================================================
// writes out default lattice parameters
//=============================================================================
std::ostream & operator<<(std::ostream& o, const CBLattice& lattice)
{
o<<"cutoff radius = "<<sqrt(lattice.RC2_)<<"\n";
lattice.N_.print("Reference base vectors");
lattice.B_.print("Reference basis vectors");
return o;
}
//===========================================================================
// Constructs the virtual atom cluster of neighbors within cutoff
// @param F the deformation gradient tensor
//===========================================================================
void CBLattice::atom_cluster(const MATRIX &F, double cutoff, AtomCluster &v)
{
RC2_ = cutoff*cutoff;
// compute new base and basis vectors
v.clear();
v.F_ = F;
n_ = F*N_;
b_ = F*B_;
// add basis from the center cell (not including representative atom)
for (int i=1; i<B_.nCols(); i++) {
v.cur_bond_len_.push_back(b_.col_norm(i));
v.ref_coords_.push_back(column(B_,i));
}
_FindAtomsInCutoff(v);
}
//=============================================================================
// Computes forces on central atom, with atom I displaced by u.
//=============================================================================
DENS_VEC AtomCluster::perturbed_force(const CbPotential *p, int I, DENS_VEC *u) const
{
DENS_VEC f(3);
for (INDEX i=0; i<size(); i++) {
DENS_VEC ri = r(i);
if (u && i+1==I) ri += *u;
if (u && I==0) ri -= *u;
const double d = ri.norm();
f.add_scaled(ri, -p->phi_r(d)/d);
}
return f;
}
//=============================================================================
// Computes the force constant matrix between atoms I and 0.
//=============================================================================
DENS_MAT AtomCluster::force_constants(INDEX I, const CbPotential *p) const
{
DENS_MAT D(3,3);
for (INDEX i=0; i<3; i++) {
DENS_VEC du(3);
du(i) = 1.0e-6; // take central difference
row(D,i) = perturbed_force(p, I, &du);
du(i) = -du(i);
row(D,i) -= perturbed_force(p, I, &du);
}
D *= 0.5e6;
return D;
}
//=============================================================================
// performs an iterative search for all neighbors within cutoff
//=============================================================================
void CBLattice::_FindAtomsInCutoff(AtomCluster &v)
{
static const int dir[2] = {-1, 1};
int a, b, c, abc;
std::stack<int> queue(queue0_);
std::set<int> done;
// search in each direction
while (!queue.empty()) {
abc = queue.top();
queue.pop();
if (done.find(abc) == done.end()) { // value not in set
unhash(abc,a,b,c); // convert abc to a,b,c
if (_CheckUnitCell(a, b, c, v)) {
done.insert(abc);
// add direct 'outward' neighbors to queue
queue.push(hash(a+dir[a>0], b, c));
queue.push(hash(a, b+dir[b>0], c));
queue.push(hash(a, b, c+dir[c>0]));
}
}
}
}
//===========================================================================
// Computes \f$r^2 = \Vert a n_1 + b n_2 +c n_3 + b_d \Vert^2 \f$
// and adds atom (a,b,c,d) if \f$r^2 < r_{cutoff}^2 \f$
// @param a cell x-index
// @param b cell y-index
// @param c cell z-index
//===========================================================================
bool CBLattice::_CheckUnitCell(char a, char b, char c, AtomCluster &v)
{
const int nsd = n_.nRows(); // number of spatial dimensions
const double A=double(a), B=double(b), C=double(c);
bool found=false;
DENS_VEC r0(nsd,false), R0(nsd,false), Rd(nsd,false); // don't initialize
for (int i=0; i<nsd; i++) { // precompute locations of cell
R0(i) = A*N_(0,i) + B*N_(1,i) + C*N_(2,i); // reference
}
r0 = v.F_*R0; // deformed
for (int d=0; d<b_.nCols(); d++) {
double ri = r0(0) + b_(0,d);
double r2 = ri*ri;
for (int i=1; i<nsd; i++) {
ri = r0(i) + b_(i,d);
r2 += ri*ri;
}
if (r2 <= RC2_) {
v.ref_coords_.push_back(R0);
v.ref_coords_.back() += column(B_,d); // position is R0 + B_[d]
v.cur_bond_len_.push_back(sqrt(r2));
found = true;
}
}
return found;
}
} // end ATC
|