Comments (5)
Hey @dgasmith ,
I am trying to come up with a good way to loop over everything in the electrostatic routine. I have two options:
- Loop over SITES <i,j>. This will be easy to go through and fast to implement. The only problem is that then we need to check if a pair <i,j> is excluded, by finding the pair in a set that contains all the excluded pairs of the system. Also, the screening parameter a that the screening functions need depend on the monomer type. This would add some conditionals in the loop that probably will destroy any chance of vectorization.
- Loop over MONOMER TYPES <i,j>. I already have a vector of pairs with monomer types and number of monomer of each type. Implementing this will require more loops (looping over monomer types, and then over atoms) but will be (I think) easier to parallelize and ensure vectorization if I code it right. We will still need information about excluded pairs, but this time will be a way shorter set, that will be directly accessible through indexes i and j. Also, the excluded pairs are only needed when accounting for electrostatic interaction of two sites of the same monomer.
Unless you have another idea, I would try to go for the second choice. I will see how is the outcome of this and then we can talk about it. But if you have any other idea we can try let me know!
See you!
from mbx.
Hello @dgasmith and @fpaesani ,
A couple of updates about the vectorization of the electrostatics. I think I can divide the obtainment of the different components in two parts:
- Interactions due to sites in the same monomer (for now, later will have to be molecule). This part is practically impossible to vectorize for a couple reasons. A) we need to find if the pair we are looking at is excluded, and if so, provide with the proper thole damping, since for water is 0.626 and 0.055 for 1-2 and 1-3 distances respectively, and for the rest of the molecules is 0.3 and 0.3 respectively. I think I can bypass this by performing the search outside the loop I am vectorizing (see TODOs in the loop in the function below). The main and big problem is B) the gamma function. This function is a sum of infinite terms, and is done by performing undefined loops until the convergence is reached. We could also bypass this by precomputing the values, or setting a maximum number of iterations. The algorithm implemented in our old C++ code is the one shown in numerical recipes, chapter 6.2. HOWEVER, most of the pairs that actually need the gamma function (only for the charge charge interactions) will be excluded. This means that this part of the electrostatics should not be a big amount of time in comparison with all the rest. This is just to obtain the permament electric field, which is only computed once. Thus, unless you think it might be important, I would allow this not to be vectorized and use the functions we already have coded.
- Interactions between sites in different molecules. Here there are not excluded pairs. All the pairs will be computed, and the thole damping is the same for all (0.055). This should be the big cost of the electrostatics calculation. With all the system information I store in the setup of the system, I exactly know how many monomers of each type I have, and how many types are in my system. This allows to easily separate these two sets of calculations, in both the permanent electric field and the dipole electric field.
For your information, since is not pushed yet, I paste the function here that I have for now, which only computes the contribution to the permanent electric field of sites inside the same molecule.
namespace elec {
double electrostatics(const std::vector<double> chg,
const std::vector<double> polfac,
const std::vector<double> pol,
const std::vector<double> orig_xyz,
const std::vector<std::string> mon_id,
const std::vector<size_t> sites,
const std::vector<size_t> first_ind,
const excluded_set_type& excluded12,
const excluded_set_type& excluded13,
const excluded_set_type& excluded14,
const std::vector<std::pair<std::string,size_t>> mon_type_count,
const bool do_grads,
std::vector<double> &grad) {
// Damping declarations
const double aCC = 0.4;
const double aCD = 0.4;
const double aDD = 0.055;
// Constants that will be used later
const double g34 = std::exp(gammln(3.0/4.0));
// System properties and sizes
const size_t nsites = chg.size();
std::vector<double> sqrtpol(3*nsites, 0.0);
// Electric fields and potential
std::vector<double> Efq(3*nsites,0.0);
std::vector<double> Efd(3*nsites,0.0);
std::vector<double> phi(nsites,0.0);
// Squareroot all pols
for (size_t j = 0; j < nsites; j++) {
const size_t j3 = 3*j;
const double sq = std::sqrt(pol[j]);
for (size_t i = 0; i < 3; i++) {
sqrtpol[j3 + i] = sq;
}
}
// Organize xyz so we have x1_1 x1_2 ... y1_1 y1_2...
// where xN_M is read as coordinate x of site N of monomer M
// for the first monomer type. Then follows the second, and so on.
std::vector<double> xyz(nsites,0.0);
size_t fi_mon = 0;
size_t fi_crd = 0;
for (size_t mt = 0; mt < mon_type_count.size(); mt++) {
size_t ns = sites[fi_mon];
size_t nmon = mon_type_count[mt].second;
size_t nmon2 = nmon*2;
for (size_t m = 0; m < nmon; m++) {
size_t mns3 = m*ns*3;
for (size_t i = 0; i < ns; i++) {
size_t inmon3 = 3*i*nmon;
xyz[inmon3 + m + fi_crd] =
orig_xyz[fi_crd + mns3 + 3*i];
xyz[inmon3 + m + fi_crd + nmon] =
orig_xyz[fi_crd + mns3 + 3*i + 1];
xyz[inmon3 + m + fi_crd + nmon2] =
orig_xyz[fi_crd + mns3 + 3*i + 2];
}
}
fi_mon += nmon;
fi_crd += nmon*ns*3;
}
// Obtain permanent electric field
// Monomers alone
fi_mon = 0;
size_t fi_sites = 0;
for (size_t mt = 0; mt < mon_type_count.size(); mt++) {
size_t ns = sites[fi_mon];
size_t nmon = mon_type_count[mt].second;
size_t nmon2 = nmon*2;
for (size_t i = 0; i < ns -1; i++) {
size_t inmon = i*nmon;
size_t inmon3 = 3*inmon;
size_t i3 = 3*i;
for (size_t j = i + 1; j < ns; j++) {
size_t jnmon = j*nmon;
size_t jnmon3 = 3*jnmon;
size_t j3 = 3*j;
// TODO For now, assuming A > std::numeric_limits<double>::epsilon();
// TODO COntinue only if i and j are not bonded
double A = polfac[fi_sites + i] * polfac[fi_sites + j];
double Ai = 1/A;
double Asqsq = A*A*A*A;
std::vector<double> phii(nmon,0.0);
std::vector<double> phij(nmon,0.0);
std::vector<double> Efqix(nmon,0.0);
std::vector<double> Efqjx(nmon,0.0);
std::vector<double> Efqiy(nmon,0.0);
std::vector<double> Efqjy(nmon,0.0);
std::vector<double> Efqiz(nmon,0.0);
std::vector<double> Efqjz(nmon,0.0);
for (size_t m = 0; m < nmon; m++) {
// Distances and values that will be reused
const double rijx = xyz[inmon3 + m] - xyz[jnmon3 + m];
const double rijy = xyz[inmon3 + m + nmon] - xyz[jnmon3 + m + nmon];
const double rijz = xyz[inmon3 + m + nmon2] - xyz[jnmon3 + m + nmon2];
const double rsq = rijx*rijx + rijy*rijy + rijz*rijz;
const double r = std::sqrt(rsq);
const double ri = 1.0/r;
const double risq = ri*ri;
const double rsqsq = rsq * rsq;
// Some values that will be used in the screening functions
const double rA4 = rsqsq/Asqsq;
const double arA4 = aCC*rA4;
// TODO look at the exponential function intel vec
const double exp1 = std::exp(-arA4);
const double gq = gammq(3.0/4.0, arA4);
//const double gq = 1.0;
const double a_mrt = std::pow(aCC, 1.0/4.0);
//const double a4 = aCC * 4.0;
// Get screening functions
const double s1r = ri - exp1*ri;
const double s0r = s1r + a_mrt * Ai * g34 * gq;
const double s1r3 = s1r * risq;
// Update the field
const size_t shift = first_ind[fi_mon + m];
const size_t shift3 = 3*shift;
const size_t spi = shift + i;
const size_t spj = shift + j;
phii[m] = s0r *chg[spj];
phij[m] = s0r *chg[spi];
// Update Electric field
Efqix[m] = s1r3 * chg[spj] * rijx;
Efqjx[m] = s1r3 * chg[spi] * rijx;
Efqiy[m] = s1r3 * chg[spj] * rijy;
Efqjy[m] = s1r3 * chg[spi] * rijy;
Efqiz[m] = s1r3 * chg[spj] * rijz;
Efqjz[m] = s1r3 * chg[spi] * rijz;
}
for (size_t m = 0; m < nmon; m++) {
const size_t shift = first_ind[fi_mon + m];
const size_t shift3 = 3*shift;
phi[i] += phii[m];
phi[j] += phij[m];
Efq[shift3 + i3] += Efqix[m];
Efq[shift3 + j3] -= Efqjx[m];
Efq[shift3 + i3 + 1] += Efqiy[m];
Efq[shift3 + j3 + 1] -= Efqjy[m];
Efq[shift3 + i3 + 2] += Efqiz[m];
Efq[shift3 + j3 + 2] -= Efqjz[m];
}
}
}
// Update first indexes
fi_mon += nmon;
fi_sites += nmon * ns;
}
return 0.0;
}
from mbx.
Electrostatics is implemented with gradients, and working. I will proceed now to clean up the code, reduce the number of vector declarations, and try to compact similar operations.
from mbx.
Hey @dgasmith , (@fpaesani to keep you in the loop)
I pushed to my branch the new version of the electrostatics. These are the new modifications:
- Vectorized all the field and gradient calculations. To add this, I needed to add the pragma ivdep since the compiler was confused about some dependencies that I know for sure they don't exist. With that pragma, loops are vectorized (all except the gammq function, which is not vectorizable at all)
- The code in electrostatics.cpp is cleaner and easier to read. It declares a Field object at the beginning that is used to call the functions that calculate permanent electric field, dipole electric field and gradients.
- The payback is that when I loop over the intramonomer contributions in the permanent electric field, the dipole field and the gradients, that has to call the function N times, where N is the number of monomers. Since the only one that will be called several times is the dipole one, I can generate a special function for the intramonomer case, and vectorize that one too.
- Tests are passing, and the time for the same 256 molecules has been reduced from 2.1 seconds (the first version of the electrostatics code I implemented) to 1.2 seconds using gradients.
I think this is it. Maybe we can discuss today what can we do to make it a little bit faster. I think I added all your suggestions, but I might have forgotten some at some place. I will also have a look at intel sqrt and exp. I did not put that yet.
Thanks for all the tips and advice!!
from mbx.
Seems to work well. Closing issue.
from mbx.
Related Issues (20)
- Improve generalization in energy calls HOT 2
- Need to write unittest for charge gradients
- Write unittests for dipole functions
- Add convergence params update in electrostatics HOT 1
- Update electrostatic force calculation with new functions in helpme HOT 1
- Typo in alpha HOT 1
- CRITICAL BUG in energy2b.cpp
- correlation.dat 2nd column incorrect for fit-2b-ttm HOT 1
- Incorrect unit test for unittest-co2-monomer
- Something odd with general box implementation HOT 1
- buckingham turned off HOT 1
- Add monomer identification from site index
- Installation error on MacOS: "Could NOT find FFTW" when it is installed. HOT 2
- Library in the makefile of the i-pi plugin isn't linked correctly HOT 2
- Meaning of max_n_eval_Xb not clear HOT 3
- OpenMM plugin support HOT 2
- Ensure that make check can only be run when configured without MPI
- Update Readme.md badges
- Stress Tensor HOT 1
- Electric field on LAMMPS doesn't act on MB-pol water
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mbx.