void
NucleationLocationUserObject::execute()
{
  // here, we just look at an individual element

  /**
   * generate random # based on element id and timestep. random number needs to
   * be different for each element, each timestep.  take steps of n_elem
   */
  unsigned int elem_id = _current_elem->id();

  unsigned int grandgirl = _mrand.randl(_slave_random);

  // we are driving the random seed for each element_id state off of TWO random numbers
  _mrand.seed(elem_id, elem_id + grandgirl + _granddad);

  //_mrand.seed(elem_id, elem_id + _random_seed + (_counter * _mesh.nElem()));
  Real random_number;

  if(!closeToBoundary())
  {
    for(unsigned int i(0); i<_n_coupled_aux; ++i)
    {
      random_number = _mrand.rand(elem_id);

      //test for nucleation
      if (((*_coupled_probability[i])[0] > 0) && (random_number < (*_coupled_probability[i])[0]))
      {
        // get the centroid of the element as the center of the nucleus
        Point nucleus_center = _current_elem->centroid();

        Nucleus current_nucleus;
        current_nucleus.setLocation(nucleus_center);
        current_nucleus.setStartTime(_t);
        current_nucleus.setEndTime(_t+_dwell_time);

        // if(_n_coupled_aux != _num_orientations)
        // {
        //  _mrand.seed(_phase_gen_index, elem_id + _random_seed + (_counter * _mesh.nElem()));
        //  int r_num = _mrand.randl(_phase_gen_index);

          /**
           * randl supplies some integer random number, we want to be between 1 and n coupled
           * vars, so modulo size()
           */
        //  r_num = r_num%_num_orientations;
        //  current_nucleus.setOrientation(r_num);
        // }
        //else
        //{
          current_nucleus.setOrientation(i);
          //}
          // this runs the tiny chance that there might be 2 or 3 nucleation events on the same element.
        _local_nucleus.push_back(current_nucleus);

      }
    }
  }
}
	void findGoodCorners2(const Mat &grayFrame, const SoccerPitchData &data, Mat &currToKeyTrans, Mat &keyToTopTrans) {
		Mat topToCurrTrans;
		invert(keyToTopTrans * currToKeyTrans, topToCurrTrans);
		vector<Point2f> imagePitchOuterContour;
		perspectiveTransform(data.pitchOuterPoints, imagePitchOuterContour, topToCurrTrans);

		vector<Point2f> hull;
		convexHull(imagePitchOuterContour, hull);

		Mat mask = Mat::zeros(frameSize, CV_8UC1);
		fillConvexPoly(mask, vector<Point>(hull.begin(), hull.end()), Scalar(1, 0, 0));

		dilate(mask, mask, getStructuringElement(MORPH_ELLIPSE, Size(3, 3)));

		Mat bin;
		adaptiveThreshold(grayFrame, bin, 255, ADAPTIVE_THRESH_MEAN_C , THRESH_BINARY, 5, -10);
		
		vector<Point2f> candidateCorners;
		goodFeaturesToTrack(bin, candidateCorners, 100, 0.01, 24, mask);

		cornerSubPix(bin, candidateCorners, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS & CV_TERMCRIT_ITER, 40, 0.001));

		vector<Point2f> goodPoints;
		for (Point2f corner : candidateCorners) {
			if (goodCornerCheck(corner, bin) && !closeToBoundary(corner))
				goodPoints.push_back(corner);
		}

		if (goodPoints.size() > 0) {
			vector<Point2f> reprojGoodPoints;
			perspectiveTransform(goodPoints, reprojGoodPoints, keyToTopTrans * currToKeyTrans);
			// try to add these new corners into the relocatedCorners
			for (int i = 0; i < reprojGoodPoints.size(); i++) {
				// if does not exists already and coincide with reproj of 28 points
				bool exists = hasSimilarPoint(relocatedPitchPoints, reprojGoodPoints[i], 10) ;
				int minId = findClosestPoint(data.pitchPoints, reprojGoodPoints[i]);
				double minDist = norm(reprojGoodPoints[i] - data.pitchPoints[minId]);
				if ((!exists ) && (minDist < 16) && (minDist < reprojErr[minId])) {
					relocatedCorners.push_back(goodPoints[i]);
					relocatedPitchPoints.push_back(data.pitchPoints[minId]);
					reprojErr[minId] = minDist;
				}
			}
		}

		cout<<relocatedCorners.size()<<" points relocated"<<endl;
	}
	void removeOutsiders(const SoccerPitchData &data, vector<Point2f> &trackedPitchPoints, vector<Point2f> &pitchPoints) {
		pitchPoints = data.pitchPoints;
		auto it1 = trackedPitchPoints.begin();
		auto it2 = pitchPoints.begin();
		while (it1 != trackedPitchPoints.end()) {
			if ((*it1).x < 0 || (*it1).x >= frameSize.width || (*it1).y < 0 || (*it1).y >= frameSize.height || closeToBoundary(*it1)) {
				it1 = trackedPitchPoints.erase(it1);
				it2 = pitchPoints.erase(it2);
			}
			else {
				it1++;
				it2++;
			}
		}
	}