python::list StaticStructF::computeArray(int nqx, int nqy, int nqz, real bin_factor) const { time_t start; time(&start); cout << "collective calc starts " << ctime(&start) << "\n"; //fist the system coords are saved at each CPU System& system = getSystemRef(); esutil::Error err(system.comm); Real3D Li = system.bc->getBoxL(); //Box size (Lx, Ly, Lz) int nprocs = system.comm->size(); // number of CPUs int myrank = system.comm->rank(); // current CPU's number if (myrank == 0) { cout << "collective calc starts " << ctime(&start) << "\n"; } int num_part = 0; ConfigurationPtr config = make_shared<Configuration > (); // loop over all CPU-numbers - to give all CPUs all particle coords for (int rank_i = 0; rank_i < nprocs; rank_i++) { map< size_t, Real3D > conf; if (rank_i == myrank) { CellList realCells = system.storage->getRealCells(); for (CellListIterator cit(realCells); !cit.isDone(); ++cit) { int id = cit->id(); conf[id] = cit->position(); } } boost::mpi::broadcast(*system.comm, conf, rank_i); // for simplicity we will number the particles from 0 for (map<size_t, Real3D>::iterator itr = conf.begin(); itr != conf.end(); ++itr) { size_t id = itr->first; Real3D p = itr->second; config->set(id, p[0], p[1], p[2]); //config->set(num_part, p[0], p[1], p[2]); num_part++; } } if (myrank == 0) { time_t distributed; time(&distributed); cout << "particles on all CPUs " << ctime(&distributed) << "\n"; cout << "distribution to CPUs took " << difftime(distributed, start) << " seconds \n"; } // now all CPUs have all particle coords and num_part is the total number // of particles // use all CPUs // TODO it could be a problem if n_nodes > num_part // here starts calculation of the static structure factor //step size for qx, qy, qz real dqs[3]; dqs[0] = 2. * M_PIl / Li[0]; dqs[1] = 2. * M_PIl / Li[1]; dqs[2] = 2. * M_PIl / Li[2]; Real3D q; //calculations for binning real bin_size = bin_factor * min(dqs[0], (dqs[1], dqs[2])); real q_sqr_max = nqx * nqx * dqs[0] * dqs[0] + nqy * nqy * dqs[1] * dqs[1] + nqz * nqz * dqs[2] * dqs[2]; real q_max = sqrt(q_sqr_max); int num_bins = (int) ceil(q_max / bin_size); vector<real> sq_bin; vector<real> q_bin; vector<int> count_bin; sq_bin.resize(num_bins); q_bin.resize(num_bins); count_bin.resize(num_bins); if (myrank == 0) { cout << nprocs << " CPUs\n\n" << "bin size \t" << bin_size << "\n" << "q_max \t" << q_max << "\n"; } real n_reci = 1. / num_part; real scos_local = 0; //will store cos-sum on each CPU real ssin_local = 0; //will store sin-sum on each CPU int ppp = (int) ceil((double) num_part / nprocs); //particles per proc Real3D coordP; python::list pyli; //loop over different q values //starting from zero because combinations with negative components //will give the same result in S(q). so S(q) is the same for //the 8 vectors q=(x,y,z),(-x,y,z), (x,-y,z),(x,y,-z),(-x,-y,z),... for (int hx = -nqx; hx <= nqx; hx++) { for (int hy = -nqy; hy <= nqy; hy++) { for (int hz = 0; hz <= nqz; hz++) { //values of q-vector q[0] = hx * dqs[0]; q[1] = hy * dqs[1]; q[2] = hz * dqs[2]; real q_abs = q.abs(); //determining the bin number int bin_i = (int) floor(q_abs / bin_size); q_bin[bin_i] += q_abs; count_bin[bin_i] += 1; //resetting the variables that store the local sum on each proc scos_local = 0; ssin_local = 0; //loop over particles for (int k = myrank * ppp; k < (1 + myrank) * ppp && k < num_part; k++) { coordP = config->getCoordinates(k); scos_local += cos(q * coordP); ssin_local += sin(q * coordP); } if (myrank != 0) { boost::mpi::reduce(*system.comm, scos_local, plus<real > (), 0); boost::mpi::reduce(*system.comm, ssin_local, plus<real > (), 0); } if (myrank == 0) { real scos = 0; real ssin = 0; boost::mpi::reduce(*system.comm, scos_local, scos, plus<real > (), 0); boost::mpi::reduce(*system.comm, ssin_local, ssin, plus<real > (), 0); sq_bin[bin_i] += scos * scos + ssin * ssin; } } } } //creates the python list with the results if (myrank == 0) { //starting with bin_i = 1 will leave out the value for q=0, otherwise start with bin_i=0 for (int bin_i = 1; bin_i < num_bins; bin_i++) { real c = (count_bin[bin_i]) ? 1 / (real) count_bin[bin_i] : 0; sq_bin[bin_i] = n_reci * sq_bin[bin_i] * c; q_bin[bin_i] = q_bin[bin_i] * c; python::tuple q_Sq_pair; q_Sq_pair = python::make_tuple(q_bin[bin_i], sq_bin[bin_i]); pyli.append(q_Sq_pair); } } return pyli; }
python::list StaticStructF::computeArraySingleChain(int nqx, int nqy, int nqz, real bin_factor, int chainlength) const { //fist the system coords are saved at each CPU System& system = getSystemRef(); esutil::Error err(system.comm); Real3D Li = system.bc->getBoxL(); //Box size (Lx, Ly, Lz) int nprocs = system.comm->size(); // number of CPUs int myrank = system.comm->rank(); // current CPU's number int num_part = 0; ConfigurationPtr config = make_shared<Configuration > (); // loop over all CPU-numbers - to give all CPUs all particle coords for (int rank_i = 0; rank_i < nprocs; rank_i++) { map< size_t, Real3D > conf; if (rank_i == myrank) { CellList realCells = system.storage->getRealCells(); for (CellListIterator cit(realCells); !cit.isDone(); ++cit) { int id = cit->id(); conf[id] = cit->position(); } } boost::mpi::broadcast(*system.comm, conf, rank_i); // for simplicity we will number the particles from 0 for (map<size_t, Real3D>::iterator itr = conf.begin(); itr != conf.end(); ++itr) { size_t id = itr->first; Real3D p = itr->second; config->set(id, p[0], p[1], p[2]); //config->set(num_part, p[0], p[1], p[2]); num_part++; } } cout << "particles are given to each CPU!\n"; // now all CPUs have all particle coords and num_part is the total number // of particles // use all CPUs // TODO it could be a problem if n_nodes > num_part // here starts calculation of the static structure factor //step size for qx, qy, qz real dqs[3]; dqs[0] = 2. * M_PIl / Li[0]; dqs[1] = 2. * M_PIl / Li[1]; dqs[2] = 2. * M_PIl / Li[2]; Real3D q; //calculations for binning real bin_size = bin_factor * min(dqs[0], (dqs[1], dqs[2])); real q_sqr_max = nqx * nqx * dqs[0] * dqs[0] + nqy * nqy * dqs[1] * dqs[1] + nqz * nqz * dqs[2] * dqs[2]; real q_max = sqrt(q_sqr_max); int num_bins = (int) ceil(q_max / bin_size); vector<real> sq_bin; vector<real> q_bin; vector<int> count_bin; sq_bin.resize(num_bins); q_bin.resize(num_bins); count_bin.resize(num_bins); if (myrank == 0) { cout << nprocs << " CPUs\n\n" << "bin size \t" << bin_size << "\n" << "q_max \t" << q_max << "\n"; } real n_reci = 1. / num_part; real chainlength_reci = 1. / chainlength; real scos_local = 0; //will store cos-sum on each CPU real ssin_local = 0; //will store sin-sum on each CPU //will store the summation of the the single chain structure factor real singleChain_localSum = 0; Real3D coordP; python::list pyli; //calculations for parallelizing (over chains) int num_chains; if (num_part % chainlength == 0) num_chains = num_part / chainlength; else { cout << "ERROR: chainlenght does not match total number of " << "particles. num_part % chainlenght is unequal 0. \n" << "Calculation of SingleChain_StaticStructF aborted\n"; return pyli; } int cpp = (int) ceil((double) num_chains / nprocs); //chains per proc cout << "chains per proc\t" << cpp << "\n"; //loop over different q values //starting from zero because combinations with negative components //will give the same result in S(q). so S(q) is the same for //the 8 vectors q=(x,y,z),(-x,y,z), (x,-y,z),(x,y,-z),(-x,-y,z),... for (int hx = -nqx; hx <= nqx; hx++) { for (int hy = -nqy; hy <= nqy; hy++) { for (int hz = 0; hz <= nqz; hz++) { //values of q-vector q[0] = hx * dqs[0]; q[1] = hy * dqs[1]; q[2] = hz * dqs[2]; real q_abs = q.abs(); //determining the bin number int bin_i = (int) floor(q_abs / bin_size); q_bin[bin_i] += q_abs; count_bin[bin_i] += 1; //resetting the variable that stores the sum for each q-vector singleChain_localSum = 0; //loop over chains (cid is chain_id) for (int cid = myrank * cpp; cid < (1 + myrank) * cpp && cid < num_chains; cid++) { scos_local = 0; //resetting the cos sum for the each chain ssin_local = 0; //resetting the sin sum for the each chain //loop over particles for (int k = cid * chainlength; k < (1 + cid) * chainlength && k < num_part; k++) { coordP = config->getCoordinates(k); scos_local += cos(q * coordP); ssin_local += sin(q * coordP); } //the (summation part of the) single chain structure // factors are summed up for the averaging at the // end (over the chains) singleChain_localSum += scos_local * scos_local + ssin_local * ssin_local; } if (myrank != 0) { boost::mpi::reduce(*system.comm, singleChain_localSum, plus<real > (), 0); } if (myrank == 0) { real singleChainSum = 0; boost::mpi::reduce(*system.comm, singleChain_localSum, singleChainSum, plus<real > (), 0); sq_bin[bin_i] += singleChainSum; } } } } //creates the python list with the results if (myrank == 0) { //starting with bin_i = 1 will leave out the value for q=0, otherwise start with bin_i=0 for (int bin_i = 1; bin_i < num_bins; bin_i++) { real c = (count_bin[bin_i]) ? 1 / (real) count_bin[bin_i] : 0; sq_bin[bin_i] = n_reci * chainlength_reci * sq_bin[bin_i] * c; q_bin[bin_i] = q_bin[bin_i] * c; python::tuple q_Sq_pair; q_Sq_pair = python::make_tuple(q_bin[bin_i], sq_bin[bin_i]); pyli.append(q_Sq_pair); } } return pyli; }