Files
sics/sgclib.c
koennecke 361ee9ebea - Reworked the connection object and the IO system
- Reworked the support for TRICS
- Added a second generation motor
2009-02-03 08:05:39 +00:00

2506 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__