2665 lines
55 KiB
C
2665 lines
55 KiB
C
/*
|
|
Space Group Info's (c) 1994-96 Ralf W. Grosse-Kunstleve
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
#define SGCLIB_C__
|
|
#include "sginfo.h"
|
|
|
|
|
|
static const char *Err_Ill_SMx_in_List = "Error: Illegal SeitzMx in list";
|
|
|
|
|
|
void SetSgError(const char *msg)
|
|
{
|
|
if (SgError == NULL)
|
|
SgError = msg;
|
|
}
|
|
|
|
|
|
int iModPositive(int ix, int iy)
|
|
{
|
|
if (iy > 0) {
|
|
ix %= iy;
|
|
if (ix < 0)
|
|
ix += iy;
|
|
}
|
|
|
|
return ix;
|
|
}
|
|
|
|
|
|
static void SwapRTMx(T_RTMx * Mx_a, T_RTMx * Mx_b)
|
|
{
|
|
int i;
|
|
T_RTMx BufMx;
|
|
|
|
|
|
for (i = 0; i < 12; i++)
|
|
BufMx.a[i] = Mx_a->a[i];
|
|
for (i = 0; i < 12; i++)
|
|
Mx_a->a[i] = Mx_b->a[i];
|
|
for (i = 0; i < 12; i++)
|
|
Mx_b->a[i] = BufMx.a[i];
|
|
}
|
|
|
|
|
|
static void CopyRotMxInfo(T_RotMxInfo * target, const T_RotMxInfo * source)
|
|
{
|
|
memcpy(target, source, sizeof(*target));
|
|
}
|
|
|
|
|
|
static void SwapRotMxInfo(T_RotMxInfo * RMx_a, T_RotMxInfo * RMx_b)
|
|
{
|
|
T_RotMxInfo Buffer;
|
|
|
|
memcpy(&Buffer, RMx_a, sizeof(Buffer));
|
|
memcpy(RMx_a, RMx_b, sizeof(Buffer));
|
|
memcpy(RMx_b, &Buffer, sizeof(Buffer));
|
|
}
|
|
|
|
|
|
int traceRotMx(const int *RotMx)
|
|
{
|
|
return RotMx[0] + RotMx[4] + RotMx[8];
|
|
}
|
|
|
|
|
|
int deterRotMx(const int *RotMx)
|
|
{
|
|
int det;
|
|
|
|
det = RotMx[0] * (RotMx[4] * RotMx[8] - RotMx[5] * RotMx[7]);
|
|
det -= RotMx[1] * (RotMx[3] * RotMx[8] - RotMx[5] * RotMx[6]);
|
|
det += RotMx[2] * (RotMx[3] * RotMx[7] - RotMx[4] * RotMx[6]);
|
|
|
|
return det;
|
|
}
|
|
|
|
|
|
void RotMx_t_Vector(int *R_t_V, const int *RotMx, const int *Vector,
|
|
int FacTr)
|
|
{
|
|
const int *vec;
|
|
|
|
|
|
if (FacTr > 0) {
|
|
vec = Vector;
|
|
*R_t_V = *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec;
|
|
*R_t_V %= FacTr;
|
|
if (*R_t_V < 0)
|
|
*R_t_V += FacTr;
|
|
R_t_V++;
|
|
vec = Vector;
|
|
*R_t_V = *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec;
|
|
*R_t_V %= FacTr;
|
|
if (*R_t_V < 0)
|
|
*R_t_V += FacTr;
|
|
R_t_V++;
|
|
vec = Vector;
|
|
*R_t_V = *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx * *vec;
|
|
*R_t_V %= FacTr;
|
|
if (*R_t_V < 0)
|
|
*R_t_V += FacTr;
|
|
} else {
|
|
vec = Vector;
|
|
*R_t_V = *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec++;
|
|
*R_t_V++ += *RotMx++ * *vec;
|
|
vec = Vector;
|
|
*R_t_V = *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec++;
|
|
*R_t_V++ += *RotMx++ * *vec;
|
|
vec = Vector;
|
|
*R_t_V = *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx++ * *vec++;
|
|
*R_t_V += *RotMx * *vec;
|
|
}
|
|
}
|
|
|
|
|
|
void RotMxMultiply(int *rmxab, const int *rmxa, const int *rmxb)
|
|
{
|
|
const int *a, *b;
|
|
|
|
/* no loops to be as fast as posslible */
|
|
|
|
a = rmxa;
|
|
b = rmxb;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r11 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
b -= 5;
|
|
rmxab++;
|
|
|
|
a = rmxa;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r12 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
b -= 5;
|
|
rmxab++;
|
|
|
|
a = rmxa;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r13 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a++ * *b;
|
|
b = rmxb;
|
|
rmxab++;
|
|
|
|
rmxa = a;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r21 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
b -= 5;
|
|
rmxab++;
|
|
|
|
a = rmxa;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r22 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
b -= 5;
|
|
rmxab++;
|
|
|
|
a = rmxa;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r23 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a++ * *b;
|
|
b = rmxb;
|
|
rmxab++;
|
|
|
|
rmxa = a;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r31 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
b -= 5;
|
|
rmxab++;
|
|
|
|
a = rmxa;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r32 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
b -= 5;
|
|
rmxab++;
|
|
|
|
a = rmxa;
|
|
*rmxab = *a++ * *b;
|
|
b += 3; /* r33 */
|
|
*rmxab += *a++ * *b;
|
|
b += 3;
|
|
*rmxab += *a * *b;
|
|
}
|
|
|
|
|
|
void RotateRotMx(int *RotMx, const int *RMx, const int *InvRMx)
|
|
{
|
|
int BufMx[9];
|
|
|
|
|
|
RotMxMultiply(BufMx, RotMx, InvRMx);
|
|
RotMxMultiply(RotMx, RMx, BufMx);
|
|
}
|
|
|
|
|
|
void SeitzMxMultiply(T_RTMx * smxab, const T_RTMx * smxa,
|
|
const T_RTMx * smxb)
|
|
{
|
|
const int *ar, *a, *b, *bt;
|
|
int *ab;
|
|
|
|
/* no loops to be as fast as posslible */
|
|
|
|
ar = smxa->a;
|
|
a = smxa->a;
|
|
b = smxb->a;
|
|
ab = smxab->a;
|
|
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r11 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r12 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r13 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a++ * *b;
|
|
b = smxb->a;
|
|
ab++;
|
|
|
|
ar = a;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r21 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r22 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r23 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a++ * *b;
|
|
b = smxb->a;
|
|
ab++;
|
|
|
|
ar = a;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r31 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r32 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r33 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a++ * *b++;
|
|
bt = b;
|
|
ab++;
|
|
|
|
ar = smxa->a;
|
|
*ab = *ar++ * *b++; /* t1 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar++ * *b;
|
|
b = bt;
|
|
*ab += *a++;
|
|
*ab %= STBF;
|
|
if (*ab < 0)
|
|
*ab += STBF;
|
|
ab++;
|
|
|
|
*ab = *ar++ * *b++; /* t2 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar++ * *b;
|
|
b = bt;
|
|
*ab += *a++;
|
|
*ab %= STBF;
|
|
if (*ab < 0)
|
|
*ab += STBF;
|
|
ab++;
|
|
|
|
*ab = *ar++ * *b++; /* t3 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar * *b;
|
|
*ab += *a;
|
|
*ab %= STBF;
|
|
if (*ab < 0)
|
|
*ab += STBF;
|
|
}
|
|
|
|
|
|
void RTMxMultiply(T_RTMx * rtmxab, const T_RTMx * rtmxa,
|
|
const T_RTMx * rtmxb, int FacAug, int FacTr)
|
|
{
|
|
const int *ar, *a, *b, *bt;
|
|
int *ab;
|
|
|
|
/* no loops to be as fast as posslible */
|
|
|
|
ar = rtmxa->a;
|
|
a = rtmxa->a;
|
|
b = rtmxb->a;
|
|
ab = rtmxab->a;
|
|
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r11 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r12 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r13 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a++ * *b;
|
|
b = rtmxb->a;
|
|
ab++;
|
|
|
|
ar = a;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r21 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r22 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r23 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a++ * *b;
|
|
b = rtmxb->a;
|
|
ab++;
|
|
|
|
ar = a;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r31 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r32 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a * *b;
|
|
b -= 5;
|
|
ab++;
|
|
|
|
a = ar;
|
|
*ab = *a++ * *b;
|
|
b += 3; /* r33 */
|
|
*ab += *a++ * *b;
|
|
b += 3;
|
|
*ab += *a++ * *b++;
|
|
bt = b;
|
|
ab++;
|
|
|
|
if (FacTr > 0) {
|
|
ar = rtmxa->a;
|
|
*ab = *ar++ * *b++; /* t1 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar++ * *b;
|
|
b = bt;
|
|
*ab += *a++ * FacAug;
|
|
*ab %= FacTr;
|
|
if (*ab < 0)
|
|
*ab += FacTr;
|
|
ab++;
|
|
|
|
*ab = *ar++ * *b++; /* t2 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar++ * *b;
|
|
b = bt;
|
|
*ab += *a++ * FacAug;
|
|
*ab %= FacTr;
|
|
if (*ab < 0)
|
|
*ab += FacTr;
|
|
ab++;
|
|
|
|
*ab = *ar++ * *b++; /* t3 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar * *b;
|
|
*ab += *a * FacAug;
|
|
*ab %= FacTr;
|
|
if (*ab < 0)
|
|
*ab += FacTr;
|
|
} else {
|
|
ar = rtmxa->a;
|
|
*ab = *ar++ * *b++; /* t1 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar++ * *b;
|
|
b = bt;
|
|
*ab += *a++ * FacAug;
|
|
ab++;
|
|
|
|
*ab = *ar++ * *b++; /* t2 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar++ * *b;
|
|
b = bt;
|
|
*ab += *a++ * FacAug;
|
|
ab++;
|
|
|
|
*ab = *ar++ * *b++; /* t3 */
|
|
*ab += *ar++ * *b++;
|
|
*ab += *ar * *b;
|
|
*ab += *a * FacAug;
|
|
}
|
|
}
|
|
|
|
|
|
void InverseRotMx(const int *RotMx, int *InvRotMx)
|
|
{
|
|
InvRotMx[0] = RotMx[4] * RotMx[8] - RotMx[5] * RotMx[7];
|
|
InvRotMx[1] = -RotMx[1] * RotMx[8] + RotMx[2] * RotMx[7];
|
|
InvRotMx[2] = RotMx[1] * RotMx[5] - RotMx[2] * RotMx[4];
|
|
InvRotMx[3] = -RotMx[3] * RotMx[8] + RotMx[5] * RotMx[6];
|
|
InvRotMx[4] = RotMx[0] * RotMx[8] - RotMx[2] * RotMx[6];
|
|
InvRotMx[5] = -RotMx[0] * RotMx[5] + RotMx[2] * RotMx[3];
|
|
InvRotMx[6] = RotMx[3] * RotMx[7] - RotMx[4] * RotMx[6];
|
|
InvRotMx[7] = -RotMx[0] * RotMx[7] + RotMx[1] * RotMx[6];
|
|
InvRotMx[8] = RotMx[0] * RotMx[4] - RotMx[1] * RotMx[3];
|
|
}
|
|
|
|
|
|
void InverseRTMx(const T_RTMx * RTMx, T_RTMx * InvRTMx)
|
|
{
|
|
int *iR;
|
|
const int *T;
|
|
|
|
|
|
iR = InvRTMx->s.R;
|
|
|
|
InverseRotMx(RTMx->s.R, iR);
|
|
|
|
T = RTMx->s.T;
|
|
|
|
InvRTMx->s.T[0] = -iR[0] * T[0] - iR[1] * T[1] - iR[2] * T[2];
|
|
InvRTMx->s.T[1] = -iR[3] * T[0] - iR[4] * T[1] - iR[5] * T[2];
|
|
InvRTMx->s.T[2] = -iR[6] * T[0] - iR[7] * T[1] - iR[8] * T[2];
|
|
}
|
|
|
|
|
|
int IsSMxTransl0(const T_LatticeInfo * LatticeInfo, const int *SeitzMxT)
|
|
{
|
|
int iTrV, nTrV, t;
|
|
const int *TrV;
|
|
|
|
|
|
nTrV = LatticeInfo->nTrVector;
|
|
TrV = LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++) {
|
|
t = (SeitzMxT[0] + TrV[0]) % STBF;
|
|
if (t == 0) {
|
|
t = (SeitzMxT[1] + TrV[1]) % STBF;
|
|
if (t == 0) {
|
|
t = (SeitzMxT[2] + TrV[2]) % STBF;
|
|
if (t == 0)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
TrV += 3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int IsSpecialSeitzMx(T_SgInfo * SgInfo, const T_RTMx * SMx,
|
|
int ExpandLT)
|
|
{
|
|
int i, special, smx11;
|
|
const T_LatticeInfo *ExpLT;
|
|
|
|
|
|
/* check rotation part for identity or inversion operation */
|
|
|
|
smx11 = SMx->s.R[0];
|
|
if (smx11 != 1 && smx11 != -1)
|
|
return 0;
|
|
|
|
for (i = 1; i < 9; i++) {
|
|
if (i % 4) {
|
|
if (SMx->s.R[i] != 0)
|
|
return 0;
|
|
} else {
|
|
if (SMx->s.R[i] != smx11)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (smx11 == 1)
|
|
special = SpecialSMx_Identity;
|
|
else
|
|
special = SpecialSMx_Inversion;
|
|
|
|
/* rotation part is identity or inversion
|
|
check translation part now
|
|
*/
|
|
|
|
if (IsSMxTransl0(SgInfo->LatticeInfo, SMx->s.T) == 1)
|
|
return (special | SpecialSMx_Transl0);
|
|
|
|
if (ExpandLT && (smx11 == 1 || SgInfo->Centric)) {
|
|
/* try to expand lattice type */
|
|
|
|
ExpLT = NULL;
|
|
|
|
switch (SgInfo->LatticeInfo->Code) {
|
|
case 'P':
|
|
if (IsSMxTransl0(LI_A, SMx->s.T) == 1) {
|
|
ExpLT = LI_A;
|
|
break;
|
|
}
|
|
if (IsSMxTransl0(LI_B, SMx->s.T) == 1) {
|
|
ExpLT = LI_B;
|
|
break;
|
|
}
|
|
if (IsSMxTransl0(LI_C, SMx->s.T) == 1) {
|
|
ExpLT = LI_C;
|
|
break;
|
|
}
|
|
if (IsSMxTransl0(LI_I, SMx->s.T) == 1) {
|
|
ExpLT = LI_I;
|
|
break;
|
|
}
|
|
if (IsSMxTransl0(LI_R, SMx->s.T) == 1) {
|
|
ExpLT = LI_R;
|
|
break;
|
|
}
|
|
if (IsSMxTransl0(LI_S, SMx->s.T) == 1) {
|
|
ExpLT = LI_S;
|
|
break;
|
|
}
|
|
if (IsSMxTransl0(LI_T, SMx->s.T) == 1) {
|
|
ExpLT = LI_T;
|
|
break;
|
|
}
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
if (IsSMxTransl0(LI_F, SMx->s.T) == 1)
|
|
ExpLT = LI_F;
|
|
}
|
|
|
|
if (ExpLT != NULL) {
|
|
SgInfo->LatticeInfo = ExpLT;
|
|
SgInfo->StatusLatticeTr = -1;
|
|
return (special | SpecialSMx_Transl0);
|
|
}
|
|
}
|
|
|
|
return special;
|
|
}
|
|
|
|
|
|
int CompareSeitzMx(const T_LatticeInfo * LatticeInfo,
|
|
const T_RTMx * SeitzMxA, const T_RTMx * SeitzMxB)
|
|
{
|
|
int i, iTrV, nTrV, t;
|
|
const int *TrV;
|
|
|
|
|
|
/* compare rotation part */
|
|
|
|
for (i = 0; i < 9; i++)
|
|
if (SeitzMxA->s.R[i] != SeitzMxB->s.R[i])
|
|
return 1;
|
|
|
|
/* rotation part is same
|
|
check translation
|
|
*/
|
|
|
|
nTrV = LatticeInfo->nTrVector;
|
|
TrV = LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++, TrV += 3) {
|
|
t = (SeitzMxA->s.T[0] + TrV[0]) % STBF;
|
|
if (t == SeitzMxB->s.T[0]) {
|
|
t = (SeitzMxA->s.T[1] + TrV[1]) % STBF;
|
|
if (t == SeitzMxB->s.T[1]) {
|
|
t = (SeitzMxA->s.T[2] + TrV[2]) % STBF;
|
|
if (t == SeitzMxB->s.T[2])
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int GetRotMxOrder(const int *RotMx)
|
|
{
|
|
int deter = deterRotMx(RotMx);
|
|
|
|
if (deter == -1 || deter == 1) {
|
|
switch (traceRotMx(RotMx)) {
|
|
case -3:
|
|
return -1;
|
|
case -2:
|
|
return -6;
|
|
case -1:
|
|
if (deter == -1)
|
|
return -4;
|
|
else
|
|
return 2;
|
|
case 0:
|
|
if (deter == -1)
|
|
return -3;
|
|
else
|
|
return 3;
|
|
case 1:
|
|
if (deter == -1)
|
|
return -2;
|
|
else
|
|
return 4;
|
|
case 2:
|
|
return 6;
|
|
case 3:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int nNextBasis_of_DirCode(const int DirCode,
|
|
const int **RMx, const int **InvRMx)
|
|
{
|
|
switch (DirCode) {
|
|
case '.':
|
|
*RMx = *InvRMx = NULL;
|
|
return 1;
|
|
case '=':
|
|
case '"':
|
|
case '\'':
|
|
case '|':
|
|
case '\\':
|
|
*RMx = RMx_3_111;
|
|
*InvRMx = RMx_3i111;
|
|
return 3;
|
|
case '*':
|
|
*RMx = RMx_4_001;
|
|
*InvRMx = RMx_4i001;
|
|
return 4;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SetSgError("Internal Error: Corrupt DirCode");
|
|
return -1;
|
|
}
|
|
|
|
|
|
int GetRotMxInfo(const int *RotMx, T_RotMxInfo * RotMxInfo)
|
|
{
|
|
int i;
|
|
int nNextBasis, iNextBasis;
|
|
int nLoopInv, iLoopInv;
|
|
int Order, AbsOrder;
|
|
int RMxCopy[9], MatchMx[9], InvMatchMx[9], REV[3];
|
|
int *mmx;
|
|
const int *NBRMx, *InvNBRMx;
|
|
|
|
const T_TabXtalRotMx *txrmx;
|
|
|
|
|
|
Order = GetRotMxOrder(RotMx);
|
|
|
|
if (RotMxInfo)
|
|
RotMxInfo->Order = Order;
|
|
|
|
if (Order) {
|
|
AbsOrder = abs(Order);
|
|
|
|
if (Order > 0)
|
|
for (i = 0; i < 9; i++)
|
|
RMxCopy[i] = RotMx[i];
|
|
else
|
|
for (i = 0; i < 9; i++)
|
|
RMxCopy[i] = -RotMx[i];
|
|
|
|
for (txrmx = TabXtalRotMx; txrmx->Order; txrmx++)
|
|
if (txrmx->Order == AbsOrder)
|
|
break;
|
|
|
|
while (txrmx->Order == AbsOrder) {
|
|
nNextBasis =
|
|
nNextBasis_of_DirCode(txrmx->DirCode, &NBRMx, &InvNBRMx);
|
|
|
|
if (nNextBasis < 0)
|
|
return 0;
|
|
|
|
if (AbsOrder > 2)
|
|
nLoopInv = 2;
|
|
else
|
|
nLoopInv = 1;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
MatchMx[i] = txrmx->RMx[i];
|
|
|
|
for (iNextBasis = 0; iNextBasis < nNextBasis; iNextBasis++) {
|
|
if (iNextBasis)
|
|
RotateRotMx(MatchMx, NBRMx, InvNBRMx);
|
|
|
|
mmx = MatchMx;
|
|
|
|
for (iLoopInv = 0; iLoopInv < nLoopInv; iLoopInv++) {
|
|
if (iLoopInv) {
|
|
InverseRotMx(MatchMx, InvMatchMx);
|
|
mmx = InvMatchMx;
|
|
}
|
|
|
|
for (i = 0; i < 9; i++)
|
|
if (mmx[i] != RMxCopy[i])
|
|
break;
|
|
|
|
if (i == 9) { /* matrix has been found */
|
|
if (RotMxInfo) {
|
|
RotMxInfo->Inverse = iLoopInv;
|
|
|
|
if (nNextBasis == 3) {
|
|
switch (iNextBasis) {
|
|
case 0:
|
|
RotMxInfo->RefAxis = 'z';
|
|
break;
|
|
case 1:
|
|
RotMxInfo->RefAxis = 'x';
|
|
break;
|
|
case 2:
|
|
RotMxInfo->RefAxis = 'y';
|
|
break;
|
|
}
|
|
} else
|
|
RotMxInfo->RefAxis = 'o';
|
|
|
|
RotMxInfo->DirCode = txrmx->DirCode;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
RotMxInfo->EigenVector[i] = txrmx->EigenVector[i];
|
|
|
|
for (; iNextBasis--;) {
|
|
RotMx_t_Vector(REV, NBRMx, RotMxInfo->EigenVector, 0);
|
|
|
|
if (iNextBasis-- == 0) {
|
|
for (i = 0; i < 3; i++)
|
|
RotMxInfo->EigenVector[i] = REV[i];
|
|
|
|
break;
|
|
}
|
|
|
|
RotMx_t_Vector(RotMxInfo->EigenVector, NBRMx, REV, 0);
|
|
}
|
|
}
|
|
|
|
return Order;
|
|
}
|
|
}
|
|
}
|
|
|
|
txrmx++;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
const T_RotMxInfo *ListOrBufRotMxInfo(const T_SgInfo * SgInfo, int iList,
|
|
T_RotMxInfo * BufRotMxInfo)
|
|
{
|
|
T_RotMxInfo *RMxI;
|
|
|
|
|
|
RMxI = SgInfo->ListRotMxInfo;
|
|
if (RMxI)
|
|
RMxI += iList;
|
|
else {
|
|
RMxI = BufRotMxInfo;
|
|
|
|
if (GetRotMxInfo(SgInfo->ListSeitzMx[iList].s.R, RMxI) == 0) {
|
|
SetSgError(Err_Ill_SMx_in_List);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return RMxI;
|
|
}
|
|
|
|
|
|
static int CoreAdd2ListSeitzMx(T_SgInfo * SgInfo, const T_RTMx * NewSMx)
|
|
{
|
|
int i, iList;
|
|
T_RTMx *lsmx;
|
|
T_RotMxInfo RotMxInfo;
|
|
const T_LatticeInfo *LI;
|
|
|
|
static const char *Err_NonXtalOp =
|
|
"Error: Generators produce non-crystallographic operation";
|
|
|
|
|
|
if (SgInfo->GenOption)
|
|
LI = SgInfo->LatticeInfo;
|
|
else
|
|
LI = LI_P;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++)
|
|
if (CompareSeitzMx(LI, NewSMx, lsmx) == 0)
|
|
return 0; /* matrix is not unique */
|
|
|
|
if (GetRotMxInfo(NewSMx->s.R, &RotMxInfo) == 0) {
|
|
SetSgError(Err_NonXtalOp);
|
|
return -1;
|
|
}
|
|
|
|
if (SgInfo->nList >= SgInfo->MaxList) {
|
|
if (SgInfo->nList >= 192)
|
|
SetSgError(Err_NonXtalOp);
|
|
else
|
|
SetSgError
|
|
("Internal Error: Allocated space for ListSeitzMx too small");
|
|
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < 12; i++)
|
|
lsmx->a[i] = NewSMx->a[i];
|
|
|
|
if (SgInfo->ListRotMxInfo != NULL)
|
|
CopyRotMxInfo(&SgInfo->ListRotMxInfo[SgInfo->nList], &RotMxInfo);
|
|
|
|
SgInfo->nList++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int Add2ListSeitzMx(T_SgInfo * SgInfo, const T_RTMx * NewSMx)
|
|
{
|
|
int i, special, Enter;
|
|
int iMult, jMult;
|
|
T_RTMx TrialSMx, *iMultSMx, *jMultSMx;
|
|
|
|
static const char *Err_Ill_lattice_translation =
|
|
"Error: Illegal lattice translation";
|
|
|
|
|
|
if (SgInfo->nList == 0) {
|
|
/* make sure identity matrix is first in list */
|
|
|
|
InitSeitzMx(&TrialSMx, 1);
|
|
|
|
if (CoreAdd2ListSeitzMx(SgInfo, &TrialSMx) < 0)
|
|
return -1;;
|
|
}
|
|
|
|
for (i = 0; i < 9; i++)
|
|
TrialSMx.s.R[i] = NewSMx->s.R[i];
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
TrialSMx.s.T[i] = NewSMx->s.T[i] % STBF;
|
|
if (TrialSMx.s.T[i] < 0)
|
|
TrialSMx.s.T[i] += STBF;
|
|
}
|
|
|
|
iMult = SgInfo->nList;
|
|
iMultSMx = &SgInfo->ListSeitzMx[iMult];
|
|
|
|
jMult = 1;
|
|
jMultSMx = &SgInfo->ListSeitzMx[1]; /* skip first = identity matrix */
|
|
|
|
for (;;) {
|
|
Enter = 1;
|
|
|
|
special = IsSpecialSeitzMx(SgInfo, &TrialSMx, 1);
|
|
|
|
if (special & SpecialSMx_Identity) {
|
|
if (!(special & SpecialSMx_Transl0)) {
|
|
SetSgError(Err_Ill_lattice_translation);
|
|
return -1;
|
|
}
|
|
|
|
if (SgInfo->GenOption)
|
|
Enter = 0;
|
|
} else if (special & SpecialSMx_Inversion) {
|
|
if (!(special & SpecialSMx_Transl0)) {
|
|
if (SgInfo->Centric) {
|
|
SetSgError(Err_Ill_lattice_translation);
|
|
return -1;
|
|
}
|
|
|
|
SgInfo->InversionOffOrigin = 1;
|
|
} else {
|
|
if (SgInfo->InversionOffOrigin)
|
|
SgInfo->Centric = 1;
|
|
|
|
SgInfo->InversionOffOrigin = 0;
|
|
|
|
if (SgInfo->GenOption) {
|
|
if (SgInfo->Centric == 0)
|
|
SgInfo->Centric = -1;
|
|
|
|
Enter = 0;
|
|
} else
|
|
SgInfo->Centric = 1;
|
|
}
|
|
}
|
|
|
|
if (Enter && CoreAdd2ListSeitzMx(SgInfo, &TrialSMx) < 0)
|
|
return -1;
|
|
|
|
if (SgInfo->GenOption < 0)
|
|
break;
|
|
|
|
if (jMult > iMult) {
|
|
iMult++;
|
|
iMultSMx++;
|
|
|
|
jMult = 1;
|
|
jMultSMx = &SgInfo->ListSeitzMx[1]; /* skip first = identity matrix */
|
|
}
|
|
|
|
if (iMult == SgInfo->nList)
|
|
break;
|
|
|
|
SeitzMxMultiply(&TrialSMx, jMultSMx, iMultSMx);
|
|
|
|
jMult++;
|
|
jMultSMx++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int AddInversion2ListSeitzMx(T_SgInfo * SgInfo)
|
|
{
|
|
T_RTMx SeitzMx;
|
|
|
|
InitSeitzMx(&SeitzMx, -1);
|
|
return Add2ListSeitzMx(SgInfo, &SeitzMx);
|
|
}
|
|
|
|
|
|
int AddLatticeTr2ListSeitzMx(T_SgInfo * SgInfo,
|
|
const T_LatticeInfo * LatticeInfo)
|
|
{
|
|
int iTrV, nTrV;
|
|
const int *TrV;
|
|
T_RTMx SeitzMx;
|
|
|
|
|
|
InitRotMx(SeitzMx.s.R, 1);
|
|
|
|
nTrV = LatticeInfo->nTrVector;
|
|
TrV = &LatticeInfo->TrVector[3]; /* skip first vector which is always 000 */
|
|
|
|
for (iTrV = 1; iTrV < nTrV; iTrV++) {
|
|
SeitzMx.s.T[0] = *TrV++;
|
|
SeitzMx.s.T[1] = *TrV++;
|
|
SeitzMx.s.T[2] = *TrV++;
|
|
|
|
if (Add2ListSeitzMx(SgInfo, &SeitzMx) < 0)
|
|
return -1;
|
|
}
|
|
|
|
if (SgInfo->GenOption)
|
|
SgInfo->StatusLatticeTr = 0;
|
|
else
|
|
SgInfo->StatusLatticeTr = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int RemoveLatticeTr(T_SgInfo * SgInfo)
|
|
{
|
|
int iList, jList, i;
|
|
T_RTMx *smxi, *smxj, *lastsmx;
|
|
T_RotMxInfo *lrmxi, *lastrmxi;
|
|
|
|
|
|
if (SgInfo->LatticeInfo->Code == 'P')
|
|
return 0;
|
|
|
|
if (SgInfo->StatusLatticeTr == -1) {
|
|
if (AddLatticeTr2ListSeitzMx(SgInfo, SgInfo->LatticeInfo) < 0)
|
|
return -1;
|
|
}
|
|
|
|
iList = 0;
|
|
|
|
while (iList < SgInfo->nList) {
|
|
smxi = &SgInfo->ListSeitzMx[iList];
|
|
jList = iList + 1;
|
|
|
|
while (jList < SgInfo->nList) {
|
|
smxj = &SgInfo->ListSeitzMx[jList];
|
|
|
|
if (CompareSeitzMx(SgInfo->LatticeInfo, smxi, smxj) == 0) {
|
|
/* copy last element to this place */
|
|
|
|
SgInfo->nList--;
|
|
lastsmx = &SgInfo->ListSeitzMx[SgInfo->nList];
|
|
for (i = 0; i < 12; i++)
|
|
smxj->a[i] = lastsmx->a[i];
|
|
|
|
if (SgInfo->ListRotMxInfo != NULL) {
|
|
lrmxi = &SgInfo->ListRotMxInfo[jList];
|
|
lastrmxi = &SgInfo->ListRotMxInfo[SgInfo->nList];
|
|
CopyRotMxInfo(lrmxi, lastrmxi);
|
|
}
|
|
} else
|
|
jList++;
|
|
}
|
|
|
|
iList++;
|
|
}
|
|
|
|
SgInfo->StatusLatticeTr = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int RemoveInversion(T_SgInfo * SgInfo)
|
|
{
|
|
int i, iList, special, deter, Centric, InversionOffOrigin;
|
|
T_RTMx *lsmx, *smx, ProperSMx;
|
|
T_RotMxInfo *lrmxi, *rmxi;
|
|
|
|
|
|
Centric = 0;
|
|
InversionOffOrigin = 0;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
special = IsSpecialSeitzMx(SgInfo, lsmx, 0);
|
|
|
|
if (special & SpecialSMx_Inversion) {
|
|
if (special & SpecialSMx_Transl0)
|
|
Centric = 1;
|
|
else
|
|
InversionOffOrigin = 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (InversionOffOrigin && Centric) {
|
|
SetSgError("Internal Error: Corrupt SgInfo");
|
|
return -1;
|
|
}
|
|
|
|
if (Centric == 0) {
|
|
if (InversionOffOrigin) {
|
|
SgInfo->Centric = 0;
|
|
SgInfo->InversionOffOrigin = 1;
|
|
} else {
|
|
if (SgInfo->Centric)
|
|
SgInfo->Centric = -1;
|
|
SgInfo->InversionOffOrigin = 0;
|
|
}
|
|
} else {
|
|
SgInfo->InversionOffOrigin = 0;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
lrmxi = SgInfo->ListRotMxInfo;
|
|
iList = 0;
|
|
|
|
while (iList < SgInfo->nList) {
|
|
deter = deterRotMx(lsmx->s.R);
|
|
|
|
if (deter == -1 && SgInfo->Centric == -1) {
|
|
for (i = 0; i < 9; i++)
|
|
ProperSMx.s.R[i] = -lsmx->s.R[i];
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
ProperSMx.s.T[i] = -lsmx->s.T[i] % STBF;
|
|
if (ProperSMx.s.T[i] < 0)
|
|
ProperSMx.s.T[i] += STBF;
|
|
}
|
|
|
|
smx = SgInfo->ListSeitzMx;
|
|
|
|
for (i = 0; i < SgInfo->nList; i++, smx++)
|
|
if (CompareSeitzMx(LI_P, &ProperSMx, smx) == 0)
|
|
break;
|
|
|
|
if (i == SgInfo->nList) {
|
|
for (i = 0; i < 12; i++)
|
|
lsmx->a[i] = ProperSMx.a[i];
|
|
|
|
deter = deterRotMx(lsmx->s.R);
|
|
|
|
if (deter != 1 || (lrmxi && GetRotMxInfo(lsmx->s.R, lrmxi) == 0)) {
|
|
SetSgError(Err_Ill_SMx_in_List);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (deter == -1) {
|
|
/* copy last element to this place */
|
|
|
|
SgInfo->nList--;
|
|
if (SgInfo->nList != iList) {
|
|
smx = &SgInfo->ListSeitzMx[SgInfo->nList];
|
|
for (i = 0; i < 12; i++)
|
|
lsmx->a[i] = smx->a[i];
|
|
|
|
if (lrmxi) {
|
|
rmxi = &SgInfo->ListRotMxInfo[SgInfo->nList];
|
|
CopyRotMxInfo(lrmxi, rmxi);
|
|
}
|
|
}
|
|
} else if (deter == 1) {
|
|
lsmx++;
|
|
if (lrmxi != NULL)
|
|
lrmxi++;
|
|
iList++;
|
|
} else {
|
|
SetSgError(Err_Ill_SMx_in_List);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
SgInfo->Centric = -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int ApplyOriginShift(T_SgInfo * SgInfo)
|
|
{
|
|
int HaveOrSh, iList, i;
|
|
T_RTMx *lsmx, SMx;
|
|
int OrSh[3], lo[3];
|
|
|
|
|
|
HaveOrSh = 0;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
OrSh[i] = SgInfo->OriginShift[i] * (STBF / 12);
|
|
if (OrSh[i])
|
|
HaveOrSh = 1;
|
|
}
|
|
|
|
if (HaveOrSh == 0)
|
|
return 0;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
RotMx_t_Vector(lo, lsmx->s.R, OrSh, STBF);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
lsmx->s.T[i] = iModPositive(lsmx->s.T[i] - lo[i] + OrSh[i], STBF);
|
|
}
|
|
|
|
if (SgInfo->Centric == -1) {
|
|
lsmx = &SMx;
|
|
|
|
InitSeitzMx(lsmx, -1);
|
|
|
|
RotMx_t_Vector(lo, lsmx->s.R, OrSh, STBF);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
lsmx->s.T[i] = iModPositive(lsmx->s.T[i] - lo[i] + OrSh[i], STBF);
|
|
|
|
if (CoreAdd2ListSeitzMx(SgInfo, lsmx) < 0)
|
|
return -1;
|
|
|
|
SgInfo->Centric = 0;
|
|
SgInfo->InversionOffOrigin = 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void TidyTranslation(T_SgInfo * SgInfo)
|
|
{
|
|
int iList;
|
|
int iTrV, nTrV;
|
|
const int *TrV;
|
|
T_RTMx *lsmx;
|
|
int t1, t2, t3, *lt1, *lt2, *lt3, mint1, mint2, mint3;
|
|
int n0t, n0mint;
|
|
|
|
|
|
nTrV = SgInfo->LatticeInfo->nTrVector;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
mint1 = *(lt1 = &lsmx->s.T[0]);
|
|
mint2 = *(lt2 = &lsmx->s.T[1]);
|
|
mint3 = *(lt3 = &lsmx->s.T[2]);
|
|
|
|
TrV = SgInfo->LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++) {
|
|
t1 = ((*lt1) + *TrV++) % STBF;
|
|
t2 = ((*lt2) + *TrV++) % STBF;
|
|
t3 = ((*lt3) + *TrV++) % STBF;
|
|
|
|
n0t = (t1 == 0) + (t2 == 0) + (t3 == 0);
|
|
n0mint = (mint1 == 0) + (mint2 == 0) + (mint3 == 0);
|
|
|
|
if (n0t > n0mint
|
|
|| (n0t == n0mint
|
|
&& (t1 + t2 + t3 < mint1 + mint2 + mint3
|
|
|| (t1 + t2 + t3 == mint1 + mint2 + mint3
|
|
&& (t1 < mint1 || (t1 == mint1 && t2 < mint2)))))) {
|
|
mint1 = t1;
|
|
mint2 = t2;
|
|
mint3 = t3;
|
|
}
|
|
}
|
|
|
|
*lt1 = mint1;
|
|
*lt2 = mint2;
|
|
*lt3 = mint3;
|
|
}
|
|
}
|
|
|
|
|
|
static T_SgInfo *Pt_SgInfo_ListSortFunction = NULL;
|
|
|
|
static int SgInfoListSortFunction(const int *iList_a, const int *iList_b)
|
|
{
|
|
int val_a, val_b, n0_a, n0_b, i;
|
|
T_RTMx *smx_a, *smx_b;
|
|
T_RotMxInfo RotMxInfo_a, RotMxInfo_b, *rmxi_a, *rmxi_b;
|
|
T_SgInfo *SgInfo = Pt_SgInfo_ListSortFunction;
|
|
|
|
|
|
if (SgError != NULL)
|
|
return 0;
|
|
|
|
if (SgInfo->ListRotMxInfo == NULL) {
|
|
rmxi_a = &RotMxInfo_a;
|
|
rmxi_b = &RotMxInfo_b;
|
|
|
|
smx_a = &SgInfo->ListSeitzMx[*iList_a];
|
|
smx_b = &SgInfo->ListSeitzMx[*iList_b];
|
|
|
|
if (GetRotMxInfo(smx_a->s.R, rmxi_a) == 0
|
|
|| GetRotMxInfo(smx_b->s.R, rmxi_b) == 0) {
|
|
SetSgError(Err_Ill_SMx_in_List);
|
|
return 0;
|
|
}
|
|
} else {
|
|
rmxi_a = &SgInfo->ListRotMxInfo[*iList_a];
|
|
rmxi_b = &SgInfo->ListRotMxInfo[*iList_b];
|
|
}
|
|
|
|
val_a = abs(rmxi_a->Order);
|
|
val_b = abs(rmxi_b->Order);
|
|
|
|
if (val_a == 1 && val_b != 1)
|
|
return -1;
|
|
if (val_a != 1 && val_b == 1)
|
|
return 1;
|
|
if (rmxi_a->Order == 1 && rmxi_b->Order != 1)
|
|
return -1;
|
|
if (rmxi_a->Order != 1 && rmxi_b->Order == 1)
|
|
return 1;
|
|
|
|
if (val_a != 1) {
|
|
if (val_a > val_b)
|
|
return -1;
|
|
if (val_a < val_b)
|
|
return 1;
|
|
if (rmxi_a->Order > rmxi_b->Order)
|
|
return -1;
|
|
if (rmxi_a->Order < rmxi_b->Order)
|
|
return 1;
|
|
}
|
|
|
|
n0_a = n0_b = 0;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (rmxi_a->EigenVector[i] == 0)
|
|
n0_a++;
|
|
if (rmxi_b->EigenVector[i] == 0)
|
|
n0_b++;
|
|
}
|
|
if (n0_a > n0_b)
|
|
return -1;
|
|
if (n0_a < n0_b)
|
|
return 1;
|
|
|
|
val_a = val_b = 0;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (val_a < abs(rmxi_a->EigenVector[i]))
|
|
val_a = abs(rmxi_a->EigenVector[i]);
|
|
if (val_b < abs(rmxi_b->EigenVector[i]))
|
|
val_b = abs(rmxi_b->EigenVector[i]);
|
|
}
|
|
if (val_a < val_b)
|
|
return -1;
|
|
if (val_a > val_b)
|
|
return 1;
|
|
|
|
val_a = 100 * abs(rmxi_a->EigenVector[2]);
|
|
val_a += 10 * abs(rmxi_a->EigenVector[0]);
|
|
val_a += abs(rmxi_a->EigenVector[1]);
|
|
val_b = 100 * abs(rmxi_b->EigenVector[2]);
|
|
val_b += 10 * abs(rmxi_b->EigenVector[0]);
|
|
val_b += abs(rmxi_b->EigenVector[1]);
|
|
|
|
if (n0_a < 2) {
|
|
if (val_a < val_b)
|
|
return -1;
|
|
if (val_a > val_b)
|
|
return 1;
|
|
} else {
|
|
if (val_a > val_b)
|
|
return -1;
|
|
if (val_a < val_b)
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (rmxi_a->EigenVector[i] > rmxi_b->EigenVector[i])
|
|
return -1;
|
|
if (rmxi_a->EigenVector[i] < rmxi_b->EigenVector[i])
|
|
return 1;
|
|
}
|
|
|
|
if (rmxi_a->Inverse < rmxi_b->Inverse)
|
|
return -1;
|
|
if (rmxi_a->Inverse > rmxi_b->Inverse)
|
|
return 1;
|
|
|
|
smx_a = &SgInfo->ListSeitzMx[*iList_a];
|
|
smx_b = &SgInfo->ListSeitzMx[*iList_b];
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (smx_a->s.T[i] < smx_b->s.T[i])
|
|
return -1;
|
|
if (smx_a->s.T[i] > smx_b->s.T[i])
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int PostSortSgInfoList(const T_SgInfo * SgInfo, int *List_iList)
|
|
{
|
|
int nList, iL_iL, jL_iL;
|
|
T_RTMx BufMx1, BufMx2, *smxab;
|
|
const T_RTMx *lsmx, *smxb;
|
|
T_RotMxInfo RotMxInfo;
|
|
const T_RotMxInfo *rmxi;
|
|
int nO_1, iO, save, i, i_;
|
|
|
|
|
|
nList = SgInfo->nList;
|
|
|
|
iL_iL = 0;
|
|
|
|
while (iL_iL < nList) {
|
|
lsmx = &SgInfo->ListSeitzMx[List_iList[iL_iL]];
|
|
|
|
rmxi = ListOrBufRotMxInfo(SgInfo, List_iList[iL_iL], &RotMxInfo);
|
|
if (rmxi == NULL)
|
|
return -1;
|
|
|
|
iL_iL++;
|
|
|
|
iO = rmxi->Order;
|
|
if (iO < 0 && iO % 2)
|
|
iO *= 2;
|
|
nO_1 = abs(iO) - 1;
|
|
|
|
smxab = &BufMx2;
|
|
smxb = lsmx;
|
|
|
|
for (iO = 1; iO < nO_1; iO++) {
|
|
SeitzMxMultiply(smxab, lsmx, smxb);
|
|
|
|
for (jL_iL = iL_iL; jL_iL < nList; jL_iL++) {
|
|
smxb = &SgInfo->ListSeitzMx[List_iList[jL_iL]];
|
|
if (CompareSeitzMx(SgInfo->LatticeInfo, smxab, smxb) == 0)
|
|
break;
|
|
}
|
|
|
|
if (jL_iL < nList) {
|
|
save = List_iList[jL_iL];
|
|
|
|
for (i = i_ = jL_iL; i > iL_iL; i = i_)
|
|
List_iList[i] = List_iList[--i_];
|
|
|
|
List_iList[iL_iL++] = save;
|
|
}
|
|
|
|
smxb = smxab;
|
|
if (iO % 2)
|
|
smxab = &BufMx1;
|
|
else
|
|
smxab = &BufMx2;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void SortSgInfoList(T_SgInfo * SgInfo, int *List_iList)
|
|
{
|
|
int i, j, refi;
|
|
int nList;
|
|
T_RTMx *lsmx;
|
|
T_RotMxInfo *lrmxi;
|
|
|
|
|
|
if (SgError != NULL)
|
|
return;
|
|
|
|
nList = SgInfo->nList;
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
lrmxi = SgInfo->ListRotMxInfo;
|
|
Pt_SgInfo_ListSortFunction = SgInfo;
|
|
|
|
for (i = 0; i < nList; i++)
|
|
List_iList[i] = i;
|
|
|
|
qsort((void *) List_iList, nList, sizeof(*List_iList),
|
|
(int (*)(const void *, const void *)) SgInfoListSortFunction);
|
|
|
|
Pt_SgInfo_ListSortFunction = NULL;
|
|
if (SgError != NULL)
|
|
return;
|
|
|
|
if (PostSortSgInfoList(SgInfo, List_iList) != 0)
|
|
return;
|
|
|
|
for (i = 0; i < nList; i++) {
|
|
j = List_iList[i];
|
|
|
|
if (j != i) {
|
|
for (refi = i + 1; refi < nList; refi++)
|
|
if (List_iList[refi] == i)
|
|
break;
|
|
|
|
if (refi >= nList) {
|
|
SetSgError("Internal Error: SortSgInfoList(): Corrupt List_iList");
|
|
return;
|
|
}
|
|
|
|
SwapRTMx(&lsmx[i], &lsmx[j]);
|
|
if (lrmxi != NULL)
|
|
SwapRotMxInfo(&lrmxi[i], &lrmxi[j]);
|
|
|
|
List_iList[refi] = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int FindSeitzMx(const T_SgInfo * SgInfo,
|
|
int Order, int HonorSign, int RefAxis, int DirCode)
|
|
{
|
|
int iList;
|
|
int MatchingOrder;
|
|
T_RTMx *lsmx;
|
|
T_RotMxInfo *lrmxi, RotMxInfo;
|
|
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
lrmxi = SgInfo->ListRotMxInfo;
|
|
|
|
if (lrmxi == NULL)
|
|
lrmxi = &RotMxInfo;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
if (lrmxi == &RotMxInfo) {
|
|
if (GetRotMxInfo(lsmx->s.R, lrmxi) == 0) {
|
|
SetSgError(Err_Ill_SMx_in_List);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (HonorSign == 0)
|
|
MatchingOrder = (abs(Order) == abs(lrmxi->Order));
|
|
else
|
|
MatchingOrder = (Order == lrmxi->Order);
|
|
|
|
if (MatchingOrder
|
|
&& lrmxi->Inverse == 0
|
|
&& (RefAxis == 0 || RefAxis == lrmxi->RefAxis)
|
|
&& (DirCode == 0 || DirCode == lrmxi->DirCode)) {
|
|
if (DirCode != '*')
|
|
return iList;
|
|
|
|
if (lrmxi->EigenVector[0] == 1
|
|
&& lrmxi->EigenVector[1] == 1 && lrmxi->EigenVector[2] == 1)
|
|
return iList;
|
|
}
|
|
|
|
if (lrmxi != &RotMxInfo)
|
|
lrmxi++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int FindXtalSystem(T_SgInfo * SgInfo)
|
|
{
|
|
int iList, i;
|
|
int HonorSign = 0, CheckEnantiomorph;
|
|
const T_RTMx *lsmx;
|
|
T_RotMxInfo RotMxInfo;
|
|
const T_RotMxInfo *lrmxi;
|
|
|
|
enum Axis { N1 = 0, N2, N3, N4, N6, EndOfAxis };
|
|
int N_count[EndOfAxis];
|
|
|
|
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
SgInfo->UniqueRefAxis = 0;
|
|
SgInfo->UniqueDirCode = 0;
|
|
SgInfo->ExtraInfo = EI_Unknown;
|
|
|
|
CheckEnantiomorph = 0;
|
|
|
|
for (i = 0; i < EndOfAxis; i++)
|
|
N_count[i] = 0;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
lrmxi = SgInfo->ListRotMxInfo;
|
|
|
|
if (lrmxi == NULL)
|
|
lrmxi = &RotMxInfo;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
if (lrmxi == &RotMxInfo) {
|
|
if (GetRotMxInfo(lsmx->s.R, &RotMxInfo) == 0) {
|
|
SetSgError(Err_Ill_SMx_in_List);
|
|
return XS_Unknown;
|
|
}
|
|
}
|
|
|
|
switch (abs(lrmxi->Order)) {
|
|
case 1:
|
|
i = N1;
|
|
break;
|
|
case 2:
|
|
i = N2;
|
|
break;
|
|
case 3:
|
|
i = N3;
|
|
break;
|
|
case 4:
|
|
i = N4;
|
|
break;
|
|
case 6:
|
|
i = N6;
|
|
break;
|
|
default:
|
|
SetSgError
|
|
("Internal Error: FindXtalSystem(): Corrupt ListRotMxInfo");
|
|
return XS_Unknown;
|
|
}
|
|
|
|
if (lrmxi->Inverse == 0) /* skip N^-1 */
|
|
N_count[i]++;
|
|
|
|
if (lrmxi != &RotMxInfo)
|
|
lrmxi++;
|
|
}
|
|
|
|
i = EndOfAxis;
|
|
|
|
if (SgInfo->InversionOffOrigin == 1) {
|
|
for (i = 0; i < EndOfAxis; i++) {
|
|
if (N_count[i] % 2)
|
|
break;
|
|
N_count[i] /= 2;
|
|
}
|
|
}
|
|
|
|
if (i == EndOfAxis) {
|
|
if (N_count[N3] == 4)
|
|
SgInfo->XtalSystem = XS_Cubic;
|
|
else if (N_count[N3] > 1)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
else if (N_count[N6] == 1)
|
|
SgInfo->XtalSystem = XS_Hexagonal;
|
|
else if (N_count[N6] > 0)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
else if (N_count[N3] == 1)
|
|
SgInfo->XtalSystem = XS_Trigonal;
|
|
else if (N_count[N4] == 1)
|
|
SgInfo->XtalSystem = XS_Tetragonal;
|
|
else if (N_count[N4] > 0)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
else if (N_count[N2] > 2)
|
|
SgInfo->XtalSystem = XS_Orthorhombic;
|
|
else if (N_count[N2] > 0)
|
|
SgInfo->XtalSystem = XS_Monoclinic;
|
|
else if (N_count[N1] > 0)
|
|
SgInfo->XtalSystem = XS_Triclinic;
|
|
|
|
HonorSign = 1;
|
|
iList = FindSeitzMx(SgInfo, -1, HonorSign, 'o', '.');
|
|
if (iList < 0)
|
|
HonorSign = 0;
|
|
|
|
switch (SgInfo->XtalSystem) {
|
|
case XS_Monoclinic:
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 0, '=');
|
|
if (iList < 0)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
break;
|
|
case XS_Tetragonal:
|
|
CheckEnantiomorph = 1;
|
|
iList = FindSeitzMx(SgInfo, 4, HonorSign, 0, '=');
|
|
if (iList < 0)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
break;
|
|
case XS_Trigonal:
|
|
CheckEnantiomorph = 1;
|
|
iList = FindSeitzMx(SgInfo, 3, HonorSign, 0, '=');
|
|
if (iList < 0)
|
|
iList = FindSeitzMx(SgInfo, 3, HonorSign, 0, '*');
|
|
if (iList < 0)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
break;
|
|
case XS_Hexagonal:
|
|
CheckEnantiomorph = 1;
|
|
iList = FindSeitzMx(SgInfo, 6, HonorSign, 0, '=');
|
|
if (iList < 0)
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
break;
|
|
case XS_Cubic:
|
|
iList = FindSeitzMx(SgInfo, 4, HonorSign, 0, '=');
|
|
if (iList >= 0)
|
|
CheckEnantiomorph = 1;
|
|
break;
|
|
default:
|
|
iList = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Unknown) {
|
|
SetSgError("Error: Can't determine crystal system");
|
|
} else if (iList >= 0) {
|
|
lrmxi = ListOrBufRotMxInfo(SgInfo, iList, &RotMxInfo);
|
|
if (lrmxi == NULL) {
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
return XS_Unknown;
|
|
}
|
|
|
|
if (SgInfo->XtalSystem != XS_Cubic) {
|
|
SgInfo->UniqueRefAxis = lrmxi->RefAxis;
|
|
SgInfo->UniqueDirCode = lrmxi->DirCode;
|
|
|
|
if (SgInfo->XtalSystem == XS_Trigonal && lrmxi->DirCode == '=') {
|
|
switch (lrmxi->RefAxis) {
|
|
case 'z':
|
|
switch (SgInfo->LatticeInfo->Code) {
|
|
case 'R':
|
|
SgInfo->ExtraInfo = EI_Obverse;
|
|
break;
|
|
case 'T':
|
|
SgInfo->ExtraInfo = EI_Reverse;
|
|
break;
|
|
}
|
|
break;
|
|
case 'y':
|
|
switch (SgInfo->LatticeInfo->Code) {
|
|
case 'S':
|
|
SgInfo->ExtraInfo = EI_Obverse;
|
|
break;
|
|
case 'R':
|
|
SgInfo->ExtraInfo = EI_Reverse;
|
|
break;
|
|
}
|
|
break;
|
|
case 'x':
|
|
switch (SgInfo->LatticeInfo->Code) {
|
|
case 'T':
|
|
SgInfo->ExtraInfo = EI_Obverse;
|
|
break;
|
|
case 'S':
|
|
SgInfo->ExtraInfo = EI_Reverse;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HonorSign == 0 /* no inversion matrix */
|
|
&& SgInfo->LatticeInfo->Code == 'P' && CheckEnantiomorph == 1) {
|
|
lsmx = &SgInfo->ListSeitzMx[iList];
|
|
|
|
if (GetRotMxOrder(lsmx->s.R) > 1) {
|
|
i = lsmx->s.T[0] * lrmxi->EigenVector[0];
|
|
i += lsmx->s.T[1] * lrmxi->EigenVector[1];
|
|
i += lsmx->s.T[2] * lrmxi->EigenVector[2];
|
|
|
|
if (i % (STBF / 2))
|
|
SgInfo->ExtraInfo = EI_Enantiomorphic;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SgInfo->XtalSystem;
|
|
}
|
|
|
|
|
|
static int BuildGenerator_iList(T_SgInfo * SgInfo)
|
|
{
|
|
int iList, iList_1, nG;
|
|
int SgInfo_CI, HonorSign, Flag3asterisk, FlagPG;
|
|
|
|
|
|
SgInfo_CI = (SgInfo->Centric || SgInfo->InversionOffOrigin);
|
|
|
|
SgInfo->PointGroup = PG_Unknown;
|
|
|
|
nG = SgInfo->nGenerator = 0;
|
|
#define G_iL SgInfo->Generator_iList
|
|
|
|
HonorSign = 1;
|
|
iList_1 = FindSeitzMx(SgInfo, -1, HonorSign, 'o', '.');
|
|
if (iList_1 < 0)
|
|
HonorSign = 0;
|
|
|
|
if (SgInfo->XtalSystem == XS_Unknown)
|
|
FindXtalSystem(SgInfo);
|
|
|
|
switch (SgInfo->XtalSystem) {
|
|
case XS_Triclinic:
|
|
if (iList_1 < 0)
|
|
iList_1 = FindSeitzMx(SgInfo, 1, HonorSign, 'o', '.');
|
|
if (iList_1 >= 0)
|
|
G_iL[nG++] = iList_1;
|
|
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_1b;
|
|
else
|
|
SgInfo->PointGroup = PG_1;
|
|
|
|
SgInfo->nGenerator = nG;
|
|
return 0;
|
|
|
|
case XS_Monoclinic:
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 0, '=');
|
|
if (iList < 0)
|
|
break;
|
|
G_iL[nG++] = iList;
|
|
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_2_m;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[iList].s.R) == -1)
|
|
SgInfo->PointGroup = PG_m;
|
|
else
|
|
SgInfo->PointGroup = PG_2;
|
|
|
|
if (iList_1 >= 0)
|
|
G_iL[nG++] = iList_1;
|
|
|
|
SgInfo->nGenerator = nG;
|
|
return 0;
|
|
|
|
case XS_Orthorhombic:
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'z', '=');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'x', '=');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
|
|
if (nG < 2) {
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'y', '=');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
}
|
|
|
|
if (nG != 2)
|
|
break;
|
|
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_mmm;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[0]].s.R) == -1
|
|
|| deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_mm2;
|
|
else
|
|
SgInfo->PointGroup = PG_222;
|
|
|
|
if (iList_1 >= 0)
|
|
G_iL[nG++] = iList_1;
|
|
|
|
SgInfo->nGenerator = nG;
|
|
return 0;
|
|
|
|
case XS_Tetragonal:
|
|
iList = FindSeitzMx(SgInfo, 4, HonorSign, 0, '=');
|
|
if (iList < 0)
|
|
break;
|
|
G_iL[nG++] = iList;
|
|
|
|
if (SgInfo->UniqueRefAxis != 'x') {
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'x', '=');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
}
|
|
if (nG < 2 && SgInfo->UniqueRefAxis != 'z') {
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'z', '=');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
}
|
|
if (nG < 2 && SgInfo->UniqueRefAxis != 'y') {
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'y', '=');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
}
|
|
|
|
if (nG < 2) {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_4_m;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[0]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_4b;
|
|
else
|
|
SgInfo->PointGroup = PG_4;
|
|
} else {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_4_mmm;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[0]].s.R) == -1) {
|
|
if (deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_4bm2;
|
|
else
|
|
SgInfo->PointGroup = PG_4b2m;
|
|
} else {
|
|
if (deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_4mm;
|
|
else
|
|
SgInfo->PointGroup = PG_422;
|
|
}
|
|
}
|
|
|
|
if (iList_1 >= 0)
|
|
G_iL[nG++] = iList_1;
|
|
|
|
SgInfo->nGenerator = nG;
|
|
return 0;
|
|
|
|
case XS_Trigonal:
|
|
case XS_Hexagonal:
|
|
Flag3asterisk = 0;
|
|
|
|
if (SgInfo->XtalSystem == XS_Trigonal) {
|
|
iList = FindSeitzMx(SgInfo, 3, HonorSign, 0, '=');
|
|
if (iList < 0) {
|
|
iList = FindSeitzMx(SgInfo, 3, HonorSign, 0, '*');
|
|
Flag3asterisk = 1;
|
|
}
|
|
} else
|
|
iList = FindSeitzMx(SgInfo, 6, HonorSign, 0, '=');
|
|
|
|
if (iList < 0)
|
|
break;
|
|
G_iL[nG++] = iList;
|
|
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 0, '\'');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
|
|
FlagPG = -1;
|
|
|
|
if (nG < 2) {
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 0, '"');
|
|
if (iList >= 0)
|
|
G_iL[nG++] = iList;
|
|
FlagPG = 1;
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Trigonal) {
|
|
if (nG < 2) {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_3b;
|
|
else
|
|
SgInfo->PointGroup = PG_3;
|
|
} else {
|
|
if (Flag3asterisk == 1) {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_3bm;
|
|
else {
|
|
FlagPG = deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R);
|
|
if (FlagPG == -1)
|
|
SgInfo->PointGroup = PG_3m;
|
|
else
|
|
SgInfo->PointGroup = PG_32;
|
|
}
|
|
} else if (FlagPG == -1) {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_3b1m;
|
|
else {
|
|
FlagPG = deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R);
|
|
if (FlagPG == -1)
|
|
SgInfo->PointGroup = PG_31m;
|
|
else
|
|
SgInfo->PointGroup = PG_312;
|
|
}
|
|
} else {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_3bm1;
|
|
else {
|
|
FlagPG = deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R);
|
|
if (FlagPG == -1)
|
|
SgInfo->PointGroup = PG_3m1;
|
|
else
|
|
SgInfo->PointGroup = PG_321;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (nG < 2) {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_6_m;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[0]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_6b;
|
|
else
|
|
SgInfo->PointGroup = PG_6;
|
|
} else {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_6_mmm;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[0]].s.R) == -1) {
|
|
if (deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R) == FlagPG)
|
|
SgInfo->PointGroup = PG_6b2m;
|
|
else
|
|
SgInfo->PointGroup = PG_6bm2;
|
|
} else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[1]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_6mm;
|
|
else
|
|
SgInfo->PointGroup = PG_622;
|
|
}
|
|
}
|
|
|
|
if (iList_1 >= 0)
|
|
G_iL[nG++] = iList_1;
|
|
|
|
SgInfo->nGenerator = nG;
|
|
return 0;
|
|
|
|
case XS_Cubic:
|
|
FlagPG = 0;
|
|
|
|
iList = FindSeitzMx(SgInfo, 4, HonorSign, 'z', '=');
|
|
if (iList < 0) {
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'z', '=');
|
|
FlagPG = 1;
|
|
}
|
|
if (iList < 0)
|
|
break;
|
|
G_iL[nG++] = iList;
|
|
|
|
iList = FindSeitzMx(SgInfo, 2, HonorSign, 'x', '=');
|
|
if (iList < 0)
|
|
break;
|
|
G_iL[nG++] = iList;
|
|
|
|
iList = FindSeitzMx(SgInfo, 3, HonorSign, 'o', '*');
|
|
if (iList < 0)
|
|
break;
|
|
G_iL[nG++] = iList;
|
|
|
|
if (FlagPG) {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_m3b;
|
|
else
|
|
SgInfo->PointGroup = PG_23;
|
|
} else {
|
|
if (SgInfo_CI)
|
|
SgInfo->PointGroup = PG_m3bm;
|
|
else if (deterRotMx(SgInfo->ListSeitzMx[G_iL[0]].s.R) == -1)
|
|
SgInfo->PointGroup = PG_4b3m;
|
|
else
|
|
SgInfo->PointGroup = PG_432;
|
|
}
|
|
|
|
if (iList_1 >= 0)
|
|
G_iL[nG++] = iList_1;
|
|
|
|
SgInfo->nGenerator = nG;
|
|
return 0;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#undef G_iL
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int BuildHSym(T_SgInfo * SgInfo)
|
|
{
|
|
int NeedDash, HaveOrSh, nGRT, iList, iG, ip, os, i;
|
|
int AbsOrder, RefAxis, DirCode, ScrewPrimitive, Screw;
|
|
int PreviousRotation, PreviousRefAxis, PreviousDirCode;
|
|
int nTrV, iTrV, OrSh[3], RO[3], Transl[3];
|
|
const int *TrV, *ht;
|
|
T_RTMx SMx_1;
|
|
const T_RTMx *SMx;
|
|
const T_RotMxInfo *rmxi;
|
|
char *hsym, *hsym_mark;
|
|
|
|
struct {
|
|
T_RotMxInfo RMxI_Buf;
|
|
const T_RotMxInfo *RMxI;
|
|
int Transl[3];
|
|
} GRT[sizeof SgInfo->Generator_iList / sizeof(*SgInfo->Generator_iList) +
|
|
1];
|
|
|
|
const char *Digits = "0123456";
|
|
|
|
|
|
if (SgInfo->nGenerator == 0) {
|
|
SetSgError("Internal Error: BuildHSym(): Empty generator list");
|
|
return -1;
|
|
}
|
|
|
|
HaveOrSh = 0;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
OrSh[i] = SgInfo->OriginShift[i] * (STBF / 12);
|
|
if (OrSh[i])
|
|
HaveOrSh = 1;
|
|
}
|
|
|
|
NeedDash = 0;
|
|
nGRT = 0;
|
|
|
|
for (iG = 0; iG < SgInfo->nGenerator; iG++) {
|
|
iList = SgInfo->Generator_iList[iG];
|
|
|
|
GRT[nGRT].RMxI =
|
|
ListOrBufRotMxInfo(SgInfo, iList, &GRT[nGRT].RMxI_Buf);
|
|
if (GRT[nGRT].RMxI == NULL)
|
|
return -1;
|
|
|
|
SMx = &SgInfo->ListSeitzMx[iList];
|
|
|
|
RotMx_t_Vector(RO, SMx->s.R, OrSh, STBF);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
GRT[nGRT].Transl[i] =
|
|
iModPositive(SMx->s.T[i] + RO[i] - OrSh[i], STBF);
|
|
|
|
if (GRT[nGRT].RMxI->Order == -1) {
|
|
for (i = 0; i < 3; i++)
|
|
if (GRT[nGRT].Transl[i] != 0)
|
|
break;
|
|
|
|
if (i == 3)
|
|
NeedDash = 1;
|
|
else
|
|
nGRT++;
|
|
} else
|
|
nGRT++;
|
|
}
|
|
|
|
if (SgInfo->Centric) {
|
|
if (HaveOrSh == 0)
|
|
NeedDash = 1;
|
|
else {
|
|
for (iG = 0; iG < nGRT; iG++)
|
|
if (GRT[iG].RMxI->Order == 1)
|
|
break;
|
|
|
|
InitSeitzMx(&SMx_1, -1);
|
|
|
|
if (GetRotMxInfo(SMx_1.s.R, &GRT[iG].RMxI_Buf) != -1) {
|
|
SetSgError("Internal Error: BuildHSym(): Corrupt GetRotMxInfo()");
|
|
return -1;
|
|
}
|
|
|
|
GRT[iG].RMxI = &GRT[iG].RMxI_Buf;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
GRT[iG].Transl[i] = iModPositive(-2 * OrSh[i], STBF);
|
|
|
|
if (iG == nGRT)
|
|
nGRT++;
|
|
}
|
|
}
|
|
|
|
hsym = SgInfo->HallSymbol;
|
|
|
|
for (i = 0; i <= MaxLenHallSymbol; i++)
|
|
*hsym++ = '\0';
|
|
|
|
PreviousRotation = 0;
|
|
PreviousRefAxis = 0;
|
|
PreviousDirCode = 0;
|
|
|
|
hsym = SgInfo->HallSymbol;
|
|
|
|
if (NeedDash)
|
|
*hsym++ = '-';
|
|
else
|
|
*hsym++ = ' ';
|
|
|
|
*hsym++ = SgInfo->LatticeInfo->Code;
|
|
|
|
nTrV = SgInfo->LatticeInfo->nTrVector;
|
|
|
|
for (iG = 0; iG < nGRT; iG++) {
|
|
rmxi = GRT[iG].RMxI;
|
|
|
|
AbsOrder = abs(rmxi->Order);
|
|
RefAxis = rmxi->RefAxis;
|
|
DirCode = rmxi->DirCode;
|
|
if (RefAxis == 'o')
|
|
RefAxis = 0;
|
|
if (DirCode == '=' || DirCode == '.')
|
|
DirCode = 0;
|
|
|
|
if (iG == 0) {
|
|
if (RefAxis == 'z')
|
|
RefAxis = 0;
|
|
} else {
|
|
if (AbsOrder == 2) {
|
|
if (PreviousRotation == 2 || PreviousRotation == 4) {
|
|
if (RefAxis == 'x')
|
|
RefAxis = 0;
|
|
} else if (PreviousRotation == 3 || PreviousRotation == 6) {
|
|
if (PreviousDirCode == '*' || RefAxis == PreviousRefAxis)
|
|
RefAxis = 0;
|
|
if (DirCode == '\'')
|
|
DirCode = 0;
|
|
}
|
|
} else if (AbsOrder == 3) {
|
|
if (DirCode == '*')
|
|
DirCode = 0;
|
|
}
|
|
}
|
|
|
|
PreviousRotation = AbsOrder;
|
|
PreviousRefAxis = rmxi->RefAxis;
|
|
PreviousDirCode = rmxi->DirCode;
|
|
|
|
*hsym++ = ' ';
|
|
if (rmxi->Order < 0)
|
|
*hsym++ = '-';
|
|
*hsym++ = Digits[AbsOrder];
|
|
if (RefAxis)
|
|
*hsym++ = RefAxis;
|
|
if (DirCode)
|
|
*hsym++ = DirCode;
|
|
|
|
TrV = SgInfo->LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++, TrV += 3) {
|
|
for (i = 0; i < 3; i++)
|
|
if ((GRT[iG].Transl[i] + TrV[i]) % STBF != 0)
|
|
break;
|
|
|
|
if (i == 3)
|
|
break;
|
|
}
|
|
|
|
if (iTrV < nTrV)
|
|
continue; /* next iG */
|
|
|
|
hsym_mark = hsym;
|
|
|
|
TrV = SgInfo->LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++, TrV += 3, hsym = hsym_mark) {
|
|
for (i = 0; i < 3; i++)
|
|
Transl[i] = iModPositive(GRT[iG].Transl[i] + TrV[i], STBF);
|
|
|
|
Screw = 0;
|
|
|
|
for (ip = 0; ip < 3; ip++)
|
|
if (rmxi->EigenVector[ip] != 0)
|
|
break;
|
|
|
|
if (ip < 3 && rmxi->EigenVector[ip] == 1) {
|
|
for (i = ip + 1; i < 3; i++)
|
|
if (rmxi->EigenVector[i] != 0)
|
|
break;
|
|
|
|
if (i == 3) {
|
|
ScrewPrimitive = STBF / AbsOrder;
|
|
Screw = Transl[ip] / ScrewPrimitive;
|
|
i = Screw * ScrewPrimitive;
|
|
if (i % 3) {
|
|
*hsym++ = Digits[Screw];
|
|
Transl[ip] -= i;
|
|
}
|
|
}
|
|
}
|
|
|
|
ht = HallTranslations;
|
|
|
|
while (*ht) {
|
|
for (i = 0; i < 3; i++)
|
|
if (Transl[i] < ht[i + 1])
|
|
break;
|
|
|
|
if (i == 3) {
|
|
for (i = 0; i < 3; i++)
|
|
Transl[i] -= ht[i + 1];
|
|
|
|
*hsym++ = (char) *ht;
|
|
}
|
|
|
|
ht += 4;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
if (Transl[i] != 0)
|
|
break;
|
|
|
|
if (i == 3)
|
|
break;
|
|
}
|
|
|
|
if (iTrV == nTrV)
|
|
return 0;
|
|
}
|
|
|
|
if (nGRT == 0) {
|
|
*hsym++ = ' ';
|
|
*hsym++ = '1';
|
|
}
|
|
|
|
if (HaveOrSh) {
|
|
*hsym++ = ' ';
|
|
*hsym++ = '(';
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (i)
|
|
*hsym++ = ' ';
|
|
|
|
os = iModPositive(SgInfo->OriginShift[i], 12);
|
|
if (os > 6) {
|
|
*hsym++ = '-';
|
|
os = 12 - os;
|
|
}
|
|
|
|
*hsym++ = Digits[os];
|
|
}
|
|
|
|
*hsym++ = ')';
|
|
}
|
|
|
|
*hsym = '\0';
|
|
|
|
if (SgInfo->HallSymbol[MaxLenHallSymbol] != '\0') {
|
|
SetSgError("Internal Error: BuildHSym(): MaxLenHallSymbol too small");
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int BuildHallSymbol(T_SgInfo * SgInfo, int FixedOriginShift)
|
|
{
|
|
int ix, iy, iz;
|
|
int status;
|
|
|
|
static const int ShiftTable[] = { 0, 1, -1, 2, -2, 3 };
|
|
|
|
|
|
if (SgError != NULL)
|
|
return -1;
|
|
|
|
if (SgInfo->nGenerator == 0) {
|
|
if (BuildGenerator_iList(SgInfo) != 0) {
|
|
SetSgError("Error: Can't build generator list");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (FixedOriginShift) {
|
|
status = BuildHSym(SgInfo);
|
|
if (status == 1)
|
|
return 0;
|
|
} else {
|
|
for (ix = 0; ix < 6; ix++) {
|
|
SgInfo->OriginShift[0] = ShiftTable[ix];
|
|
|
|
for (iy = 0; iy < 6; iy++) {
|
|
SgInfo->OriginShift[1] = ShiftTable[iy];
|
|
|
|
for (iz = 0; iz < 6; iz++) {
|
|
SgInfo->OriginShift[2] = ShiftTable[iz];
|
|
|
|
status = BuildHSym(SgInfo);
|
|
if (status < 0)
|
|
return -1;
|
|
|
|
if (status == 1)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SetSgError("Error: Can't build Hall Symbol");
|
|
return -1;
|
|
}
|
|
|
|
|
|
void InitSgInfo(T_SgInfo * SgInfo)
|
|
{
|
|
int i;
|
|
|
|
|
|
SgInfo->GenOption = 0;
|
|
SgInfo->Centric = 0;
|
|
SgInfo->InversionOffOrigin = 0;
|
|
SgInfo->LatticeInfo = LI_P;
|
|
SgInfo->StatusLatticeTr = 0;
|
|
for (i = 0; i < 3; i++)
|
|
SgInfo->OriginShift[i] = 0;
|
|
SgInfo->nList = 0;
|
|
|
|
SgInfo->OrderL = 0;
|
|
SgInfo->OrderP = 0;
|
|
SgInfo->XtalSystem = XS_Unknown;
|
|
SgInfo->UniqueRefAxis = 0;
|
|
SgInfo->UniqueDirCode = 0;
|
|
SgInfo->ExtraInfo = EI_Unknown;
|
|
SgInfo->PointGroup = PG_Unknown;
|
|
SgInfo->nGenerator = 0;
|
|
SgInfo->HallSymbol[0] = '\0';
|
|
SgInfo->TabSgName = NULL;
|
|
SgInfo->CCMx_LP = NULL;
|
|
SgInfo->n_si_Vector = -1;
|
|
}
|
|
|
|
|
|
int CompleteSgInfo(T_SgInfo * SgInfo)
|
|
{
|
|
int List_iList[192];
|
|
const T_TabSgName *tsgn;
|
|
|
|
|
|
if (SgInfo->StatusLatticeTr == -1) {
|
|
if (AddLatticeTr2ListSeitzMx(SgInfo, SgInfo->LatticeInfo) < 0)
|
|
return -1;
|
|
}
|
|
|
|
if (ApplyOriginShift(SgInfo) < 0)
|
|
return -1;
|
|
|
|
if (SgInfo->nList > sizeof List_iList / sizeof(*List_iList)) {
|
|
SetSgError("Internal Error: CompleteSgInfo()");
|
|
return -1;
|
|
}
|
|
|
|
if (SgInfo->nList > 1) {
|
|
SortSgInfoList(SgInfo, List_iList);
|
|
if (SgError != NULL)
|
|
return -1;
|
|
}
|
|
|
|
if (RemoveLatticeTr(SgInfo) != 0)
|
|
return -1;
|
|
|
|
if (RemoveInversion(SgInfo) != 0)
|
|
return -1;
|
|
|
|
TidyTranslation(SgInfo);
|
|
|
|
if (SgInfo->nList > 1) {
|
|
SortSgInfoList(SgInfo, List_iList);
|
|
if (SgError != NULL)
|
|
return -1;
|
|
}
|
|
SgInfo->OrderP = SgInfo->nList;
|
|
if (SgInfo->Centric == -1)
|
|
SgInfo->OrderP *= 2;
|
|
|
|
SgInfo->OrderL = SgInfo->OrderP * SgInfo->LatticeInfo->nTrVector;
|
|
|
|
if (BuildHallSymbol(SgInfo, 0) != 0)
|
|
return -1;
|
|
|
|
for (tsgn = TabSgName; tsgn->HallSymbol; tsgn++)
|
|
if (strcmp(tsgn->HallSymbol, SgInfo->HallSymbol) == 0
|
|
&& (SgInfo->TabSgName == NULL || SgInfo->TabSgName == tsgn))
|
|
break;
|
|
|
|
if (SgInfo->TabSgName != NULL && tsgn->HallSymbol == NULL) {
|
|
if (SgError)
|
|
return -1;
|
|
|
|
sprintf(SgErrorBuffer,
|
|
"Internal Error: Input/Output HallSymbol mismatch: %s <> %s",
|
|
SgInfo->TabSgName->HallSymbol, SgInfo->HallSymbol);
|
|
|
|
SetSgError(SgErrorBuffer);
|
|
return -1;
|
|
}
|
|
|
|
if (tsgn->HallSymbol)
|
|
SgInfo->TabSgName = tsgn;
|
|
|
|
SgInfo->CCMx_LP = NULL;
|
|
|
|
switch (SgInfo->LatticeInfo->Code) {
|
|
case 'P':
|
|
SgInfo->CCMx_LP = CCMx_PP;
|
|
break;
|
|
case 'A':
|
|
SgInfo->CCMx_LP = CCMx_AP;
|
|
break;
|
|
case 'B':
|
|
SgInfo->CCMx_LP = CCMx_BP;
|
|
break;
|
|
case 'C':
|
|
SgInfo->CCMx_LP = CCMx_CP;
|
|
break;
|
|
case 'I':
|
|
SgInfo->CCMx_LP = CCMx_IP;
|
|
break;
|
|
case 'R':
|
|
switch (SgInfo->UniqueRefAxis) {
|
|
case 0:
|
|
case 'z':
|
|
SgInfo->CCMx_LP = CCMx_RP_z;
|
|
break;
|
|
case 'y':
|
|
SgInfo->CCMx_LP = CCMx_RP_y;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case 'S':
|
|
switch (SgInfo->UniqueRefAxis) {
|
|
case 0:
|
|
case 'y':
|
|
SgInfo->CCMx_LP = CCMx_SP_y;
|
|
break;
|
|
case 'x':
|
|
SgInfo->CCMx_LP = CCMx_SP_x;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case 'T':
|
|
switch (SgInfo->UniqueRefAxis) {
|
|
case 0:
|
|
case 'x':
|
|
SgInfo->CCMx_LP = CCMx_TP_x;
|
|
break;
|
|
case 'z':
|
|
SgInfo->CCMx_LP = CCMx_TP_z;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case 'F':
|
|
SgInfo->CCMx_LP = CCMx_FP;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (SgInfo->CCMx_LP == NULL) {
|
|
SetSgError("Internal Error: Illegal lattice code");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int CB_SMx(T_RTMx * CSiC,
|
|
const T_RTMx * CBMx, const T_RTMx * SMx, const T_RTMx * InvCBMx)
|
|
{
|
|
int i;
|
|
T_RTMx BufMx;
|
|
|
|
|
|
RTMxMultiply(&BufMx, SMx, InvCBMx, CTBF / STBF, CTBF);
|
|
RTMxMultiply(CSiC, CBMx, &BufMx, CRBF, CRBF * CTBF);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
if (CSiC->s.R[i] % (CRBF * CRBF)) {
|
|
SetSgError("Internal Error: Corrupt CBMx/SMx/InvCBMx");
|
|
return -1;
|
|
}
|
|
|
|
CSiC->s.R[i] /= (CRBF * CRBF);
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (CSiC->s.T[i] % (CRBF * (CTBF / STBF))) {
|
|
SetSgError("Internal Error: Out of STBF range");
|
|
return -1;
|
|
}
|
|
|
|
CSiC->s.T[i] /= (CRBF * (CTBF / STBF));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int TransformSgInfo(const T_SgInfo * SgInfo,
|
|
const T_RTMx * CBMx, const T_RTMx * InvCBMx,
|
|
T_SgInfo * BC_SgInfo)
|
|
{
|
|
int iList, f, i;
|
|
int nTrV, iTrV, nLoopInv, iLoopInv;
|
|
const int *TrV;
|
|
T_RTMx SMx, BC_SMx;
|
|
const T_RTMx *lsmx;
|
|
|
|
|
|
nLoopInv = Sg_nLoopInv(SgInfo);
|
|
|
|
nTrV = SgInfo->LatticeInfo->nTrVector;
|
|
TrV = SgInfo->LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++, TrV += 3) {
|
|
for (iLoopInv = 0; iLoopInv < nLoopInv; iLoopInv++) {
|
|
if (iLoopInv == 0)
|
|
f = 1;
|
|
else
|
|
f = -1;
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
for (i = 0; i < 9; i++)
|
|
SMx.s.R[i] = f * lsmx->s.R[i];
|
|
|
|
for (i = 0; i < 3; i++)
|
|
SMx.s.T[i] = f * lsmx->s.T[i] + TrV[i];
|
|
|
|
if (CB_SMx(&BC_SMx, CBMx, &SMx, InvCBMx) != 0)
|
|
return -1;
|
|
|
|
if (Add2ListSeitzMx(BC_SgInfo, &BC_SMx) < 0)
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#undef SGCLIB_C__
|