Exemple #1
0
/**
 * Normalized the intensities of the given integrated peaks
 *
 * This function normalizes the peak intensities according to the source
 * spectrum, the number of chopper slits and the number of detector elements.
 *
 * @param peakCollection :: PoldiPeakCollection with integrated intensities
 * @return PoldiPeakCollection with normalized intensities
 */
PoldiPeakCollection_sptr PoldiFitPeaks2D::getNormalizedPeakCollection(
    const PoldiPeakCollection_sptr &peakCollection) const {
  if (!peakCollection) {
    throw std::invalid_argument(
        "Cannot proceed with invalid PoldiPeakCollection.");
  }

  if (!m_timeTransformer) {
    throw std::invalid_argument("Cannot proceed without PoldiTimeTransformer.");
  }

  PoldiPeakCollection_sptr normalizedPeakCollection =
      boost::make_shared<PoldiPeakCollection>(PoldiPeakCollection::Integral);
  normalizedPeakCollection->setProfileFunctionName(
      peakCollection->getProfileFunctionName());

  // Carry over unit cell and point group
  assignCrystalData(normalizedPeakCollection, peakCollection);

  for (size_t i = 0; i < peakCollection->peakCount(); ++i) {
    PoldiPeak_sptr peak = peakCollection->peak(i);
    double calculatedIntensity =
        m_timeTransformer->calculatedTotalIntensity(peak->d());

    PoldiPeak_sptr normalizedPeak = peak->clone();
    normalizedPeak->setIntensity(peak->intensity() / calculatedIntensity);
    normalizedPeakCollection->addPeak(normalizedPeak);
  }

  return normalizedPeakCollection;
}
Exemple #2
0
/**
 * Returns a Poldi2DFunction that encapsulates a PawleyFunction
 *
 * This function creates a PawleyFunction using the supplied profile function
 * name and the crystal system as well as initial cell from the input
 * properties of the algorithm and wraps it in a Poldi2DFunction.
 *
 * The cell is refined using LatticeFunction to get better starting values.
 *
 * Because the peak intensities are integral at this step but PawleyFunction
 * expects peak heights, a profile function is created and
 * setIntensity/height-methods are used to convert.
 *
 * @param profileFunctionName :: Profile function name for PawleyFunction.
 * @param peakCollection :: Peak collection with peaks to be used in the fit.
 * @return :: A Poldi2DFunction with a PawleyFunction.
 */
Poldi2DFunction_sptr PoldiFitPeaks2D::getFunctionPawley(
    std::string profileFunctionName,
    const PoldiPeakCollection_sptr &peakCollection) {
  auto mdFunction = boost::make_shared<Poldi2DFunction>();

  boost::shared_ptr<PoldiSpectrumPawleyFunction> poldiPawleyFunction =
      boost::dynamic_pointer_cast<PoldiSpectrumPawleyFunction>(
          FunctionFactory::Instance().createFunction(
              "PoldiSpectrumPawleyFunction"));

  if (!poldiPawleyFunction) {
    throw std::invalid_argument("Could not create pawley function.");
  }

  poldiPawleyFunction->setDecoratedFunction("PawleyFunction");

  IPawleyFunction_sptr pawleyFunction =
      poldiPawleyFunction->getPawleyFunction();
  pawleyFunction->setProfileFunction(profileFunctionName);

  // Extract crystal system from peak collection
  PointGroup_sptr pointGroup = peakCollection->pointGroup();
  if (!pointGroup) {
    throw std::invalid_argument("Can not initialize pawley function properly - "
                                "peaks do not have point group.");
  }

  std::string latticeSystem = getLatticeSystemFromPointGroup(pointGroup);
  pawleyFunction->setLatticeSystem(latticeSystem);

  UnitCell cell = peakCollection->unitCell();
  // Extract unit cell from peak collection
  pawleyFunction->setUnitCell(getRefinedStartingCell(
      unitCellToStr(cell), latticeSystem, peakCollection));

  IPeakFunction_sptr pFun = boost::dynamic_pointer_cast<IPeakFunction>(
      FunctionFactory::Instance().createFunction(profileFunctionName));

  for (size_t i = 0; i < peakCollection->peakCount(); ++i) {
    PoldiPeak_sptr peak = peakCollection->peak(i);

    pFun->setCentre(peak->d());
    pFun->setFwhm(peak->fwhm(PoldiPeak::AbsoluteD));
    pFun->setIntensity(peak->intensity());

    pawleyFunction->addPeak(peak->hkl().asV3D(),
                            peak->fwhm(PoldiPeak::AbsoluteD), pFun->height());
  }

  pawleyFunction->fix(pawleyFunction->parameterIndex("f0.ZeroShift"));
  mdFunction->addFunction(poldiPawleyFunction);

  return mdFunction;
}
Exemple #3
0
/**
 * Return peak collection with integrated peaks
 *
 * This method takes a PoldiPeakCollection where the intensity is represented
 * by the maximum. Then it takes the profile function stored in the peak
 * collection, which must be the name of a registered
 * IPeakFunction-implementation. The parameters height and fwhm are assigned,
 * centre is set to 0 to avoid problems with the parameter transformation for
 * the integration from -inf to inf. The profiles are integrated using
 * a PeakFunctionIntegrator to the precision of 1e-10.
 *
 * The original peak collection is not modified, a new instance is created.
 *
 * @param rawPeakCollection :: PoldiPeakCollection
 * @return PoldiPeakCollection with integrated intensities
 */
PoldiPeakCollection_sptr PoldiFitPeaks2D::getIntegratedPeakCollection(
    const PoldiPeakCollection_sptr &rawPeakCollection) const {
  if (!rawPeakCollection) {
    throw std::invalid_argument(
        "Cannot proceed with invalid PoldiPeakCollection.");
  }

  if (!isValidDeltaT(m_deltaT)) {
    throw std::invalid_argument("Cannot proceed with invalid time bin size.");
  }

  if (!m_timeTransformer) {
    throw std::invalid_argument(
        "Cannot proceed with invalid PoldiTimeTransformer.");
  }

  if (rawPeakCollection->intensityType() == PoldiPeakCollection::Integral) {
    /* Intensities are integral already - don't need to do anything,
     * except cloning the collection, to make behavior consistent, since
     * integrating also results in a new peak collection.
     */
    return rawPeakCollection->clone();
  }

  /* If no profile function is specified, it's not possible to get integrated
   * intensities at all and we try to use the one specified by the user
   * instead.
   */
  std::string profileFunctionName = rawPeakCollection->getProfileFunctionName();

  if (!rawPeakCollection->hasProfileFunctionName()) {
    profileFunctionName = getPropertyValue("PeakProfileFunction");
  }

  std::vector<std::string> allowedProfiles =
      FunctionFactory::Instance().getFunctionNames<IPeakFunction>();

  if (std::find(allowedProfiles.begin(), allowedProfiles.end(),
                profileFunctionName) == allowedProfiles.end()) {
    throw std::runtime_error(
        "Cannot integrate peak profiles with invalid profile function.");
  }

  PoldiPeakCollection_sptr integratedPeakCollection =
      boost::make_shared<PoldiPeakCollection>(PoldiPeakCollection::Integral);
  integratedPeakCollection->setProfileFunctionName(profileFunctionName);

  // Preserve unit cell, point group
  assignCrystalData(integratedPeakCollection, rawPeakCollection);

  for (size_t i = 0; i < rawPeakCollection->peakCount(); ++i) {
    PoldiPeak_sptr peak = rawPeakCollection->peak(i);

    IPeakFunction_sptr profileFunction =
        boost::dynamic_pointer_cast<IPeakFunction>(
            FunctionFactory::Instance().createFunction(profileFunctionName));

    profileFunction->setHeight(peak->intensity());
    profileFunction->setFwhm(peak->fwhm(PoldiPeak::AbsoluteD));

    PoldiPeak_sptr integratedPeak = peak->clone();
    integratedPeak->setIntensity(UncertainValue(profileFunction->intensity()));
    integratedPeakCollection->addPeak(integratedPeak);
  }

  return integratedPeakCollection;
}
Exemple #4
0
bool PoldiPeakSearch::isLessThanMinimum(PoldiPeak_sptr peak) {
  return peak->intensity().value() <= m_minimumPeakHeight;
}
/** Assigns most likely indices to measured peaks.
 *
 *  This method takes a list of index candidate pairs and sorts it according to
 *their score, because
 *  a high score corresponds to a high probability of the assignment being
 *correct. Then the function
 *  takes the element with the highest score and inspects the
 *IndexCandidatePair. If the measured reflection
 *  does not have an index yet, it checks whether the candidate index has
 *already been used. In that case,
 *  the measured peak is stored in a buffer. Otherwise, the candidate presents
 *the best solution for the
 *  measured peak (because the current pair has the highest score in the list of
 *remaining candidate pairs) and
 *  the solution is accepted. This means that the measured as well as the
 *candidate peak are marked as "used" and
 *  the measured peak is stored in the PoldiPeakCollection that is located at
 *the index of the current pair.
 *
 *  Then the next element is checked and so on. Whenever a "next best" solution
 *for a measured peak in the mentioned
 *  buffer is found, the peak is removed from that buffer. Once all candidate
 *pairs have been evaluated, the peaks
 *  that are still in the buffer are considered unindexed and treated
 *accordingly.
 *
 *  For a more complete explanation of the principle, please check the
 *documentation in the wiki.
 *
 *  @param candidates :: Vector of possible index candidates.
 */
void PoldiIndexKnownCompounds::assignCandidates(
    const std::vector<IndexCandidatePair> &candidates) {
    // Make a copy since this is going to be modified
    std::vector<IndexCandidatePair> workCandidates = candidates;

    /* The vector is sorted by score (see comparison operator of PeakCandidate),
     * so the first element has the lowest score (lowest probability of being
     * a good guess).
     */
    std::sort(workCandidates.begin(), workCandidates.end());

    std::set<PoldiPeak_sptr> usedMeasuredPeaks;
    std::set<PoldiPeak_sptr> usedExpectedPeaks;

    std::set<PoldiPeak_sptr> unassignedMeasuredPeaks;

    /* The candidate at the back of the vector has the highest score,
     * so it's the candidate with the highest probability of being correct.
     * Consequently, the vector is iterated from end to beginning.
     */
    for (auto it = workCandidates.rbegin(); it != workCandidates.rend(); ++it) {
        IndexCandidatePair currentCandidate = *it;

        PoldiPeak_sptr measuredPeak = currentCandidate.observed;
        PoldiPeak_sptr expectedPeak = currentCandidate.candidate;

        g_log.information() << "    Candidate d="
                            << static_cast<double>(measuredPeak->d()) << " -> "
                            << "Phase: "
                            << currentCandidate.candidateCollectionIndex << " ["
                            << MillerIndicesIO::toString(expectedPeak->hkl())
                            << "] (d=" << static_cast<double>(expectedPeak->d())
                            << "), "
                            << "Score=(" << currentCandidate.positionMatch << "): ";

        /* If the peak has not been indexed yet, it is not stored in the set
         * that holds measured peaks that are already indexed, so the candidate
         * needs to be examined further.
         */
        if (!inPeakSet(usedMeasuredPeaks, measuredPeak)) {

            /* If the theoretical reflection of this index-candidate has already been
             * assigned to a measured peak, the measured peak is inserted into
             * a second set where it is kept in case there is another candidate
             * for this measured peak.
             */
            if (inPeakSet(usedExpectedPeaks, expectedPeak)) {
                unassignedMeasuredPeaks.insert(measuredPeak);
                g_log.information()
                        << "      Candidate rejected: Candidate has been already used."
                        << std::endl;
            } else {
                /* Otherwise, the indexed candidate is accepted and the measured peak
                 * is removed from the set of peaks that are waiting for another
                 * solution.
                 */
                if (inPeakSet(unassignedMeasuredPeaks, measuredPeak)) {
                    unassignedMeasuredPeaks.erase(measuredPeak);
                }

                usedExpectedPeaks.insert(expectedPeak);
                usedMeasuredPeaks.insert(measuredPeak);

                assignPeakIndex(currentCandidate);
                g_log.information() << "      Candidate accepted." << std::endl;
            }
        } else {
            g_log.information()
                    << "      Candidate rejected: peak has already been indexed: ["
                    << MillerIndicesIO::toString(measuredPeak->hkl()) << "]."
                    << std::endl;
        }
    }

    /* All peaks that are still in this set at this point are not indexed and thus
     * inserted into the
     * peak collection that holds unindexed peaks.
     */
    for (auto it = unassignedMeasuredPeaks.begin();
            it != unassignedMeasuredPeaks.end(); ++it) {
        collectUnindexedPeak(*it);
    }
}
bool PoldiFitPeaks1D2::peakIsAcceptable(const PoldiPeak_sptr &peak) const {
  return peak->intensity() > 0 &&
         peak->fwhm(PoldiPeak::Relative) < m_maxRelativeFwhm &&
         peak->fwhm(PoldiPeak::Relative) > 0.001;
}