int main() { auto lbmodel = std::make_unique<LBModel>("D2Q9"); float rholocal = 1.0f; std::array<float, 3> ulocal = {0.5, 0.5, -0.5}; std::vector<float> nlocal(lbmodel->get_num_directions(), 0.0f); // Get eqlb dist auto eqlbdist = std::make_unique<EqlbDist>(lbmodel.get()); (*eqlbdist)(rholocal, ulocal, nlocal); // Expected value of eqlb dist std::vector<float> nexpected = { -0.05555555597, 0.277777791, -0.05555555597, -0.05555555597, 0.277777791, -0.003472222248, -0.003472222248, 0.2048611194, 0.03819444403 }; // Error auto err = 0.0f; for (auto k = 0; k < 9; ++k) { auto tmp = nexpected[k] - nlocal[k]; err += tmp*tmp; } assert(err == 0.0f); }
//-------------------------------------------------------- // apply_charged_surfaces //-------------------------------------------------------- void ChargeRegulatorMethodEffectiveCharge::apply_local_forces() { double * q = lammpsInterface_->atom_charge(); _atomElectricalForce_.resize(nlocal(),nsd_); double penalty = poissonSolver_->penalty_coefficient(); if (penalty <= 0.0) throw ATC_Error("ExtrinsicModelElectrostatic::apply_charged_surfaces expecting non zero penalty"); double dx[3]; const DENS_MAT & xa((interscaleManager_->per_atom_quantity("AtomicCoarseGrainingPositions"))->quantity()); // WORKSPACE - most are static SparseVector<double> dv(nNodes_); vector<SparseVector<double> > derivativeVectors; derivativeVectors.reserve(nsd_); const SPAR_MAT_VEC & shapeFunctionDerivatives((interscaleManager_->vector_sparse_matrix("InterpolateGradient"))->quantity()); DenseVector<INDEX> nodeIndices; DENS_VEC nodeValues; NODE_TO_XF_MAP::const_iterator inode; for (inode = nodeXFMap_.begin(); inode != nodeXFMap_.end(); inode++) { int node = inode->first; DENS_VEC xI = (inode->second).first; double qI = (inode->second).second; double phiI = nodalChargePotential_[node]; for (int i = 0; i < nlocal(); i++) { int atom = (atc_->internal_to_atom_map())(i); double qa = q[atom]; if (qa != 0) { double dxSq = 0.; for (int j = 0; j < nsd_; j++) { dx[j] = xa(i,j) - xI(j); dxSq += dx[j]*dx[j]; } if (dxSq < rCsq_) { // first apply pairwise coulombic interaction if (!useSlab_) { double coulForce = qqrd2e_*qI*qa/(dxSq*sqrtf(dxSq)); for (int j = 0; j < nsd_; j++) { _atomElectricalForce_(i,j) += dx[j]*coulForce; } } // second correct for FE potential induced by BCs // determine shape function derivatives at atomic location // and construct sparse vectors to store derivative data for (int j = 0; j < nsd_; j++) { shapeFunctionDerivatives[j]->row(i,nodeValues,nodeIndices); derivativeVectors.push_back(dv); for (int k = 0; k < nodeIndices.size(); k++) { derivativeVectors[j](nodeIndices(k)) = nodeValues(k); } } // compute greens function from charge quadrature SparseVector<double> shortFePotential(nNodes_); shortFePotential.add_scaled(greensFunctions_[node],penalty*phiI); // compute electric field induced by charge DENS_VEC efield(nsd_); for (int j = 0; j < nsd_; j++) { efield(j) = -.1*dot(derivativeVectors[j],shortFePotential); } // apply correction in atomic forces double c = qV2e_*qa; for (int j = 0; j < nsd_; j++) { if ((!useSlab_) || (j==nsd_)) { _atomElectricalForce_(i,j) -= c*efield(j); } } } } } } }