void sort(Master&                   master,               //!< master object
              const Assigner&           assigner,             //!< assigner object
              std::vector<T> Block::*   values,               //!< all values to sort
              std::vector<T> Block::*   samples,              //!< (output) boundaries of blocks
              size_t                    num_samples,          //!< desired number of samples
              const Cmp&                cmp,                  //!< comparison function
              int                       k   = 2,              //!< k-ary reduction will be used
              bool                      samples_only = false) //!< false: results will be all_to_all exchanged; true: only sort but don't exchange results
    {
        bool immediate = master.immediate();
        master.set_immediate(false);

        // NB: although sorter will go out of scope, its member functions sample()
        //     and exchange() will return functors whose copies get saved inside reduce
        detail::SampleSort<Block,T,Cmp> sorter(values, samples, cmp, num_samples);

        // swap-reduce to all-gather samples
        RegularDecomposer<DiscreteBounds> decomposer(1, interval(0,assigner.nblocks()), assigner.nblocks());
        RegularSwapPartners   partners(decomposer, k);
        reduce(master, assigner, partners, sorter.sample(), detail::SkipIntermediate(partners.rounds()));

        // all_to_all to exchange the values
        if (!samples_only)
            all_to_all(master, assigner, sorter.exchange(), k);

        master.set_immediate(immediate);
    }
Esempio n. 2
0
void test(int n, int k)
{
    int dim = 2;

    diy::DiscreteBounds global_bounds(dim);
    global_bounds.min[0] = global_bounds.min[1] = 0;
    global_bounds.max[0] = global_bounds.min[1] = 1023;

    diy::RegularDecomposer<diy::DiscreteBounds> decomposer(dim, global_bounds, n);

    diy::RegularPartners partners(decomposer, k, false);

    int kvs_product = 1;
    for (size_t i = 0; i < partners.rounds(); ++i)
        kvs_product *= partners.size(i);
    REQUIRE(kvs_product == n);

    for (int gid = 0; gid < n; ++gid)
        for (size_t i = 0; i < partners.rounds(); ++i)
        {
            std::vector<int> nbr_gids;
            partners.fill(i, gid, nbr_gids);
            for (int nbr_gid : nbr_gids)
                CHECK(nbr_gid <= n);
        }
}
    void kdtree_sampling
               (Master&                         master,      //!< master object
                const Assigner&                 assigner,    //!< assigner object
                int                             dim,         //!< dimensionality
                const ContinuousBounds&         domain,      //!< global data extents
                std::vector<Point>  Block::*    points,      //!< input points to sort into kd-tree
                size_t                          samples,     //!< number of samples to take in each block
                bool                            wrap = false)//!< periodic boundaries in all dimensions
    {
        if (assigner.nblocks() & (assigner.nblocks() - 1))
        {
            fprintf(stderr, "KD-tree requires a number of blocks that's a power of 2, got %d\n", assigner.nblocks());
            std::abort();
        }

        typedef     diy::RegularContinuousLink      RCLink;

        for (size_t i = 0; i < master.size(); ++i)
        {
            RCLink* link   = static_cast<RCLink*>(master.link(i));
            *link = RCLink(dim, domain, domain);

            if (wrap)       // set up the links to self
            {
                diy::BlockID self = { master.gid(i), master.communicator().rank() };
                for (int j = 0; j < dim; ++j)
                {
                    diy::Direction dir, wrap_dir;

                    // left
                    dir.x[j] = -1; wrap_dir.x[j] = -1;
                    link->add_neighbor(self);
                    link->add_bounds(domain);
                    link->add_direction(dir);
                    link->add_wrap(wrap_dir);

                    // right
                    dir.x[j] = 1; wrap_dir.x[j] = 1;
                    link->add_neighbor(self);
                    link->add_bounds(domain);
                    link->add_direction(dir);
                    link->add_wrap(wrap_dir);
                }
            }
        }

        detail::KDTreeSamplingPartition<Block,Point>    kdtree_partition(dim, points, samples);

        detail::KDTreePartners                          partners(dim, assigner.nblocks(), wrap, domain);
        reduce(master, assigner, partners, kdtree_partition);

        // update master.expected to match the links
        int expected = 0;
        for (size_t i = 0; i < master.size(); ++i)
            expected += master.link(i)->size_unique();
        master.set_expected(expected);
    }
	// calculates and adds its forces to the current forces of the force field
	void MMFF94OutOfPlaneBend::updateForces()
	{
		const double FC = K0 * 2. * RADIAN_TO_DEGREE * RADIAN_TO_DEGREE;
		bool us = getForceField()->getUseSelection();

		//////////////////////////////////////////////////////////////////
		// ids of the non-central atoms for the three runs per out of plane bend:
		vector<vector<Position> > atom_ids;
		// Atom i:
		vector<Position> temp;
		temp.push_back(0);
		temp.push_back(0);
		temp.push_back(1);
		atom_ids.push_back(temp);

		// Atom k:
		temp.clear();
		temp.push_back(1);
		temp.push_back(2);
		temp.push_back(2);
		atom_ids.push_back(temp);

		// Atom l:
		temp.clear();
		temp.push_back(2);
		temp.push_back(1);
		temp.push_back(0);
		atom_ids.push_back(temp);

		////////////////////////////////////////////////////////////////////////
		// all calculations below have to be performed at double precision
		// otherwise the results are far off, especially for small wilson angles
		//
		// temp variables:
		double length;
		TVector3<double> delta;

		// the three atoms bound to the central atom (for the actual plane bend)
		vector<Atom*> partners(3);
		// lenght of the vectors from the central atom to outer atoms:
		vector<double> lengths(3);
		// normalized bond vectors from central atom to outer atoms:
		vector<TVector3<double> > nbv(3);
		
		// index of the individual atoms in partners and nbv:
		Position pi, pk, pl;

		// normal vectors of the three planes:
		TVector3<double> an, bn, cn;

		for (Position t = 0; t < bends_.size(); t++)
		{
			// the current bend
			const OutOfPlaneBend& bend = bends_[t];
			Atom& ta1 = *bend.i->ptr;
			Atom& ta2 = *bend.j->ptr;
			Atom& ta3 = *bend.k->ptr;
			Atom& ta4 = *bend.l->ptr;

			// if using selection and no atom is selected: ignore this bend:
			if (us && !ta1.isSelected() &&
								!ta2.isSelected() &&
								!ta3.isSelected() &&
								!ta4.isSelected())
			{
				continue;
			}

			// non central atoms for this bend:
			partners[0] = &ta1;
			partners[1] = &ta3;
			partners[2] = &ta4;
			Atom& center_atom = ta2;

			// abort for this bend if two atoms have the same position:
			bool error = false;

			// calculate normalized bond vectors from central atom to outer atoms:
			for (Position p = 0; p < 3; p++)
			{
				// transformation from single to double precision:
				delta.x = partners[p]->getPosition().x - center_atom.getPosition().x;
				delta.y = partners[p]->getPosition().y - center_atom.getPosition().y;
				delta.z = partners[p]->getPosition().z - center_atom.getPosition().z;
				length = delta.getLength();
				if (Maths::isZero(length))
				{
					error = true;
					break;
				}

				// normalize the bond vector:
				delta /= length;
				// store the normalized bond vector:
				nbv[p] = delta;
				// store length of this bond:
				lengths[p] = length;
			}

			// abort if any bond lenght equals zero
			if (error) continue;

			// three runs per OOP:
			for (Position run = 0; run < 3; run++)
			{
				// position of the individual atoms in partners[] and nbv[]
				pi = atom_ids[0][run];
				pk = atom_ids[1][run];
				pl = atom_ids[2][run];

				Atom& i = *partners[pi];
				Atom& k = *partners[pk];
				Atom& l = *partners[pl];

				// normalized vectors from central atom to outer atoms:
				const TVector3<double>& ji = nbv[pi];
				const TVector3<double>& jk = nbv[pk];
				const TVector3<double>& jl = nbv[pl];

				const double& length_ji = lengths[pi];
				const double& length_jk = lengths[pk];
				const double& length_jl = lengths[pl];

				// the normal vectors of the three planes:
				an = ji % jk;
				bn = jk % jl;
				cn = jl % ji;

				// Bond angle ji to jk
				const double cos_theta = ji * jk;
				const double theta = acos(cos_theta);
				// If theta equals 180 degree or 0 degree
				if (Maths::isZero(theta) ||
						Maths::isZero(fabs(theta - Constants::PI)))
				{
					continue;
				}
				
				const double sin_theta = sin(theta);
				const double sin_dl = an * jl / sin_theta;

				// the wilson angle:
				const double dl = asin(sin_dl);

				// In case: wilson angle equals 0 or 180 degree: do nothing
				if (Maths::isZero(dl) ||
						Maths::isZero(fabs(dl - Constants::PI)))
				{
					continue;
				}
				

				const double cos_dl = cos(dl);

				// if wilson angle equal 90 degree: abort
				if (cos_dl < 0.0001)
				{
					continue;
				}

				// scaling factor for all forces:
				// wilson K0 * this_bend_constant * wilson_angle * DEGREE_TO_RADIAN * DEGREE_TO_RADIAN
				double c1 = -dl * FC * bend.k_oop * FORCES_FACTOR * Constants::JOULE_PER_CAL;

				double tmp = cos_dl / c1;

			/*	
			Log.precision(30);
      Log.error() << "bond   " << theta            << std::endl;
      Log.error() << "wilson " << dl            << std::endl;
			Log.error() << "tan_dl " << tan_dl            << std::endl;
      Log.error() << "cdst   " << cdst            << std::endl;
      Log.error() << "tdst   "  << tdst           << std::endl;
      Log.error() << "c1     " << c1            << std::endl;
      Log.error() << "abc "   << an << bn << cn << std::endl << std::endl << std::endl << std::endl;
			*/

				const TVector3<double> d_l = ((an / sin_theta - jl * sin_dl) / length_jl) / tmp;
				const TVector3<double> d_i = (((bn + (((-ji + jk * cos_theta) * sin_dl) / sin_theta)) / length_ji) / tmp) / sin_theta;
				const TVector3<double> d_k = (((cn + (((-jk + ji * cos_theta) * sin_dl) / sin_theta)) / length_jk) / tmp) / sin_theta;

 				if (!us || i.isSelected()) AddDV3_(i.getForce(), d_i);
 				if (!us || k.isSelected()) AddDV3_(k.getForce(), d_k);
 				if (!us || l.isSelected()) AddDV3_(l.getForce(), d_l);
 				if (!us || center_atom.isSelected()) AddDV3_(center_atom.getForce(), -(d_i + d_k + d_l));

  #ifdef BALL_MMFF94_TEST
			 getForceField()->error() << std::endl
																<< i.getName() << " " << d_i << std::endl
																<< center_atom.getName() << " " << -(d_i  +d_k + d_l) << std::endl
																<< k.getName() << " " << d_k << std::endl
																<< l.getName() << " " << d_l << std::endl;
   #endif
			}
		}
	}