// See http://en.wikipedia.org/wiki/Structure_factor, cf. (4) or (5).
    void DistanceService::FillStructureFactor(StructureFactor* structureFactor) const
    {
        // I'm using the equation from "Perfect Crystals" section, as it is faster, though may have worse precision (as doesn't use all the info from the particles).
        // It is also used in Jiao and Torquato (2011) Maximally random jammed packings of platonic solids, cf. 3.
        // For this code also Xu and Ching (2010) Effects of particle-size ratio on jamming of binary mixtures at zero temperature
        // "Due to the periodic boundary conditions, the wave vector must be chosen as..."
        structureFactor->waveVectorLengths.clear();
        structureFactor->structureFactorValues.clear();

        vector<StructureFactorPair> result;

        const int acceptableVectorsCount = 70000; // determined empirically
        const int maxDiscreteCoordinate = 12;
        const int currentVectorsCount = (2 * maxDiscreteCoordinate + 1) * (2 * maxDiscreteCoordinate + 1) * (2 * maxDiscreteCoordinate + 1);
        const FLOAT_TYPE vectorAcceptanceProbability = static_cast<FLOAT_TYPE>(acceptableVectorsCount) / currentVectorsCount;
        for (int i = -maxDiscreteCoordinate; i <= maxDiscreteCoordinate; ++i)
        {
            for (int j = -maxDiscreteCoordinate; j <= maxDiscreteCoordinate; ++j)
            {
                for (int k = -maxDiscreteCoordinate; k <= maxDiscreteCoordinate; ++k)
                {
                    if (i == 0 && j == 0 && k == 0)
                    {
                        continue;
                    }

                    SpatialVector waveVector;
                    waveVector[Axis::X] = i * 2.0 * PI / config->packingSize[Axis::X];
                    waveVector[Axis::Y] = j * 2.0 * PI / config->packingSize[Axis::Y];
                    waveVector[Axis::Z] = k * 2.0 * PI / config->packingSize[Axis::Z];

                    FLOAT_TYPE waveVectorLength = VectorUtilities::GetLength(waveVector);

                    // Usually the first maximum of structure factor is around 2 * PI
                    if (waveVectorLength > 2.0 * PI)
                    {
                        FLOAT_TYPE randomVariable = Math::GetNextRandom();
                        if (randomVariable > vectorAcceptanceProbability)
                        {
                            continue;
                        }
                    }

                    complex<FLOAT_TYPE> complexSum(0.0, 0.0);
                    complex<FLOAT_TYPE> imaginaryUnit(0.0, 1.0);
                    for (ParticleIndex particleIndex = 0; particleIndex < config->particlesCount; ++particleIndex)
                    {
                        const Packing& particlesRef = *particles;
                        FLOAT_TYPE dotProduct = VectorUtilities::GetDotProduct(waveVector, particlesRef[particleIndex].coordinates);
                        complexSum += exp(imaginaryUnit * dotProduct);
                    }

                    StructureFactorPair pair;
                    pair.waveVectorLength = waveVectorLength;
                    pair.structureFactorValue = norm(complexSum) / config->particlesCount;
                    result.push_back(pair);
                }
            }
        }

        StlUtilities::Sort(&result);

        for (vector<StructureFactorPair>::const_iterator it = result.begin(); it != result.end(); ++it)
        {
            StructureFactorPair pair = *it;

            structureFactor->waveVectorLengths.push_back(pair.waveVectorLength);
            structureFactor->structureFactorValues.push_back(pair.structureFactorValue);
        }
    }
Пример #2
0
int computeMoments(int startGate,
                   int endGate,
                   Beam *beam)

{
  
  /* initialize summation quantities */
  
  int igate;
  double sumPowerH = 0.0;
  double sumPowerV = 0.0;
  double nn = 0.0;
  Complex_t sumRvh0;
  sumRvh0.re = 0.0;
  sumRvh0.im = 0.0;

  /* loop through gates to be used for sun computations */
  
  for (igate = startGate; igate <= endGate; igate++, nn++) {
    
    /* get the I/Q data time series for the gate */
    /* the getGateIq() functions must be provided externally. */
    
    const Complex_t *iqh = getGateIqH(igate);
    const Complex_t *iqv = getGateIqV(igate);

    /* compute lag 0 covariance = power */
    
    double lag0_h = meanPower(iqh, nSamples - 1);
    double lag0_v = meanPower(iqv, nSamples - 1);
    
    /* check power for interference */

    double dbmH = 10.0 * log10(lag0_h);
    double dbmV = 10.0 * log10(lag0_v);

    if (dbmH > maxValidDrxPowerDbm) {
      /* don't use this gate - probably interference */
      continue;
    }
    
    /* compute lag0 conjugate product, for correlation */

    Complex_t lag0_hv =
      meanConjugateProduct(iqh, iqv, nSamples - 1);
    
    /* sum up */

    sumPowerH += lag0_h;
    sumPowerV += lag0_v;
    sumRvh0 = complexSum(&sumRvh0, &lag0_hv);
    
  } /* igate */

  /* sanity check */

  if (nn < 3) {
    fprintf(stderr, "Warning - computeMoments\n");
    fprintf(stderr, "  Insufficient good data found\n");
    fprintf(stderr, "  az, el: %lg, %lg\n", beam->az, beam->el);
    fprintf(stderr, "  nn: %d\n", nn);
    return -1;
  }
  
  /* compute mean moments */

  beam->powerH = sumPowerH / nn;
  beam->powerV = sumPowerV / nn;
   
  beam->dbmH = 10.0 * log10(beam->powerH);
  beam->dbmV = 10.0 * log10(beam->powerV);
  beam->dbm = (beam->dbmH + beam->dbmV)/2.0;
  beam->zdr = beam->dbmH - beam->dbmV;
  beam->SS = 1.0 / (2.0 * beam->zdr);
 
  double corrMag = mag(&sumRvh0) / nn;
  beam->corrHV = corrMag / sqrt(beam->powerH * beam->powerV);
  beam->phaseHV = argDeg(&sumRvh0);

  /* compute sun angle offset */
  
  double sunEl, sunAz;
  computePosnNova(beam->time, &sunEl, &sunAz);
  double cosel = cos(beam->el * DEG_TO_RAD);
  beam->azOffset = computeAngleDiff(beam->az, sunAz) * cosel;
  beam->elOffset = computeAngleDiff(beam->el, sunEl);
    
  return 0;

}