Skip to content
Permalink
Browse files

Add options to ReadCtfFile to convert Eulers and Hex X-Axis (#897)

+ Add options to ReadCtfFile to convert Eulers and Hex X-Axis
+ Adds a boolean option to Read CTF to convert the Eulers to Radians
+ Adds a boolean option to convert hexagonal Laue phases to the EDAX standard for X-Axis alignment
+ Clang-Format sources and update documentation file for ReadCtf filter.

updates #895. fixes #895. closes #895 

Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
  • Loading branch information...
imikejackson committed Apr 8, 2019
1 parent 67f3fd6 commit b0583924a7f7a446618f1260a093ca663fadfd08
@@ -19,37 +19,33 @@ If the data has come from a HKL acquisition system and the settings of the acqui

The user also may want to assign un-indexed pixels to be ignored by flagging them as "bad". The [Threshold Objects](@ref multithresholdobjects) **Filter** can be used to define this _mask_ by thresholding on values such as _Error_ = 0.


### Radians and Degrees ###

2D .ctf files have their angles in **degrees**. Please be sure to [convert](@ref changeanglerepresentation) the Euler angles from degrees to radians before running any other **Filter**.

Most 2D .ctf files have their angles in **degrees** where as DREAM.3D expects radians. The filter provides an option to convert the Euler Angles to Radians and is turned on by default. The user is encouraged to create an IPF Image of their EBSD data to ensure that they do in-fact need to have this option enabled.

### The Axis Alignment Issue for Hexagonal Symmetry [1] ###

+ The issue with hexagonal materials is the alignment of the Cartesian coordinate system used for calculations with the crystal coordinate system (the Bravais lattice).
+ In one convention (e.g. EDAX.TSL), the x-axis, i.e. [1,0,0], is aligned with the crystal a1 axis, i.e. the [2,-1,-1,0] direction. In this case, the y-axis is aligned with the [0,1,-1,0] direction. (Green Axis in Figure 1)
+ In the other convention, (e.g. Oxford Instr, Univ. Metz software), the x-axis, i.e. [1,0,0], is aligned with the crystal [1,0,-1,0] direction. In this case, the y-axis is aligned with the [-1,2,-1,0] direction. (Red Axis in Figure 1)
+ This is important because texture analysis can lead to an ambiguity as to the alignment of [2,-1,-1,0] versus [1,0,-1,0], with apparent **30 ** shifts in the data.
+ This is important because texture analysis can lead to an ambiguity as to the alignment of [2,-1,-1,0] versus [1,0,-1,0], with apparent **30 Degree** shifts in the data.
+ Caution: it appears that the axis alignment is a choice that must be made when installing TSL software so determination of which convention is in use must be made on a case-by-case basis. It is fixed to the y-convention in the HKL software.
+ The main clue that something is wrong in a conversion is that either the 2110 & 1010 pole figures are transposed, or that a peak in the inverse pole figure that should be present at 2110 has shifted over to 1010.
+ DREAM.3D uses the TSL/EDAX convention.
+ **The result of this is that the filter will _AUTOMATICALLY_ add 30 to phi2 when reading Oxford Instr (.ctf) files. There is no way to turn off this behavior. **
+ __The result of this is that the filter will by default add 30 degrees to the second Euler Angle (phi2) when reading Oxford Instr (.ctf) files. This can be disabled by the user if necessary.__

| Figure 1 |
|--------|
| ![](Images/Hexagonal_Axis_Alignment.png) |
| ![Figure showing 30 Degree conversions](Images/Hexagonal_Axis_Alignment.png) |
| **Figure 1:** showing TSL and Oxford Instr. conventions. EDAX/TSL is in **Green**. Oxford Inst. is in **Red** |





## Parameters ##

| Name | Type | Description |
|------|------| ----------- |
| Input File | File Path |The input .ctf file path |
| Convert to Radians | bool | Should the filter convert the Eulers to Radians (Default = true)|
| Hexagonal Axis Alignment | bool | Should the filter convert a Hexagonal phase to the EDAX standard for x-axis alignment |

## Required Geometry ##

@@ -1,5 +1,5 @@
/* ============================================================================
* Copyright (c) 2009-2016 BlueQuartz Software, LLC
* Copyright (c) 2009-2019 BlueQuartz Software, LLC
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@@ -44,14 +44,16 @@
#include "SIMPLib/FilterParameters/AbstractFilterParametersReader.h"
#include "SIMPLib/FilterParameters/DataContainerCreationFilterParameter.h"
#include "SIMPLib/FilterParameters/InputFileFilterParameter.h"
#include "SIMPLib/FilterParameters/BooleanFilterParameter.h"
#include "SIMPLib/FilterParameters/SeparatorFilterParameter.h"
#include "SIMPLib/FilterParameters/StringFilterParameter.h"
#include "SIMPLib/Geometry/ImageGeom.h"
#include "SIMPLib/Math/SIMPLibMath.h"

#include "EbsdLib/HKL/CtfFields.h"

#include "OrientationAnalysis/OrientationAnalysisConstants.h"
#include "OrientationAnalysis/OrientationAnalysisVersion.h"
#include "ChangeAngleRepresentation.h"

enum createdPathID : RenameDataPath::DataID_t
{
@@ -91,7 +93,9 @@ ReadCtfDataPrivate::ReadCtfDataPrivate(ReadCtfData* ptr)
//
// -----------------------------------------------------------------------------
ReadCtfData::ReadCtfData()
: m_DataContainerName(SIMPL::Defaults::ImageDataContainerName)
: m_DegreesToRadians(true)
, m_EdaxHexagonalAlignment(true)
, m_DataContainerName(SIMPL::Defaults::ImageDataContainerName)
, m_CellEnsembleAttributeMatrixName(SIMPL::Defaults::CellEnsembleAttributeMatrixName)
, m_CellAttributeMatrixName(SIMPL::Defaults::CellAttributeMatrixName)
, m_FileWasRead(false)
@@ -123,6 +127,8 @@ void ReadCtfData::setupFilterParameters()
{
FilterParameterVectorType parameters;
parameters.push_back(SIMPL_NEW_INPUT_FILE_FP("Input File", InputFile, FilterParameter::Parameter, ReadCtfData, "*.ctf"));
parameters.push_back(SIMPL_NEW_BOOL_FP("Convert Eulers to Radians", DegreesToRadians, FilterParameter::Parameter, ReadCtfData));
parameters.push_back(SIMPL_NEW_BOOL_FP("Convert Hexagonal X-Axis to Edax Standard", EdaxHexagonalAlignment, FilterParameter::Parameter, ReadCtfData));
parameters.push_back(SIMPL_NEW_DC_CREATION_FP("Data Container", DataContainerName, FilterParameter::CreatedArray, ReadCtfData));
parameters.push_back(SeparatorFilterParameter::New("Cell Data", FilterParameter::CreatedArray));
parameters.push_back(SIMPL_NEW_STRING_FP("Cell Attribute Matrix", CellAttributeMatrixName, FilterParameter::CreatedArray, ReadCtfData));
@@ -137,6 +143,8 @@ void ReadCtfData::setupFilterParameters()
void ReadCtfData::readFilterParameters(AbstractFilterParametersReader* reader, int index)
{
reader->openFilterGroup(this, index);
setDegreesToRadians(reader->readValue("DegreesToRadians", getDegreesToRadians()));
setEdaxHexagonalAlignment(reader->readValue("EdaxHexagonalAlignment", getEdaxHexagonalAlignment()));
setDataContainerName(reader->readDataArrayPath("DataContainerName", getDataContainerName()));
setCellAttributeMatrixName(reader->readString("CellAttributeMatrixName", getCellAttributeMatrixName()));
setCellEnsembleAttributeMatrixName(reader->readString("CellEnsembleAttributeMatrixName", getCellEnsembleAttributeMatrixName()));
@@ -215,15 +223,15 @@ void ReadCtfData::dataCheck()
CtfFields ctffeatures;
names = ctffeatures.getFilterFeatures<QVector<QString>>();
QVector<size_t> cDims(1, 1);
for(qint32 i = 0; i < names.size(); ++i)
for(const auto& name : names)
{
if(reader->getPointerType(names[i]) == Ebsd::Int32)
if(reader->getPointerType(name) == Ebsd::Int32)
{
cellAttrMat->createAndAddAttributeArray<DataArray<int32_t>, AbstractFilter, int32_t>(this, names[i], 0, cDims);
cellAttrMat->createAndAddAttributeArray<DataArray<int32_t>, AbstractFilter, int32_t>(this, name, 0, cDims);
}
else if(reader->getPointerType(names[i]) == Ebsd::Float)
else if(reader->getPointerType(name) == Ebsd::Float)
{
cellAttrMat->createAndAddAttributeArray<DataArray<float>, AbstractFilter, float>(this, names[i], 0, cDims);
cellAttrMat->createAndAddAttributeArray<DataArray<float>, AbstractFilter, float>(this, name, 0, cDims);
}
}
}
@@ -237,34 +245,34 @@ void ReadCtfData::dataCheck()
QVector<size_t> cDims(1, 3);
tempPath.update(getDataContainerName().getDataContainerName(), getCellAttributeMatrixName(), Ebsd::CtfFile::EulerAngles);
m_CellEulerAnglesPtr = getDataContainerArray()->createNonPrereqArrayFromPath<DataArray<float>, AbstractFilter, float>(
this, tempPath, 0, cDims); /* Assigns the shared_ptr<> to an instance variable that is a weak_ptr<> */
if(nullptr != m_CellEulerAnglesPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
this, tempPath, 0, cDims); /* Assigns the shared_ptr<> to an instance variable that is a weak_ptr<> */
if(nullptr != m_CellEulerAnglesPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
{
m_CellEulerAngles = m_CellEulerAnglesPtr.lock()->getPointer(0);
} /* Now assign the raw pointer to data from the DataArray<T> object */

cDims[0] = 1;
tempPath.update(getDataContainerName().getDataContainerName(), getCellAttributeMatrixName(), Ebsd::CtfFile::Phases);
m_CellPhasesPtr = getDataContainerArray()->createNonPrereqArrayFromPath<DataArray<int32_t>, AbstractFilter, int32_t>(
this, tempPath, 0, cDims); /* Assigns the shared_ptr<> to an instance variable that is a weak_ptr<> */
if(nullptr != m_CellPhasesPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
this, tempPath, 0, cDims); /* Assigns the shared_ptr<> to an instance variable that is a weak_ptr<> */
if(nullptr != m_CellPhasesPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
{
m_CellPhases = m_CellPhasesPtr.lock()->getPointer(0);
} /* Now assign the raw pointer to data from the DataArray<T> object */

tempPath.update(getDataContainerName().getDataContainerName(), getCellEnsembleAttributeMatrixName(), Ebsd::CtfFile::CrystalStructures);
m_CrystalStructuresPtr =
getDataContainerArray()->createNonPrereqArrayFromPath<DataArray<uint32_t>, AbstractFilter, uint32_t>(this, tempPath, Ebsd::CrystalStructure::UnknownCrystalStructure, cDims);
if(nullptr != m_CrystalStructuresPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
if(nullptr != m_CrystalStructuresPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
{
m_CrystalStructures = m_CrystalStructuresPtr.lock()->getPointer(0);
} /* Now assign the raw pointer to data from the DataArray<T> object */

cDims[0] = 6;
tempPath.update(getDataContainerName().getDataContainerName(), getCellEnsembleAttributeMatrixName(), Ebsd::CtfFile::LatticeConstants);
m_LatticeConstantsPtr = getDataContainerArray()->createNonPrereqArrayFromPath<DataArray<float>, AbstractFilter, float>(
this, tempPath, 0.0, cDims); /* Assigns the shared_ptr<> to an instance variable that is a weak_ptr<> */
if(nullptr != m_LatticeConstantsPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
this, tempPath, 0.0, cDims); /* Assigns the shared_ptr<> to an instance variable that is a weak_ptr<> */
if(nullptr != m_LatticeConstantsPtr.lock()) /* Validate the Weak Pointer wraps a non-nullptr pointer to a DataArray<T> object */
{
m_LatticeConstants = m_LatticeConstantsPtr.lock()->getPointer(0);
} /* Now assign the raw pointer to data from the DataArray<T> object */
@@ -300,7 +308,7 @@ void ReadCtfData::flushCache()
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void ReadCtfData::readDataFile(CtfReader* reader, DataContainer::Pointer m, QVector<size_t>& tDims, CTF_READ_FLAG flag)
void ReadCtfData::readDataFile(CtfReader* reader, const DataContainer::Pointer& m, QVector<size_t>& tDims, CTF_READ_FLAG flag)
{
QFileInfo fi(m_InputFile);
QDateTime timeStamp(fi.lastModified());
@@ -326,7 +334,7 @@ void ReadCtfData::readDataFile(CtfReader* reader, DataContainer::Pointer m, QVec
return;
}

m_FileWasRead = true;
m_FileWasRead = true;
}
else
{
@@ -494,15 +502,15 @@ void ReadCtfData::copyRawEbsdData(CtfReader* reader, QVector<size_t>& tDims, QVe
ebsdAttrMat->resizeAttributeArrays(tDims);
{
/* Take from H5CtfVolumeReader.cpp
* For HKL OIM Files if there is a single phase then the value of the phase
* data is one (1). If there are 2 or more phases then the lowest value
* of phase is also one (1). However, if there are "zero solutions" in the data
* then those points are assigned a phase of zero. Since those points can be identified
* by other methods, the phase of these points should be changed to one since in the rest
* of the reconstruction code we follow the convention that the lowest value is One (1)
* even if there is only a single phase. The next if statement converts all zeros to ones
* if there is a single phase in the OIM data.
*/
* For HKL OIM Files if there is a single phase then the value of the phase
* data is one (1). If there are 2 or more phases then the lowest value
* of phase is also one (1). However, if there are "zero solutions" in the data
* then those points are assigned a phase of zero. Since those points can be identified
* by other methods, the phase of these points should be changed to one since in the rest
* of the reconstruction code we follow the convention that the lowest value is One (1)
* even if there is only a single phase. The next if statement converts all zeros to ones
* if there is a single phase in the OIM data.
*/
phasePtr = reinterpret_cast<int32_t*>(reader->getPointerByName(Ebsd::Ctf::Phase));
for(size_t i = 0; i < totalPoints; i++)
{
@@ -530,9 +538,16 @@ void ReadCtfData::copyRawEbsdData(CtfReader* reader, QVector<size_t>& tDims, QVe
cellEulerAngles[3 * i] = f1[i];
cellEulerAngles[3 * i + 1] = f2[i];
cellEulerAngles[3 * i + 2] = f3[i];
if(m_CrystalStructures[cellPhases[i]] == Ebsd::CrystalStructure::Hexagonal_High)
if(m_CrystalStructures[cellPhases[i]] == Ebsd::CrystalStructure::Hexagonal_High && m_EdaxHexagonalAlignment)
{
cellEulerAngles[3 * i + 2] = cellEulerAngles[3 * i + 2] + (30.0); // See the documentation for this correction factor
}
// Now convert to radians if requested by the user
if(m_DegreesToRadians)
{
cellEulerAngles[3 * i + 2] = cellEulerAngles[3 * i + 2] + (30.0);
cellEulerAngles[3 * i] = cellEulerAngles[3 * i] * SIMPLib::Constants::k_PiOver180;
cellEulerAngles[3 * i + 1] = cellEulerAngles[3 * i + 1] * SIMPLib::Constants::k_PiOver180;
cellEulerAngles[3 * i + 2] = cellEulerAngles[3 * i + 2] * SIMPLib::Constants::k_PiOver180;
}
}
ebsdAttrMat->insertOrAssign(fArray);
@@ -627,8 +642,6 @@ void ReadCtfData::execute()
setInputFile_Cache(m_InputFile);
}
}


}

// -----------------------------------------------------------------------------
@@ -69,12 +69,14 @@ class ReadCtfDataPrivate;
class OrientationAnalysis_EXPORT ReadCtfData : public AbstractFilter
{
Q_OBJECT
PYB11_CREATE_BINDINGS(ReadCtfData SUPERCLASS AbstractFilter)
PYB11_PROPERTY(DataArrayPath DataContainerName READ getDataContainerName WRITE setDataContainerName)
PYB11_PROPERTY(QString CellEnsembleAttributeMatrixName READ getCellEnsembleAttributeMatrixName WRITE setCellEnsembleAttributeMatrixName)
PYB11_PROPERTY(QString CellAttributeMatrixName READ getCellAttributeMatrixName WRITE setCellAttributeMatrixName)
PYB11_PROPERTY(bool FileWasRead READ getFileWasRead WRITE setFileWasRead)
PYB11_PROPERTY(QString InputFile READ getInputFile WRITE setInputFile)
PYB11_CREATE_BINDINGS(ReadCtfData SUPERCLASS AbstractFilter)
PYB11_PROPERTY(bool DegreesToRadians READ getDegreesToRadians WRITE setDegreesToRadians)
PYB11_PROPERTY(bool EdaxHexagonalAlignment READ getEdaxHexagonalAlignment WRITE setEdaxHexagonalAlignment)
PYB11_PROPERTY(DataArrayPath DataContainerName READ getDataContainerName WRITE setDataContainerName)
PYB11_PROPERTY(QString CellEnsembleAttributeMatrixName READ getCellEnsembleAttributeMatrixName WRITE setCellEnsembleAttributeMatrixName)
PYB11_PROPERTY(QString CellAttributeMatrixName READ getCellAttributeMatrixName WRITE setCellAttributeMatrixName)
PYB11_PROPERTY(bool FileWasRead READ getFileWasRead WRITE setFileWasRead)
PYB11_PROPERTY(QString InputFile READ getInputFile WRITE setInputFile)
Q_DECLARE_PRIVATE(ReadCtfData)

public:
@@ -84,6 +86,12 @@ class OrientationAnalysis_EXPORT ReadCtfData : public AbstractFilter

~ReadCtfData() override;

SIMPL_FILTER_PARAMETER(bool, DegreesToRadians)
Q_PROPERTY(bool DegreesToRadians READ getDegreesToRadians WRITE setDegreesToRadians)

SIMPL_FILTER_PARAMETER(bool, EdaxHexagonalAlignment)
Q_PROPERTY(bool EdaxHexagonalAlignment READ getEdaxHexagonalAlignment WRITE setEdaxHexagonalAlignment)

SIMPL_FILTER_PARAMETER(DataArrayPath, DataContainerName)
Q_PROPERTY(DataArrayPath DataContainerName READ getDataContainerName WRITE setDataContainerName)

@@ -112,7 +120,7 @@ class OrientationAnalysis_EXPORT ReadCtfData : public AbstractFilter
* @brief getBrandingString Returns the branding string for the filter, which is a tag
* used to denote the filter's association with specific plugins
* @return Branding string
*/
*/
const QString getBrandingString() const override;

/**
@@ -164,8 +172,8 @@ class OrientationAnalysis_EXPORT ReadCtfData : public AbstractFilter
void execute() override;

/**
* @brief preflight Reimplemented from @see AbstractFilter class
*/
* @brief preflight Reimplemented from @see AbstractFilter class
*/
void preflight() override;

/* These are non-exposed to the user through the GUI. Manual Pipelines are OK to set them */
@@ -183,8 +191,8 @@ class OrientationAnalysis_EXPORT ReadCtfData : public AbstractFilter

public slots:
/**
* @brief flushCache Resets the cache file state
*/
* @brief flushCache Resets the cache file state
*/
void flushCache();

signals:
@@ -224,28 +232,28 @@ public slots:
void initialize();

/**
* @brief copyRawEbsdData Reads the Ang file and puts the data into the data container
* @param reader CtfReader instance pointer
* @param tDims Tuple dimensions
* @param cDims Component dimensions
*/
* @brief copyRawEbsdData Reads the Ang file and puts the data into the data container
* @param reader CtfReader instance pointer
* @param tDims Tuple dimensions
* @param cDims Component dimensions
*/
void copyRawEbsdData(CtfReader* reader, QVector<size_t>& tDims, QVector<size_t>& cDims);

/**
* @brief loadMaterialInfo Reads the values for the phase type, crystal structure
* and precipitate fractions from the EBSD file.
* @param reader CtfReader instance pointer
* @return Integer error value
*/
* @brief loadMaterialInfo Reads the values for the phase type, crystal structure
* and precipitate fractions from the EBSD file.
* @param reader CtfReader instance pointer
* @return Integer error value
*/
int32_t loadMaterialInfo(CtfReader* reader);

/**
* @brief readDataFile Reads the Ctf file
* @param reader CtfReader instance pointer
* @param m DataContainer instance pointer
* @param tDims Tuple dimensions
*/
void readDataFile(CtfReader* reader, DataContainer::Pointer m, QVector<size_t>& tDims, CTF_READ_FLAG flag);
* @brief readDataFile Reads the Ctf file
* @param reader CtfReader instance pointer
* @param m DataContainer instance pointer
* @param tDims Tuple dimensions
*/
void readDataFile(CtfReader* reader, const DataContainer::Pointer& m, QVector<size_t>& tDims, CTF_READ_FLAG flag);

private:
QScopedPointer<ReadCtfDataPrivate> const d_ptr;
Oops, something went wrong.

0 comments on commit b058392

Please sign in to comment.
You can’t perform that action at this time.