float MPU6050::dmpGetFirstYPRData()
{
    long long time = timeCheck();


    if(dmpReady && time > 0)
    {

        // get current FIFO count
        dmpFifoCount = getFIFOCount();

        if (dmpFifoCount == 1024) {
            // reset so we can continue cleanly
            resetFIFO();
            timeReset();

        // otherwise, check for DMP data ready interrupt (this should happen frequently)
        } else if (dmpFifoCount >= 42) {
            timeCount(time);

            // read a packet from FIFO
            getFIFOBytes(dmpFifoBuffer, dmpPacketSize);

            // display quaternion values in easy matrix form: w x y z
            dmpGetQuaternion(&dmpQuat, dmpFifoBuffer);
//            if(dmpDebug) printf("quat %7.2f %7.2f %7.2f %7.2f    ", dmpQuat.w,dmpQuat.x,dmpQuat.y,dmpQuat.z);

            #ifdef OUTPUT_READABLE_EULER
                // display Euler angles in degrees
                dmpGetEuler(dmpEuler, &dmpQuat);
                dmpEuler[0] = dmpEuler[0] * 180/M_PI;
                dmpEuler[1] = dmpEuler[1] * 180/M_PI;
                dmpEuler[2] = dmpEuler[2] * 180/M_PI;
//                if(dmpDebug) printf("euler %7.2f %7.2f %7.2f    ", dmpEuler[0], dmpEuler[1], dmpEuler[2]);
            #endif

            #ifdef OUTPUT_READABLE_YAWPITCHROLL
                // display Euler angles in degrees
                dmpGetGravity(&dmpGravity, &dmpQuat);
                dmpGetYawPitchRoll(dmpYawPitchRoll, &dmpQuat, &dmpGravity);
                dmpYawPitchRoll[0] = dmpYawPitchRoll[0] * 180/M_PI;
                dmpYawPitchRoll[1] = dmpYawPitchRoll[1] * 180/M_PI;
                dmpYawPitchRoll[2] = dmpYawPitchRoll[2] * 180/M_PI;
//                if(dmpDebug) printf("ypr  %7.2f %7.2f %7.2f    ", dmpYawPitchRoll[0], dmpYawPitchRoll[1], dmpYawPitchRoll[2]);
                if(dmpDebug)
                   return dmpYawPitchRoll[0];
            #endif

            #ifdef OUTPUT_READABLE_REALACCEL
                // display real acceleration, adjusted to remove gravity
                dmpGetAccel(&dmpAccel, dmpFifoBuffer);
                dmpGetGravity(&dmpGravity, &dmpQuat);
                dmpGetLinearAccel(&dmpAccelReal, &dmpAccel, &dmpGravity);
//                if(dmpDebug) printf("areal %6d %6d %6d    ", dmpAccelReal.x, dmpAccelReal.y, dmpAccelReal.z);
            #endif

            #ifdef OUTPUT_READABLE_WORLDACCEL
                // display initial world-frame acceleration, adjusted to remove gravity
                // and rotated based on known orientation from quaternion
                dmpGetAccel(&dmpAccel, dmpFifoBuffer);
                dmpGetGravity(&dmpGravity, &dmpQuat);
                dmpGetLinearAccelInWorld(&dmpAccelWorld, &dmpAccelReal, &dmpQuat);
//                if(dmpDebug) printf("aworld %6d %6d %6d    ", dmpAccelWorld.x, dmpAccelWorld.y, dmpAccelWorld.z);
            #endif

            #ifdef OUTPUT_TEAPOT
                // display quaternion values in InvenSense Teapot demo format:
                dmpTeapotPacket[2] = dmpFifoBuffer[0];
                dmpTeapotPacket[3] = dmpFifoBuffer[1];
                dmpTeapotPacket[4] = dmpFifoBuffer[4];
                dmpTeapotPacket[5] = dmpFifoBuffer[5];
                dmpTeapotPacket[6] = dmpFifoBuffer[8];
                dmpTeapotPacket[7] = dmpFifoBuffer[9];
                dmpTeapotPacket[8] = dmpFifoBuffer[12];
                dmpTeapotPacket[9] = dmpFifoBuffer[13];
                //Serial.write(dmpTeapotPacket, 14);
                dmpTeapotPacket[11]++; // packetCount, loops at 0xFF on purpose
            #endif

            return -255;
        }
    }

    return -255;
}
Esempio n. 2
0
bool BkgdObsSplineLoader::loadBkgdObs(QList<real> &bgIn)
{
  // Turn Debug on if there are problems with the vertical spline interpolation,
  // Eventually this should be replaced with the internal spline code
  // SplineD::Debug(1);

  // Geographic functions
  // GeographicLib::TransverseMercatorExact tm = GeographicLib::TransverseMercatorExact::UTM();

  real referenceLon = configHash->value("ref_lon").toFloat();

  int time;
  real lat, lon, alt, u, v, w, t, qv, rhoa, qr;
  
  real Pi = acos(-1);

  bool debugDomain = isTrue("debug_domain");
  
  // bgZ = -32768.;  TODO. What was that about?
  
  // background is in km, ROI is gridpoints
  
  iROI = configHash->value("i_background_roi").toFloat() / iincr;
  jROI = configHash->value("j_background_roi").toFloat() / jincr;
  maxGridDist = 3.0;
  
  QString interp_mode = configHash->value("bg_interpolation");
  if (interp_mode == "Cressman")
    maxGridDist = 1.0;

  if (frameVector.size() == 0) {
    std::cout << "Frame Vector is not initialized."  << std::endl;
    return false;
  }
    
  std::cout << "Loading background onto Gaussian mish with " << iROI
	    << " grid length radius of influence in i direction" << std::endl;
  std::cout << "and " << jROI << " grid length radius of influence in j direction" << std::endl;

  QDateTime startTime = frameVector.front().getTime();
  QDateTime endTime = frameVector.back().getTime();
  
  std::cout << "Start time: " << startTime.toTime_t() << " "
	    << startTime.toString("yyyy-MM-dd-HH:mm:ss").toLatin1().data() << std::endl;
  std::cout << "End  time:  " << endTime.toTime_t()  << " "
	    << endTime.toString("yyyy-MM-dd-HH:mm:ss").toLatin1().data() << std::endl;

  int timeProblem = 0;
  int domainProblem = 0;
  int radiusProblem = 0;
  int levelProblem = 0;
  int splineProblem = 0;

  std::cout << "iROI: " << iROI << ", jROI: " << jROI << ", maxGridDist: "
	    << maxGridDist << std::endl;
  std::cout << "imin: " << imin << ", iincr: " << iincr << std::endl;
  std::cout << "jmin: " << jmin << ", jincr: " << jincr << std::endl;
  std::cout << "kmin: " << kmin << ", kincr: " << kincr << std::endl;
  
  while( bkgdAdapter->next(time, lat, lon, alt, u, v, w, t, qv, rhoa, qr) ) {
    int tci;
    if (! timeCheck(time, startTime, endTime, tci)) {
      timeProblem++;
      continue;
    }
      
    real Um = frameVector[tci].getUmean();
    real Vm = frameVector[tci].getVmean();

    // Get the X, Y & Z
    real tcX, tcY, metX, metY;
    projection.Forward(referenceLon, frameVector[tci].getLat() , frameVector[tci].getLon(),
		       tcX, tcY);
    projection.Forward(referenceLon, lat, lon , metX, metY);
    bgX = (metX - tcX) / 1000.;
    bgY = (metY - tcY) / 1000.;

    real heightm = (alt > 10.0) ? alt : 10;	// don't want to take log of zero below...
    
    bgZ = heightm / 1000.;
    bgRadius = sqrt(bgX * bgX + bgY * bgY);
    bgTheta = 180.0 * atan2(bgY, bgX) / Pi;
    if (configHash->value("allow_negative_angles") != "true")
      if (bgTheta < 0)
	bgTheta += 360.0;

    // Make sure the ob is in the Interpolation domain
    
    if (runMode == RUN_MODE_XYZ) {
      if ((bgX < (imin - iincr - (iROI * iincr * maxGridDist))) or
	  (bgX > (imax + iincr + (iROI * iincr * maxGridDist))) or
	  (bgY < (jmin - jincr - (jROI * jincr * maxGridDist))) or
	  (bgY > (jmax + jincr + (jROI * jincr * maxGridDist))) or
	  (bgZ < kmin)) { //Allow for higher values for interpolation purposes
	domainProblem++;
	if (debugDomain)
	  std::cout << "bgX: " << bgX << " bgY: " << bgY << " bgZ: " << bgZ << std::endl;
	continue;
      }
    } else if (runMode == RUN_MODE_RTZ) {
      if ((bgRadius < (imin - iincr - (iROI * iincr * maxGridDist))) or
	  (bgRadius > (imax + iincr + (iROI * iincr * maxGridDist))) or
	  (bgTheta < jmin - jincr - (jROI * jincr * maxGridDist)) or
	  (bgTheta > jmax + jincr + (jROI * jincr * maxGridDist)) or
	  (bgZ < kmin)) { //Exceeding the Theta domain only makes sense for sectors
	domainProblem++;
	continue;
      }
      real cylUm = (Um * bgX + Vm * bgY) / bgRadius;
      real cylVm = (-Um * bgY + Vm * bgX) / bgRadius;
      Um = cylUm;
      Vm = cylVm;
    }

    // Reference states
    real rhoBar = refstate->getReferenceVariable(ReferenceVariable::rhoaref, heightm);
    real qBar = refstate->getReferenceVariable(ReferenceVariable::qvbhypref, heightm);
    real tBar = refstate->getReferenceVariable(ReferenceVariable::tempref, heightm);

    real rho = rhoa + rhoa * qv / 1000.;
    real rhou = rho * (u - Um);
    real rhov = rho * (v - Vm);
    real rhow = rho * w;
    real tprime = t - tBar;
    qv = refstate->bhypTransform(qv);
    real qvprime = qv - qBar;
    real rhoprime = (rhoa - rhoBar) * 100;
    real logZ = log(bgZ);
    
    if (configHash->value("qr_variable") == "qr")
      qr = refstate->bhypTransform(qr);
    
    // We assume here that the background precipitation field is always zero
    // real qr = 0.;

    if (runMode == RUN_MODE_XYZ) {
      bgIn << bgX << bgY << logZ << time << rhou << rhov << rhow << tprime << qvprime << rhoprime << qr ;
    } else if (runMode == RUN_MODE_RTZ)
      bgIn << bgRadius << bgTheta << logZ << time << rhou << rhov << rhow << tprime
	   << qvprime << rhoprime << qr ;

    // Push values for an entire column, then solve for the spline
    
    if ( (logheights.size() != 0) && (logZ <= logheights.back()) ) {
      // Not first level, not same column, Solve for the spline
      if (logheights.size() == 1) {
	std::cerr << "Error at " << lat << ", " << lon << ", " << bgZ << std::endl
		  << "Only one level found in background spline setup. " << std::endl
		  << "Please check Background.in to ensure sorting by descending Z coordinate and re-run."
		  << std::endl;
	levelProblem++;
	return false;
      }
      splineSolver(0);	// This will also clear logheights, uBG, vBG, ...
    }
    
    logheights.push_back(logZ);
    uBG.push_back(rhou);
    vBG.push_back(rhov);
    wBG.push_back(rhow);
    tBG.push_back(tprime);
    qBG.push_back(qvprime);
    rBG.push_back(rhoprime);
    zBG.push_back(qr);
    
  } // each obs

  std::cout << "timeProblem: " << timeProblem << ", domainProblem: " << domainProblem
       << ", radiusProblem: " << radiusProblem << ", levelProblem: " << levelProblem
       << ", splineProblem: " << splineProblem
       << std::endl;

  if (!logheights.size()) {
    // Error reading in the background field
    std::cout << "No background estimates read in. "
	 << "Please check the time and location of your background field.\n";
#if 0
    std::cout << "Observation window: " << tcstart.toStdString() << " to " << tcend.toStdString() << "\n";
    std::cout << "Background time: " << bgTimestring.toStdString() << "\n";
#endif
    return false;
  }

  // std::cout << "------------------------2\n";
  
  // Solve for the last spline
  if (logheights.size() == 1) {
    std::cerr << "Only one level found in background spline setup. "
	 << "Please check Background.in to ensure sorting by Z coordinate and re-run." << std::endl;
    return false;
  }

  // Exponential interpolation in horizontal, b-Spline interpolation on log height in vertical

  splineSolver(2);  // This will also clear logheights, uBG, vBG, ...

  int numbgObs = bgIn.size() / 11; // 11 entries per ob
  if (isTrue("debug_bgIn"))
    dumpBgIn(0, numbgObs, bgIn);
      
  QVector<int> emptybg;

  // TODO Do we need to check interpolation and fill hole for KD too?
  // bgWeight is a byproduct of calling the spline solver, so that's not available.
  // what about fill holes? It depends on emptyBg which is also a byproduct of the spline solver.
  
  // Check interpolation
  
  if (numbgObs > 0) {
    
    START_TIMER(timeci);

    for (int ki = -1; ki < (kdim); ki++) {
      for (int kmu = -1; kmu <= 1; kmu += 2) {
	real kPos = kmin + kincr * (ki + (0.5 * sqrt(1. / 3.) * kmu + 0.5));
	
	for (int ii = -1; ii < (idim); ii++) {
	  for (int imu = -1; imu <= 1; imu += 2) {
	    real iPos = imin + iincr * (ii + (0.5 * sqrt(1. / 3.) * imu + 0.5));
	    
	    for (int ji = -1; ji < (jdim); ji++) {
	      for (int jmu = -1; jmu <= 1; jmu += 2) {
		real jPos = jmin + jincr * (ji + (0.5 * sqrt(1. / 3.) * jmu + 0.5));
		
		int bgI = (ii + 1) * 2 + (imu + 1) / 2;
		int bgJ = (ji + 1) * 2 + (jmu + 1) / 2;
		int bgK = (ki + 1) * 2 + (kmu + 1) / 2;
		
		int bIndex = numVars * (idim + 1) * 2 * (jdim + 1) * 2 * bgK
		  + numVars * (idim + 1) * 2 * bgJ + numVars * bgI;

		for (unsigned int var = 0; var < numVars; var++) {
		  if (bgWeights[bIndex] != 0) {
		    bgU[bIndex + var] /= bgWeights[bIndex];
		  } else {
		    emptybg.push_back(bIndex);
		    if (emptybg.size() < 15) {
		      std::cout << "Empty background mish for variable "
				<< var << " at " << iPos << ", " << jPos << ", " << kPos << std::endl;
		    } else if (emptybg.size() == 15) {
		      std::cout << "Too many empty mish points, will no longer report.\n";
		    }
		  }
		}
		if (configHash->value("qr_variable") == "dbz") {
		  if (bgU[bIndex + 6] > 0) {
		    real dbzavg = 10 * log10(bgU[bIndex + 6]);
		    bgU[bIndex + 6] = (dbzavg + 35.) * 0.1;
		  } else {
		    bgU[bIndex + 6] = 0.0;
		  }
		}
	      }
	    }
	  }
	}
      }
    }

    fillHoles(emptybg);
    
    PRINT_TIMER("Interpolation check", timeci);
  } else {
    std::cout << "No background observations loaded" << std::endl;
    return false;
  }

  std::cout << numbgObs << " background observations loaded" << std::endl;

  if (isTrue("debug_bgU")) {
    dumpBgU(0, uStateSize, bgU);
  }

  if (configHash->contains("debug_bgU_nc"))
    bgu2nc(configHash->value("debug_bgU_nc").toLatin1().data(), bgU);
  
  return true;
}
Esempio n. 3
0
bool BkgdObsKDLoader::loadBkgdObs(QList<real> &bgIn)
{
  int time;
  real lat, lon, alt, u, v, w, t, qv, rhoa, qr;
  real Pi = acos(-1);

  KD_tree *kdTree;

  QDateTime startTime = frameVector.front().getTime();
  QDateTime endTime = frameVector.back().getTime();

  std::cout << "Start time: " << startTime.toTime_t() << " "
	    << startTime.toString("yyyy-MM-dd-HH:mm:ss").toLatin1().data() << std::endl;
  std::cout << "End  time:  " << endTime.toTime_t()  << " "
	    << endTime.toString("yyyy-MM-dd-HH:mm:ss").toLatin1().data() << std::endl;
  
  // background is in km, ROI is gridpoints
  // TODO that comment doesn't seem correct. These are set to 45.0 in the config file...
  
  iROI = configHash->value("i_background_roi").toFloat() / iincr;
  jROI = configHash->value("j_background_roi").toFloat() / jincr;

  maxGridDist = 3.0;
  
  int timeProblem = 0;
  int domainProblem = 0;

  int debugKd = 0;
  if (configHash->contains("debug_kd") ) {
    debugKd = configHash->value("debug_kd").toInt();
    std::cout << "*** dbugKD: " << debugKd << std::endl;    
  }

  int debugKdStep = 0;
  if (configHash->contains("debug_kd_step") ) {
    debugKdStep = configHash->value("debug_kd_step").toInt();
    std::cout << "*** Debug KD Step: " << debugKdStep << std::endl;
  }
  
  while( bkgdAdapter->next(time, lat, lon, alt, u, v, w, t, qv, rhoa, qr) ) {
    // Process the bkgdObs into Observations
    int tci;
    if (! timeCheck(time, startTime, endTime, tci)) {
      timeProblem++;
      continue;
    }
      
    real Um = frameVector[tci].getUmean();
    real Vm = frameVector[tci].getVmean();

    // Get the X, Y & Z
    real tcX, tcY, metX, metY;
    real referenceLon = configHash->value("ref_lon").toFloat();
    
    projection.Forward(referenceLon, frameVector[tci].getLat() , frameVector[tci].getLon(),
		       tcX, tcY);
    projection.Forward(referenceLon, lat, lon , metX, metY);
    bgX = (metX - tcX) / 1000.;
    bgY = (metY - tcY) / 1000.;

    real heightm = (alt > 10.0) ? alt : 10;	// don't want to take log of zero below...
    
    bgZ = heightm / 1000.;
    bgRadius = sqrt(bgX * bgX + bgY * bgY);
    bgTheta = 180.0 * atan2(bgY, bgX) / Pi;
    if (configHash->value("allow_negative_angles") != "true")
      if (bgTheta < 0)
	bgTheta += 360.0;

    // Make sure the ob is in the Interpolation domain
    
    if (runMode == RUN_MODE_XYZ) {
      if ((bgX < (imin - iincr - (iROI * iincr * maxGridDist))) or
	  (bgX > (imax + iincr + (iROI * iincr * maxGridDist))) or
	  (bgY < (jmin - jincr - (jROI * jincr * maxGridDist))) or
	  (bgY > (jmax + jincr + (jROI * jincr * maxGridDist))) or
	  (bgZ < kmin)) { //Allow for higher values for interpolation purposes
	domainProblem++;
	continue;
      }
    } else if (runMode == RUN_MODE_RTZ) {
      if ((bgRadius < (imin - iincr - (iROI * iincr * maxGridDist))) or
	  (bgRadius > (imax + iincr + (iROI * iincr * maxGridDist))) or
	  (bgTheta < jmin - jincr - (jROI * jincr * maxGridDist)) or
	  (bgTheta > jmax + jincr + (jROI * jincr * maxGridDist)) or
	  (bgZ < kmin)) { //Exceeding the Theta domain only makes sense for sectors
	domainProblem++;
	continue;
      }
      real cylUm = (Um * bgX + Vm * bgY) / bgRadius;
      real cylVm = (-Um * bgY + Vm * bgX) / bgRadius;
      Um = cylUm;
      Vm = cylVm;
    }

    // Reference states
    real rhoBar = refstate->getReferenceVariable(ReferenceVariable::rhoaref, heightm);
    real qBar = refstate->getReferenceVariable(ReferenceVariable::qvbhypref, heightm);
    real tBar = refstate->getReferenceVariable(ReferenceVariable::tempref, heightm);

    real rho = rhoa + rhoa * qv / 1000.;
    real rhou = rho * (u - Um);
    real rhov = rho * (v - Vm);
    real rhow = rho * w;
    real tprime = t - tBar;
    qv = refstate->bhypTransform(qv);
    real qvprime = qv - qBar;
    real rhoprime = (rhoa - rhoBar) * 100;
    real logZ = log(bgZ);

    if (configHash->value("qr_variable") == "qr")
      qr = refstate->bhypTransform(qr);
    
    // We assume here that the background precipitation field is always zero
    // real qr = 0.;

    if (runMode == RUN_MODE_XYZ) {
      bgIn << bgX << bgY << logZ << time << rhou << rhov << rhow << tprime << qvprime << rhoprime << qr ;
    } else if (runMode == RUN_MODE_RTZ)
      bgIn << bgRadius << bgTheta << logZ << time << rhou << rhov << rhow << tprime
	   << qvprime << rhoprime << qr;

  } // each obs

  std::cout << "timeProblem: " << timeProblem << ", domainProblem: " << domainProblem
            << std::endl;
  
  int numbgObs = bgIn.size() / 11; // 11 entries per ob
  
  if (numbgObs <= 0) {
    std::cout << "No background observations loaded" << std::endl;
    return false;
  }
  
  std::cout << numbgObs << " background observations loaded" << std::endl;
  
  if (isTrue("debug_bgIn"))
    dumpBgIn(0, numbgObs, bgIn);

  // All the obs are now loaded in bgIn. Build a KD tree
  
  kdTree = buildKDTree(bgIn);
  QVector<int> emptybg;
  
  KD_real *centerLoc = new KD_real[3];	// 3 dim
  int nbrMax  = configHash->value("bkgd_kd_num_neighbors").toInt();
  if (nbrMax <= 0) {
    std::cerr << "Number of neighbors must be greater than 0." << std::endl;
    return false;
  }
  float maxDist = configHash->value("bkgd_kd_max_distance").toFloat();
  // KD tree returns the square of the distance...
  maxDist *= maxDist;

  // For each point on the mish

  std::cout << "*** idim: " << idim << ", jdim: " << jdim << ", kdim: " << kdim << std::endl;
  
  if (debugKd)
    std::cout << "--- start of debug kd" << std::endl;
  
  for (int ii = -1; ii < (idim); ii++) {
    for (int imu = -1; imu <= 1; imu += 2) {
      real iPos = imin + iincr * (ii + (0.5 * sqrt(1. / 3.) * imu + 0.5));
	    
      for (int ji = -1; ji < (jdim); ji++) {
	for (int jmu = -1; jmu <= 1; jmu += 2) {
	  real jPos = jmin + jincr * (ji + (0.5 * sqrt(1. / 3.) * jmu + 0.5));
		
	  for (int ki = -1; ki < (kdim); ki++) {
	    for (int kmu = -1; kmu <= 1; kmu += 2) {
	      real kPos = kmin + kincr * (ki + (0.5 * sqrt(1. / 3.) * kmu + 0.5));
	
	      int bgI = (ii + 1) * 2 + (imu + 1) / 2;
	      int bgJ = (ji + 1) * 2 + (jmu + 1) / 2;
	      int bgK = (ki + 1) * 2 + (kmu + 1) / 2;

	      // std::cout << "iPos: " << iPos << ", jPos: " << jPos << ", kPos: " << kPos << std::endl;
	      // std::cout << "bgI: " << bgI << ", bgJ: " << bgJ << ", bgK " << bgK << std::endl;
	      // continue;
	      
	      // index into bgU (flat array)
	      int bIndex = numVars * (idim + 1) * 2 * (jdim + 1) * 2 * bgK
		+ numVars * (idim + 1) * 2 * bgJ + numVars * bgI;

	      // Do the KD tree here.
	      // give me the n nearest neighbors and average.

	      centerLoc[0] = iPos;
	      centerLoc[1] = jPos;
	      centerLoc[2] = kPos;

	      fillBguEntry(centerLoc, nbrMax, maxDist, bgIn, kdTree, bgU, bIndex, emptybg, debugKd);
	      if (debugKd > 0)
		debugKd -= debugKdStep;
	    }
	  }
	}
      }
    }
  }

  if (emptybg.size() > 0)
    std::cout << "** KD left " << emptybg.size() << " holes in bgU" << std::endl;
  
  if (debugKd)
    std::cout << "--- end of debug kd" << std::endl;

  if (configHash->contains("debug_bgU_overwrite"))
    overwriteBgu(configHash->value("debug_bgU_overwrite").toLatin1().data());
  
  if (isTrue("debug_bgU")) {
    dumpBgU(0, uStateSize, bgU);
  }
  
  if (configHash->contains("debug_bgU_nc"))
    bgu2nc(configHash->value("debug_bgU_nc").toLatin1().data(), bgU);
  
  return true;
}
bool Foam::conformalVoronoiMesh::distributeBackground(const Triangulation& mesh)
{
    if (!Pstream::parRun())
    {
        return false;
    }

    Info<< nl << "Redistributing points" << endl;

    timeCheck("Before distribute");

    label iteration = 0;

    scalar previousLoadUnbalance = 0;

    while (true)
    {
        scalar maxLoadUnbalance = mesh.calculateLoadUnbalance();

        if
        (
            maxLoadUnbalance <= foamyHexMeshControls().maxLoadUnbalance()
         || maxLoadUnbalance <= previousLoadUnbalance
        )
        {
            // If this is the first iteration, return false, if it was a
            // subsequent one, return true;
            return iteration != 0;
        }

        previousLoadUnbalance = maxLoadUnbalance;

        Info<< "    Total number of vertices before redistribution "
            << returnReduce(label(mesh.number_of_vertices()), sumOp<label>())
            << endl;

        const fvMesh& bMesh = decomposition_().mesh();

        volScalarField cellWeights
        (
            IOobject
            (
                "cellWeights",
                bMesh.time().timeName(),
                bMesh,
                IOobject::NO_READ,
                IOobject::NO_WRITE
            ),
            bMesh,
            dimensionedScalar("weight", dimless, 1e-2),
            zeroGradientFvPatchScalarField::typeName
        );

        meshSearch cellSearch(bMesh, polyMesh::FACE_PLANES);

        labelList cellVertices(bMesh.nCells(), label(0));

        for
        (
            typename Triangulation::Finite_vertices_iterator vit
                = mesh.finite_vertices_begin();
            vit != mesh.finite_vertices_end();
            ++vit
        )
        {
            // Only store real vertices that are not feature vertices
            if (vit->real() && !vit->featurePoint())
            {
                pointFromPoint v = topoint(vit->point());

                label cellI = cellSearch.findCell(v);

                if (cellI == -1)
                {
//                     Pout<< "findCell conformalVoronoiMesh::distribute "
//                         << "findCell "
//                         << vit->type() << " "
//                         << vit->index() << " "
//                         << v << " "
//                         << cellI
//                         << " find nearest cellI ";

                    cellI = cellSearch.findNearestCell(v);
                }

                cellVertices[cellI]++;
            }
        }

        forAll(cellVertices, cI)
        {
            // Give a small but finite weight for empty cells.  Some
            // decomposition methods have difficulty with integer overflows in
            // the sum of the normalised weight field.
            cellWeights.internalField()[cI] = max
            (
                cellVertices[cI],
                1e-2
            );
        }

        autoPtr<mapDistributePolyMesh> mapDist = decomposition_().distribute
        (
            cellWeights
        );

        cellShapeControl_.shapeControlMesh().distribute(decomposition_);

        distribute();

        timeCheck("After distribute");

        iteration++;
    }