dcomplex OrderParameter::SphHarm(int l, int m, Real3D r) { real d = r.abs(); // distance between two particles real theta, phi; // defining theta and phi theta = acos( r[2] / d ); // in radians // phi is defined as http://en.wikipedia.org/wiki/Atan2 // problem is x = y = 0, we will define it like 0 if(r[0] > 0.0){ phi = atan( r[1]/r[0] ); } else if( r[0] < 0.0 && r[1] >= 0.0 ){ phi = atan( r[1]/r[0] ) + M_PIl; } else if( r[0] < 0.0 && r[1] < 0.0 ){ phi = atan( r[1]/r[0] ) - M_PIl; } else if( r[0] == 0.0 && r[1] > 0.0 ){ phi = M_PIl; } else if( r[0] == 0.0 && r[1] < 0.0 ){ phi = -M_PIl; } else{ // x = 0; y = 0; phi = 0.0; } return boost::math::spherical_harmonic(l, m, theta, phi); }
// TODO currently works correctly for Lx = Ly = Lz // rdfN is a level of discretisation of rdf (how many elements it contains) python::list RDFatomistic::computeArray(int rdfN) const { System& system = getSystemRef(); esutil::Error err(system.comm); Real3D Li = system.bc->getBoxL(); Real3D Li_half = Li / 2.; int nprocs = system.comm->size(); int myrank = system.comm->rank(); real histogram [rdfN]; for(int i=0;i<rdfN;i++) histogram[i]=0; real dr = Li_half[1] / (real)rdfN; // If you work with nonuniform Lx, Ly, Lz, you // should use for Li_half[XXX] the shortest side length /*struct data{ Real3D pos; int type; int molecule; };*/ int num_part = 0; //ConfigurationPtr config = make_shared<Configuration> (); map< size_t, data > config; for (int rank_i=0; rank_i<nprocs; rank_i++) { //map< size_t, Real3D > conf; map< size_t, data > conf; if (rank_i == myrank) { shared_ptr<FixedTupleListAdress> fixedtupleList = system.storage->getFixedTuples(); CellList realCells = system.storage->getRealCells(); for(CellListIterator cit(realCells); !cit.isDone(); ++cit) { Particle &vp = *cit; FixedTupleListAdress::iterator it2; it2 = fixedtupleList->find(&vp); if (it2 != fixedtupleList->end()) { // Are there atomistic particles for given CG particle? If yes, use those for calculation. std::vector<Particle*> atList; atList = it2->second; for (std::vector<Particle*>::iterator it3 = atList.begin(); it3 != atList.end(); ++it3) { Particle &at = **it3; int id = at.id(); //conf[id] = at.position(); data tmp = { at.position(), at.type(), vp.id() }; conf[id] = tmp; } } else{ // If not, use CG particle itself for calculation. std::cout << "WARNING! In RDFatomistic, no atomistic AdResS particle found!\n"; exit(1); //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) { for (map<size_t,data>::iterator itr=conf.begin(); itr != conf.end(); ++itr) { //size_t id = itr->first; //Real3D p = itr->second; //config->set(num_part, p[0], p[1], p[2]); data p = itr->second; config[num_part] = p; num_part ++; } } int num_pairs = 0; // 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 int numi = num_part / nprocs + 1; int mini = myrank * numi; int maxi = mini + numi; if(maxi>num_part) maxi = num_part; int perc=0, perc1=0; for(int i = mini; i<maxi; i++){ //Real3D coordP1 = config->getCoordinates(i); Real3D coordP1 = config[i].pos; int typeP1 = config[i].type; int molP1 = config[i].molecule; if((coordP1[0] < Li_half[0]+span) && (coordP1[0] > Li_half[0]-span) ){ for(int j = i+1; j<num_part; j++){ //Real3D coordP2 = config->getCoordinates(j); Real3D coordP2 = config[j].pos; int typeP2 = config[j].type; int molP2 = config[j].molecule; if (molP1 != molP2){ if( ( (typeP1 == target1) && (typeP2 == target2) ) || ( (typeP1 == target2) && (typeP2 == target1) ) ){ Real3D distVector = coordP1 - coordP2; // minimize the distance in simulation box for(int ii=0; ii<3; ii++){ if( distVector[ii] < -Li_half[ii] ) distVector[ii] += Li[ii]; if( distVector[ii] > Li_half[ii] ) distVector[ii] -= Li[ii]; } int bin = (int)( distVector.abs() / dr ); if( bin < rdfN){ histogram[bin] += 1.0; } num_pairs += 1; } } } } /*if(system.comm->rank()==0){ perc = (int)(100*(real)(i-mini)/(real)(maxi-mini)); if(perc>perc1){ cout<<"calculation progress (radial distr. func.): "<< perc << " %\r"<<flush; perc1 = perc; } }*/ } /*if(system.comm->rank()==0) cout<<"calculation progress (radial distr. func.): "<< 100 << " %" <<endl;*/ real totHistogram[rdfN]; boost::mpi::all_reduce(*system.comm, histogram, rdfN, totHistogram, plus<real>()); int tot_num_pairs = 0; boost::mpi::all_reduce(*system.comm, num_pairs, tot_num_pairs, plus<int>()); //std::cout << tot_num_pairs << "\n"; // normalizing int nconfigs = 1; //config - 1 //avg_part = part_total / float(nconfigs) //real rho = (real)num_part / (Li[0]*Li[1]*Li[2]); real rho = (real)1.0 / (Li[0]*Li[1]*Li[2]); //real factor = 2.0 * M_PIl * dr * rho * (real)nconfigs * (real)num_part; real factor = 4.0 * M_PIl * dr * rho * (real)nconfigs * (real)tot_num_pairs; for(int i=0; i < rdfN; i++){ real radius = (i + 0.5) * dr; totHistogram[i] /= factor * (radius*radius + dr*dr / 12.0); } python::list pyli; for(int i=0; i < rdfN; i++){ pyli.append( totHistogram[i] ); } return pyli; }
// TODO currently works correctly if L_y is shortest side length (it's fine if L_x and/or L_z are equal to L_y) // rdfN is a level of discretisation of rdf (how many elements it contains) python::list RDFatomistic::computeArray(int rdfN) const { System& system = getSystemRef(); esutil::Error err(system.comm); Real3D Li = system.bc->getBoxL(); Real3D Li_half = Li / 2.; int nprocs = system.comm->size(); int myrank = system.comm->rank(); real histogram [rdfN]; for(int i=0;i<rdfN;i++) histogram[i]=0; real dr = Li_half[1] / (real)rdfN; // If you work with nonuniform Lx, Ly, Lz, you // should use for Li_half[XXX] the shortest side length. Currently using L_y int num_part = 0; map< size_t, data > config; for (int rank_i=0; rank_i<nprocs; rank_i++) { map< size_t, data > conf; if (rank_i == myrank) { shared_ptr<FixedTupleListAdress> fixedtupleList = system.storage->getFixedTuples(); CellList realCells = system.storage->getRealCells(); for(CellListIterator cit(realCells); !cit.isDone(); ++cit) { Particle &vp = *cit; FixedTupleListAdress::iterator it2; it2 = fixedtupleList->find(&vp); if (it2 != fixedtupleList->end()) { // Are there atomistic particles for given CG particle? If yes, use those for calculation. std::vector<Particle*> atList; atList = it2->second; for (std::vector<Particle*>::iterator it3 = atList.begin(); it3 != atList.end(); ++it3) { Particle &at = **it3; int id = at.id(); data tmp = { at.position(), at.type(), vp.id(), vp.lambda() }; conf[id] = tmp; } } else{ // If not, use CG particle itself for calculation. std::cout << "WARNING! In RDFatomistic, no atomistic AdResS particle found!\n"; exit(1); } } } boost::mpi::broadcast(*system.comm, conf, rank_i); // for simplicity we will number the particles from 0 for (map<size_t,data>::iterator itr=conf.begin(); itr != conf.end(); ++itr) { data p = itr->second; config[num_part] = p; num_part ++; } } int num_pairs = 0; // 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 int numi = num_part / nprocs + 1; int mini = myrank * numi; int maxi = mini + numi; if(maxi>num_part) maxi = num_part; int perc=0, perc1=0; for(int i = mini; i<maxi; i++){ Real3D coordP1 = config[i].pos; int typeP1 = config[i].type; int molP1 = config[i].molecule; real resolutionP1 = config[i].resolution; if (spanbased == true){ if((coordP1[0] < Li_half[0]+span) && (coordP1[0] > Li_half[0]-span) ){ for(int j = i+1; j<num_part; j++){ Real3D coordP2 = config[j].pos; int typeP2 = config[j].type; int molP2 = config[j].molecule; if (molP1 != molP2){ if( ( (typeP1 == target1) && (typeP2 == target2) ) || ( (typeP1 == target2) && (typeP2 == target1) ) ){ Real3D distVector = (0.0, 0.0, 0.0); system.bc->getMinimumImageVector(distVector, coordP1, coordP2); int bin = (int)( distVector.abs() / dr ); if( bin < rdfN){ histogram[bin] += 1.0; } num_pairs += 1; } } } } } else{ if( resolutionP1 == 1.0 ){ for(int j = i+1; j<num_part; j++){ Real3D coordP2 = config[j].pos; int typeP2 = config[j].type; int molP2 = config[j].molecule; real resolutionP2 = config[j].resolution; if (molP1 != molP2){ if( ( (typeP1 == target1) && (typeP2 == target2) ) || ( (typeP1 == target2) && (typeP2 == target1) ) ){ num_pairs += 1; if( resolutionP2 == 1.0 ){ Real3D distVector = (0.0, 0.0, 0.0); system.bc->getMinimumImageVector(distVector, coordP1, coordP2); int bin = (int)( distVector.abs() / dr ); if( bin < rdfN){ histogram[bin] += 1.0; } } } } } } } } real totHistogram[rdfN]; boost::mpi::all_reduce(*system.comm, histogram, rdfN, totHistogram, plus<real>()); int tot_num_pairs = 0; boost::mpi::all_reduce(*system.comm, num_pairs, tot_num_pairs, plus<int>()); int nconfigs = 1; real rho = (real)1.0 / (Li[0]*Li[1]*Li[2]); real factor = 4.0 * M_PIl * dr * rho * (real)nconfigs * (real)tot_num_pairs; for(int i=0; i < rdfN; i++){ real radius = (i + 0.5) * dr; totHistogram[i] /= factor * (radius*radius + dr*dr / 12.0); } python::list pyli; for(int i=0; i < rdfN; i++){ pyli.append( totHistogram[i] ); } return pyli; }
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; }