Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions .github/workflows/clang-format.yml

This file was deleted.

38 changes: 38 additions & 0 deletions .github/workflows/format_pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: clang-format pr

on:
pull_request:
branches:
- develop
- master

jobs:
clang_format_pr:
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- name: Add Problem Matcher
uses: ammaraskar/gcc-problem-matcher@a141586609e2a558729b99a8c574c048f7f56204
- name: Install clang-format-19
run: |
sudo apt-get update
sudo apt-get install clang-format-19
clang-format-19 --version
- name: Check Formatting
id: check_format
continue-on-error: true
run: |
python3 scripts/clang_format.py --format-version 19 --commits HEAD^ HEAD
- name: Apply Formatting
if: steps.check_format.outcome != 'success'
run: |
python3 scripts/clang_format.py --format-version 19 --modify --commits HEAD^ HEAD
- name: Add Suggestions
if: steps.check_format.outcome != 'success'
uses: reviewdog/action-suggester@v1
with:
tool_name: clang-format
fail_level: error
24 changes: 24 additions & 0 deletions .github/workflows/format_push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: clang-format

on:
push:
branches:
- develop
- master

jobs:
clang_format:
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v2
- name: Add Problem Matcher
uses: ammaraskar/gcc-problem-matcher@a141586609e2a558729b99a8c574c048f7f56204
- name: Install clang-format-19
run: |
sudo apt-get update
sudo apt-get install clang-format-19
clang-format-19 --version
- name: Check Formatting
run: |
python3 scripts/clang_format.py --format-version 19
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Repository Guidance

EbsdLib is a C++20 CMake library. Follow the checked-in formatter and lint configuration: Allman braces, two-space indentation, left-aligned pointers, and the repository naming conventions.

- Core library code is under `Source/EbsdLib/`; applications are under `Source/Apps/`; tests and CMake support live in their existing repository directories.
- Configure with `cmake --preset EbsdLib-Release`; verify with the actual CMake build and tests rather than relying on clangd diagnostics alone.
- Run tests through `ctest`, not test executables directly.
- For inverse-pole-figure and standard-stereographic-triangle visualization, reuse the LaueOps stereographic mapping. Do not substitute a Lambert eta/chi rectangle.
- Keep durable architecture and workflow documentation in the repository; do not encode active-branch status or personal machine paths here.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ option(EbsdLib_BUILD_H5SUPPORT "Build H5Support Library" OFF)


# set project's name
project(EbsdLibProj VERSION 3.1.0)
project(EbsdLibProj VERSION 3.1.1)


# Request C++17 standard, using new CMake variables.
Expand Down
77 changes: 76 additions & 1 deletion Docs/Index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Various Bits of Documentation for EbsdLib
# Documentation for EbsdLib

EbsdLib is primarily used in the [DREAM3D](https://www.bluequartz.net) family of applications and libraries.

Expand Down Expand Up @@ -27,6 +27,81 @@ Position-space validation across all 11 Laue classes lives in

---

# Release Notes — EbsdLib 3.1.1

EbsdLib 3.1.1 is the "misorientation analysis + correctness" release. It adds
tools for calculating and evaluating misorientation distribution functions
(MDFs), and fixes several long-standing Laue-class fundamental-zone and Schmid
factor defects inherited from the legacy OrientationLib implementation.

## New features

### Misorientation kernel density estimation

- `MisorientationKDE` accumulates weighted misorientations on the Laue-class MDF
fundamental-zone grid and evaluates the resulting density at arbitrary
misorientation quaternions.
- KDE evaluation is symmetrized over the crystal symmetry operators and grain
exchange, and is normalized to a mean density of one over SO(3).
- `computeAngleCurve()` extracts a misorientation-angle distribution together
with the corresponding random-reference distribution.
- Each occupied bin retains the weighted circular mean of its observations as
its kernel center. This avoids the low-angle bias caused by snapping narrow
kernels to geometric bin centers, particularly for hexagonal phases.

### SO(3) kernel and random-angle reference

- `SO3DeLaValleePoussinKernel` implements the de la Vallée Poussin orientation
kernel, including half-width conversion, normalization, and finite support.
- `random_angle_distribution::Compute()` and `MaxMisorientationAngle()` provide
analytical random misorientation-angle distributions and limits for the
supported Laue classes.

## Correctness fixes

### Misorientation fundamental-zone folds

- Corrected `getMDFFZRod()` for cubic-low, trigonal, trigonal-low,
hexagonal-low, tetragonal, and tetragonal-low symmetry. The corrected folds
preserve the misorientation angle and use the proper rotational-symmetry
sector for each Laue class.
- Implemented the previously stubbed triclinic, monoclinic, and orthorhombic
folds, so MDF calculations for those phases no longer abort with
`method_not_implemented`.
- Corrected equatorial boundary handling in the hexagonal, trigonal, and
tetragonal folds.

### ODF and Schmid-factor calculations

- Fixed the tetragonal-low ODF dimension constant that caused
`determineEulerAngles()` to return NaN Euler angles for all sampled bins.
- Replaced truncated cubic slip-system normalizers with the full-precision
`sqrt(3)` and `sqrt(2)` constants, preventing Schmid factors from exceeding
the physical maximum of 0.5 because of rounding bias.
- Initialized every output of the automatic `getSchmidFactorAndSS()` overloads
on all code paths. Unsupported Laue classes now return defined zero values
instead of stale or indeterminate angle components.

## Validation evidence

- Fundamental-zone tests cover all 11 Laue classes, including symmetry
equivalence, angle preservation, idempotence, boundary behavior, and guards
against over-folding.
- Kernel constants and random-angle distributions are checked against MTEX
6.1.0 reference values.
- Cubic and hexagonal MDF angle curves are cross-checked against MTEX, and a
correlated 60° about `<111>` (Σ3) distribution guards against regressions
that flatten a textured MDF toward the random reference.
- Schmid-factor tests pre-poison output values to ensure the stub Laue classes
explicitly reset every output.

## Maintenance

- Updated the formatting workflows to run for both pull requests and pushes,
using clang-format 19.

---

# Release Notes — EbsdLib 3.1.0

EbsdLib 3.1 is the "discrete pole figures + TSL-by-default" release. It builds
Expand Down
4 changes: 2 additions & 2 deletions Source/EbsdLib/Core/EbsdDataArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
#define EBSD_BYTE_SWAP_32(x) _byteswap_ulong(x)
#define EBSD_BYTE_SWAP_64(x) _byteswap_uint64(x)

#elif(defined(__clang__) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
#if(defined(__clang__) && __has_builtin(__builtin_bswap16)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
#elif (defined(__clang__) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
#if (defined(__clang__) && __has_builtin(__builtin_bswap16)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
#define EBSD_BYTE_SWAP_16(x) __builtin_bswap16(x)
#else
#define EBSD_BYTE_SWAP_16(x) __builtin_bswap32((x) << 16)
Expand Down
4 changes: 2 additions & 2 deletions Source/EbsdLib/Core/EbsdLibDLLExport.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ building on Windows.
#if defined(EbsdLib_EXPORTS) /* Compiling the EbsdLib DLL/Dylib */
#if defined(_MSC_VER) /* MSVC Compiler Case */
#define EbsdLib_EXPORT __declspec(dllexport)
#elif(__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
#elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
#define EbsdLib_EXPORT __attribute__((visibility("default")))
#endif
#else /* Importing the DLL into another project */
#if defined(_MSC_VER) /* MSVC Compiler Case */
#define EbsdLib_EXPORT __declspec(dllimport)
#elif(__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
#elif (__GNUC__ >= 4) /* GCC 4.x has support for visibility options */
#define EbsdLib_EXPORT __attribute__((visibility("default")))
#endif
#endif
Expand Down
4 changes: 2 additions & 2 deletions Source/EbsdLib/IO/HKL/H5CtfImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ int H5CtfImporter::writeSliceData(hid_t fileId, CtfReader& reader, int z, int ac
if(nullptr == dataPtr)
{
assert(false);
} // We are going to crash here. I would rather crash than have bad data
} // We are going to crash here. I would rather crash than have bad data
dataPtr = dataPtr + (actualSlice * dims[0]); // Put the pointer at the proper offset into the larger array
WRITE_EBSD_DATA_ARRAY(reader, int, gid, name);
}
Expand All @@ -342,7 +342,7 @@ int H5CtfImporter::writeSliceData(hid_t fileId, CtfReader& reader, int z, int ac
if(nullptr == dataPtr)
{
assert(false);
} // We are going to crash here. I would rather crash than have bad data
} // We are going to crash here. I would rather crash than have bad data
dataPtr = dataPtr + (actualSlice * dims[0]); // Put the pointer at the proper offset into the larger array
WRITE_EBSD_DATA_ARRAY(reader, float, gid, name);
}
Expand Down
46 changes: 12 additions & 34 deletions Source/EbsdLib/LaueOps/CubicLowOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,48 +316,26 @@ RodriguesDType CubicLowOps::getMDFFZRod(const RodriguesDType& inRod) const
double n1 = ax[0];
double n2 = ax[1], n3 = ax[2], w = ax[3];

double FZn1 = w, FZn2 = 0.0, FZn3 = 0.0, FZw = 0.0;
double FZn1 = 0.0, FZn2 = 0.0, FZn3 = 0.0;
double FZw = w;

n1 = fabs(n1);
n2 = fabs(n2);
n3 = fabs(n3);
if(n1 > n2)
// The tetrahedral rotation group only provides the <111> 3-fold axes, so only
// cyclic permutations of the axis components are symmetry-equivalent. Rotate
// cyclically so the largest component is first; n2/n3 must NOT be sorted.
if(n2 >= n1 && n2 >= n3)
{
if(n1 > n3)
{
FZn1 = n1;
if(n2 > n3)
{
FZn2 = n2, FZn3 = n3;
}
else
{
FZn2 = n3, FZn3 = n2;
}
}
else
{
FZn1 = n3, FZn2 = n1, FZn3 = n2;
}
FZn1 = n2, FZn2 = n3, FZn3 = n1;
}
else if(n3 >= n1 && n3 >= n2)
{
FZn1 = n3, FZn2 = n1, FZn3 = n2;
}
else
{
if(n2 > n3)
{
FZn1 = n2;
if(n1 > n3)
{
FZn2 = n1, FZn3 = n3;
}
else
{
FZn2 = n3, FZn3 = n1;
}
}
else
{
FZn1 = n3, FZn2 = n2, FZn3 = n1;
}
FZn1 = n1, FZn2 = n2, FZn3 = n3;
}

return AxisAngleDType(FZn1, FZn2, FZn3, FZw).toRodrigues();
Expand Down
20 changes: 10 additions & 10 deletions Source/EbsdLib/LaueOps/CubicOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -846,25 +846,25 @@ void CubicOps::getSchmidFactorAndSS(double load[3], double& schmidfactor, double

double mag = loadx * loadx + loady * loady + loadz * loadz;
mag = std::sqrt(mag);
theta1 = (loadx + loady + loadz) / (mag * 1.732f);
theta1 = (loadx + loady + loadz) / (mag * ebsdlib::constants::k_Sqrt3D);
theta1 = std::fabs(theta1);
theta2 = (loadx + loady - loadz) / (mag * 1.732f);
theta2 = (loadx + loady - loadz) / (mag * ebsdlib::constants::k_Sqrt3D);
theta2 = std::fabs(theta2);
theta3 = (loadx - loady + loadz) / (mag * 1.732f);
theta3 = (loadx - loady + loadz) / (mag * ebsdlib::constants::k_Sqrt3D);
theta3 = std::fabs(theta3);
theta4 = (-loadx + loady + loadz) / (mag * 1.732f);
theta4 = (-loadx + loady + loadz) / (mag * ebsdlib::constants::k_Sqrt3D);
theta4 = std::fabs(theta4);
lambda1 = (loadx + loady) / (mag * 1.414f);
lambda1 = (loadx + loady) / (mag * ebsdlib::constants::k_Sqrt2D);
lambda1 = std::fabs(lambda1);
lambda2 = (loadx + loadz) / (mag * 1.414f);
lambda2 = (loadx + loadz) / (mag * ebsdlib::constants::k_Sqrt2D);
lambda2 = std::fabs(lambda2);
lambda3 = (loadx - loady) / (mag * 1.414f);
lambda3 = (loadx - loady) / (mag * ebsdlib::constants::k_Sqrt2D);
lambda3 = std::fabs(lambda3);
lambda4 = (loadx - loadz) / (mag * 1.414f);
lambda4 = (loadx - loadz) / (mag * ebsdlib::constants::k_Sqrt2D);
lambda4 = std::fabs(lambda4);
lambda5 = (loady + loadz) / (mag * 1.414f);
lambda5 = (loady + loadz) / (mag * ebsdlib::constants::k_Sqrt2D);
lambda5 = std::fabs(lambda5);
lambda6 = (loady - loadz) / (mag * 1.414f);
lambda6 = (loady - loadz) / (mag * ebsdlib::constants::k_Sqrt2D);
lambda6 = std::fabs(lambda6);
schmid1 = theta1 * lambda6;
schmid2 = theta1 * lambda4;
Expand Down
31 changes: 15 additions & 16 deletions Source/EbsdLib/LaueOps/HexagonalLowOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,24 +386,14 @@ RodriguesDType HexagonalLowOps::getMDFFZRod(const RodriguesDType& inRod) const
FZn1 = n1;
FZn2 = n2;
FZn3 = n3;
if(angle > 30.0)
// The 6/m rotation group is only the 6-fold about c (no in-plane 2-folds), so the
// axis azimuth folds into a plain 60 degree wedge with no mirror alternation
{
n1n2mag = std::sqrt(n1 * n1 + n2 * n2);
if(int(angle / 30) % 2 == 0)
{
FZw = angle - (30.0 * int(angle / 30.0));
FZw = FZw * ebsdlib::constants::k_PiOver180D;
FZn1 = n1n2mag * std::cos(FZw);
FZn2 = n1n2mag * std::sin(FZw);
}
else
{
FZw = angle - (30.0 * int(angle / 30.0));
FZw = 30.0f - FZw;
FZw = FZw * ebsdlib::constants::k_PiOver180D;
FZn1 = n1n2mag * std::cos(FZw);
FZn2 = n1n2mag * std::sin(FZw);
}
FZw = std::fmod(static_cast<double>(angle), 60.0);
FZw = FZw * ebsdlib::constants::k_PiOver180D;
FZn1 = n1n2mag * std::cos(FZw);
FZn2 = n1n2mag * std::sin(FZw);
}

return AxisAngleDType(FZn1, FZn2, FZn3, w).toRodrigues();
Expand Down Expand Up @@ -532,6 +522,15 @@ int HexagonalLowOps::getOdfBin(const RodriguesDType& rod) const

void HexagonalLowOps::getSchmidFactorAndSS(double load[3], double& schmidfactor, double angleComps[2], int& slipsys) const
{
// Every output must be defined before the schmid comparison chain below, which only assigns to
// them when a candidate beats the incumbent. Without these, schmidfactor was READ uninitialized
// by the first `if(schmid1 > schmidfactor)`, and slipsys/angleComps were left untouched whenever
// no candidate won.
schmidfactor = 0.0;
slipsys = 0;
angleComps[0] = 0.0;
angleComps[1] = 0.0;

double theta1, theta2, theta3, theta4, theta5, theta6, theta7, theta8, theta9;
double lambda1, lambda2, lambda3, lambda4, lambda5, lambda6, lambda7, lambda8, lambda9, lambda10;
double schmid1, schmid2, schmid3, schmid4, schmid5, schmid6;
Expand Down
Loading
Loading