I am running a simulation where I have to compute the energy of my system. The system primarily has two types of particles, and in my energy computation, I loop through all instances of each type of particle. The serial loop version looks something like this:
double CalculateEnergy (std::vector <Polymer>* Polymers, std::vector <Particle*>* Cosolvent, std::vector <Particle*>* LATTICE, std::array<double,8>* E, std::array<double,8>* contacts, int x, int y, int z) {
double Energy {0.0};
(*contacts) = {0,0,0,0,0,0,0,0};
// loop through all the particles in Polymers
for (Polymer& pmer: (*Polymers)) {
for (Particle*& p: pmer.chain){
// perform an energy computation
Energy += (*LATTICE)[f(*p)]; // f is an arbitrary function that uses a property of p.
}
}
// loop through all particles of the cosolvent
for ( Particle*& p: *Cosolvent ){
// perform an energy computation
Energy += (*LATTICE)[g(*p)]; // g is an arbitrary function that uses properties of p.
}
return Energy;
}
Yes, I am using raw pointers in C++, but it does the job well enough and I see no reason to change it so far.
The idea is that I loop through Polymers, calculate energetic contribution of each particles in that set, then I loop through Cosolvent, and calculate the energetic contribution of each particle in that set. As the number of particles in my system grows, running this serially would be inefficient, timewise. So I want to parallelize this energy computation: where 1 thread does the Polymers loop, and the other thread does the Cosolvent loop.
This is what I have done:
double CalculateEnergy_parallelized (std::vector <Polymer>* Polymers, std::vector <Particle*>* Cosolvent, std::vector <Particle*>* LATTICE, std::array<double,8>* E, std::array<double,8>* contacts, int x, int y, int z) {
double Energy {0.0};
(*contacts) = {0,0,0,0,0,0,0,0};
double E1;
double E2;
std::thread t1 (PolymerEnergyLoop, Polymers, LATTICE, E, &E1, contacts, x, y, z);
std::thread t2 (CosolventEnergyLoop, Cosolvent, LATTICE, E, &E2, contacts, x, y, z);
// CosolventEnergyLoop ( Cosolvent, LATTICE, E, &E2, contacts, x, y, z);
t1.join();
t2.join();
Energy = E1 + E2;
// std::array <std::array <int,3>, 26> ne_list;
return Energy;
}
void PolymerEnergyLoop (std::vector <Polymer>* Polymers, std::vector <Particle*>* LATTICE, std::array<double,8>* E, double* Ea, std::array<double,8>* contacts, int x, int y, int z){
double Energy {0.0};
(*contacts) = {0,0,0,0,0,0,0,0};
// loop through all the particles in Polymers
for (Polymer& pmer: (*Polymers)) {
for (Particle*& p: pmer.chain){
// perform an energy computation
Energy += (*LATTICE)[f(*p)]; // f is an arbitrary function that uses a property of p.
}
}
*Ea = Energy;
return;
}
void CosolventEnergyLoop (std::vector <Particle*>* Cosolvent, std::vector <Particle*>* LATTICE, std::array<double,8>* E, double* Ea, std::array<double,8>* contacts, int x, int y, int z){
double Energy {0};
std::array <std::array <int,3>, 26> ne_list;
for ( Particle*& p: *Cosolvent ){
// perform an energy computation
Energy += (*LATTICE)[g(*p)]; // g is an arbitrary function that uses properties of p.
}
*Ea = Energy;
return;
}
However, the parallel version is slower than the serial version, by about 25%.
I know the problem of shared memory which will arise from sharing LATTICE. LATTICE is the superset of Polymers and Cosolvent, and I am asking for information from it repeatedly. Is this the problem of memory sharing in parallel processing? If so, what are the methods of overcoming it?