0

我正在使用米勒指数 (hkl) 进行一些晶体学计算,即存储在int[]数组中的整数三元组 (hkl)。我正在使用 C#。到目前为止,如果我设置一个最大值 hmax、kmax 和 lmax,我可以填充一个包含所有等效项的列表:

List<int[]> milind = new List<int[]>;
int[] mindex = new int[3];
for ( int h = -hmax ; h <= hmax; h++)
{
    mindex[0] = h;
    for ( int k = -kmax ; k <= kmax; k++)
    {
        mindex[1] = k;
        for ( int l = -lmax ; l <= lmax; l++)
        {
             mindex[2] = l;
             milind.Add(mindex);
        }
    }
} 

问题:如何使用 C# 删除/过滤所有等价物,即一组 [h,k,l] 的排列?

示例:假设我们有[h=1,k=0,l=0],我想删除/过滤: [0,1,0], [0,0,1], [-1,0,0], [0,-1,0], [0,0,-1]... 等。仅保留[0,0,1]在列表中。

如果您需要更多信息,请告诉我。

4

2 回答 2

1

为您的索引定义一个“规范”形式,例如:

  • [h]为最大震级指数,符号+1;
  • [k] 是第二大震级指数;
  • [l] 是剩余索引
  • 所有共同因素都已被排除在外

现在将所有索引转换为其规范形式,如果它们与已找到的索引重复,则将其删除。

这种形式还允许对您的米勒指数进行排序,加快搜索速度等。

我有物理学学位;我知道米勒指数不能太大。;-)

这是一个“规范化”程序。它使用蛮力进行分解,但我相信这对于问题域来说已经足够了;如果性能是一个可以稍后解决的问题。

2013-03-09:更新为使用预先计算的素数表 <= 31

  public struct MillerIndex {
    public int H { get; private set; }
    public int K { get; private set; }
    public int L { get; private set; }

    public MillerIndex( int h, int k, int l) : this() {
      H = h;  K = k;  L = l;
    }
  }

  public static class MillereHandler {

    static IList<int> Primes = new List<int> {2,3,5,7,11,13,17,19,23,29,31};

    public static MillerIndex GetCanonical(MillerIndex mi) {
      int h, k, l, sign;
      if (Math.Abs(mi.H) > Math.Abs(mi.K) && Math.Abs(mi.H) >  Math.Abs(mi.L) ) {
        sign = Math.Sign(mi.H);
        h = mi.H;
        k = Math.Abs(mi.K) > Math.Abs(mi.L) ? mi.K : mi.L;
        l = Math.Abs(mi.K) > Math.Abs(mi.L) ? mi.L : mi.K;
      } else if (Math.Abs(mi.K) > Math.Abs(mi.H) && Math.Abs(mi.K) >  Math.Abs(mi.L) ) {
        sign = Math.Sign(mi.K);
        h = mi.K;
        k = Math.Abs(mi.H) > Math.Abs(mi.L) ? mi.H : mi.L;
        l = Math.Abs(mi.H) > Math.Abs(mi.L) ? mi.L : mi.H;
      } else {
        sign = Math.Sign(mi.L);
        h = mi.L;
        k = Math.Abs(mi.H) > Math.Abs(mi.K) ? mi.H : mi.K;
        l = Math.Abs(mi.H) > Math.Abs(mi.K) ? mi.K : mi.H;
      }

      h *= sign;  k *= sign;  l *= sign;

      foreach (var i in Primes.Where(i=> (i^2) < l) ) {
        while ( (h/i)*i == h  &&  (k/i)*i == k &&  (l/i)*i == l ) {
          h /= h/i;  k /= k/i;  l /= l/i;
        }
      }

      return new MillerIndex(h, k, l);
    }
  }
于 2013-03-07T18:51:45.070 回答
0

我只想补充彼得的答案。取消公因数是不正确的。(200) 反射不同于 (100) 反射。因此,没有必要对素数进行所有努力。

如果您具有三次对称性,则生成规范形式的最简单方法是通过取绝对值然后对三个数字进行排序来使所有索引为正。因此[0,-2,-1]-> [0,2,1]->[0,1,2]

于 2014-11-06T23:39:29.230 回答