1181 lines
25 KiB
C
1181 lines
25 KiB
C
/*
|
|
Space Group Info's (c) 1994-96 Ralf W. Grosse-Kunstleve
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
|
|
#define SGCOREDEF__
|
|
#include "sginfo.h"
|
|
|
|
|
|
static int InitialCBMxR(T_SgInfo * SgInfo,
|
|
const T_LatticeInfo ** NewLatticeInfo,
|
|
int *NewPointGroup,
|
|
int *IniCBMxR, int *IniInvCBMxR)
|
|
{
|
|
int Code, NewPG, deterCCMx, fac, i;
|
|
const T_LatticeInfo *NewLI;
|
|
const int *CCMx;
|
|
|
|
|
|
Code = SgInfo->LatticeInfo->Code;
|
|
NewLI = SgInfo->LatticeInfo;
|
|
NewPG = SgInfo->PointGroup;
|
|
CCMx = CCMx_PP;
|
|
|
|
switch (SgInfo->XtalSystem) {
|
|
case XS_Triclinic:
|
|
NewLI = LI_P;
|
|
CCMx = SgInfo->CCMx_LP;
|
|
break;
|
|
|
|
case XS_Monoclinic:
|
|
case XS_Tetragonal:
|
|
switch (SgInfo->UniqueRefAxis) {
|
|
case 'z':
|
|
if (Code == 'C') {
|
|
NewLI = LI_P;
|
|
CCMx = SgInfo->CCMx_LP;
|
|
} else if (Code == 'F') {
|
|
NewLI = LI_I;
|
|
CCMx = CCMx_FI_z;
|
|
}
|
|
break;
|
|
case 'y':
|
|
if (Code == 'B') {
|
|
NewLI = LI_P;
|
|
CCMx = SgInfo->CCMx_LP;
|
|
} else if (Code == 'F') {
|
|
NewLI = LI_I;
|
|
CCMx = CCMx_FI_y;
|
|
}
|
|
break;
|
|
case 'x':
|
|
if (Code == 'A') {
|
|
NewLI = LI_P;
|
|
CCMx = SgInfo->CCMx_LP;
|
|
} else if (Code == 'F') {
|
|
NewLI = LI_I;
|
|
CCMx = CCMx_FI_x;
|
|
}
|
|
break;
|
|
default:
|
|
goto ReturnError;
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Tetragonal
|
|
&& SgInfo->LatticeInfo != NewLI) {
|
|
if (NewPG == PG_4b2m)
|
|
NewPG = PG_4bm2;
|
|
else if (NewPG == PG_4bm2)
|
|
NewPG = PG_4b2m;
|
|
}
|
|
|
|
break;
|
|
|
|
case XS_Orthorhombic:
|
|
break;
|
|
|
|
case XS_Trigonal:
|
|
NewLI = LI_P;
|
|
CCMx = SgInfo->CCMx_LP;
|
|
|
|
if (Code == 'R' || Code == 'S' || Code == 'T') {
|
|
if (NewPG == PG_321)
|
|
NewPG = PG_32;
|
|
else if (NewPG == PG_3m1)
|
|
NewPG = PG_3m;
|
|
else if (NewPG == PG_3bm1)
|
|
NewPG = PG_3bm;
|
|
}
|
|
|
|
break;
|
|
|
|
case XS_Hexagonal:
|
|
break;
|
|
|
|
case XS_Cubic:
|
|
break;
|
|
|
|
default:
|
|
goto ReturnError;
|
|
}
|
|
|
|
deterCCMx = deterRotMx(CCMx);
|
|
if (deterCCMx < 1 || CRBF % deterCCMx)
|
|
goto ReturnError;
|
|
|
|
fac = CRBF / deterCCMx;
|
|
|
|
InverseRotMx(CCMx, IniInvCBMxR);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
IniCBMxR[i] = CRBF * CCMx[i];
|
|
IniInvCBMxR[i] *= fac;
|
|
}
|
|
|
|
*NewLatticeInfo = NewLI;
|
|
*NewPointGroup = NewPG;
|
|
|
|
return deterCCMx;
|
|
|
|
ReturnError:
|
|
|
|
SetSgError("Internal Error: InitialCBMxR()");
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int CBR_RMx(int *RRMx,
|
|
const int *CBMxR, const int *RMx, const int *InvCBMxR)
|
|
{
|
|
int i, BufMx[9];
|
|
|
|
|
|
RotMxMultiply(BufMx, RMx, InvCBMxR);
|
|
RotMxMultiply(RRMx, CBMxR, BufMx);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
if (RRMx[i] % (CRBF * CRBF)) {
|
|
SetSgError("Internal Error: CBR_SMx()");
|
|
return -1;
|
|
}
|
|
|
|
RRMx[i] /= (CRBF * CRBF);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void RotateCBMxR(const int *RMx, const int *InvRMx,
|
|
int *CBMxR, int *InvCBMxR)
|
|
{
|
|
int i, BufMx[9];
|
|
|
|
|
|
RotMxMultiply(BufMx, RMx, CBMxR);
|
|
for (i = 0; i < 9; i++)
|
|
CBMxR[i] = BufMx[i];
|
|
|
|
/* matrix algebra: (A * B)^-1 = B^-1 * A^-1 */
|
|
|
|
RotMxMultiply(BufMx, InvCBMxR, InvRMx);
|
|
for (i = 0; i < 9; i++)
|
|
InvCBMxR[i] = BufMx[i];
|
|
}
|
|
|
|
|
|
static int AlignUniqueAxis(const T_SgInfo * SgInfo,
|
|
const T_SgInfo * GenSgI,
|
|
int *CBMxR, int *InvCBMxR, const int **AlignRMx)
|
|
{
|
|
int i, iListS, DirCode;
|
|
int UAMx[9], RotEV[3];
|
|
const int *RMx, *InvRMx, *lsmxR;
|
|
T_RotMxInfo RMxI_S, *RMxI_G;
|
|
|
|
|
|
if (GenSgI->nList < 2)
|
|
goto ReturnError;
|
|
|
|
RMxI_G = &GenSgI->ListRotMxInfo[1];
|
|
|
|
if (abs(RMxI_G->Order) == 3)
|
|
DirCode = 0;
|
|
else
|
|
DirCode = '=';
|
|
|
|
iListS = FindSeitzMx(SgInfo, RMxI_G->Order, 1, 0, DirCode);
|
|
if (iListS < 0) {
|
|
if (SgInfo->Centric == 0)
|
|
return 0;
|
|
|
|
iListS = FindSeitzMx(SgInfo, -RMxI_G->Order, 1, 0, DirCode);
|
|
if (iListS < 0)
|
|
goto ReturnError;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
UAMx[i] = -SgInfo->ListSeitzMx[iListS].s.R[i];
|
|
|
|
lsmxR = UAMx;
|
|
} else
|
|
lsmxR = SgInfo->ListSeitzMx[iListS].s.R;
|
|
|
|
if (CBR_RMx(UAMx, CBMxR, lsmxR, InvCBMxR) != 0)
|
|
goto ReturnError;
|
|
|
|
if (GetRotMxInfo(UAMx, &RMxI_S) != RMxI_G->Order)
|
|
goto ReturnError;
|
|
|
|
if (RMxI_S.DirCode != RMxI_G->DirCode)
|
|
return 0;
|
|
|
|
RMx = InvRMx = RMx_1_000;
|
|
|
|
for (;;) {
|
|
RotMx_t_Vector(RotEV, RMx, RMxI_S.EigenVector, 0);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
if (RotEV[i] != RMxI_G->EigenVector[i])
|
|
break;
|
|
|
|
if (i == 3)
|
|
break;
|
|
|
|
if (RMxI_S.DirCode == '=') {
|
|
if (RMx == RMx_1_000) {
|
|
RMx = RMx_3_111;
|
|
InvRMx = RMx_3i111;
|
|
} else if (RMx == RMx_3_111) {
|
|
RMx = RMx_3i111;
|
|
InvRMx = RMx_3_111;
|
|
} else
|
|
goto ReturnError;
|
|
} else if (RMxI_S.DirCode == '*') {
|
|
if (RMx == RMx_1_000) {
|
|
RMx = RMx_4_001;
|
|
InvRMx = RMx_4i001;
|
|
} else if (RMx == RMx_4_001) {
|
|
RMx = RMx_2_001;
|
|
InvRMx = RMx_2_001;
|
|
} else if (RMx == RMx_2_001) {
|
|
RMx = RMx_4i001;
|
|
InvRMx = RMx_4_001;
|
|
} else
|
|
goto ReturnError;
|
|
} else
|
|
goto ReturnError;
|
|
}
|
|
|
|
if (RMx != RMx_1_000)
|
|
RotateCBMxR(RMx, InvRMx, CBMxR, InvCBMxR);
|
|
|
|
if (AlignRMx)
|
|
*AlignRMx = RMx;
|
|
|
|
return 1;
|
|
|
|
ReturnError:
|
|
|
|
SetSgError("Internal Error: AlignUniqueAxis()");
|
|
return -1;
|
|
}
|
|
|
|
|
|
static const T_RTMx *GetSMxWithSameRot(const int *WtdRotMx,
|
|
const T_SgInfo * SgInfo,
|
|
T_RTMx * BufMx)
|
|
{
|
|
int iList, i;
|
|
const T_RTMx *lsmx;
|
|
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
for (i = 0; i < 9; i++)
|
|
if (WtdRotMx[i] != lsmx->s.R[i])
|
|
break;
|
|
|
|
if (i == 9)
|
|
return lsmx;
|
|
|
|
if (SgInfo->Centric != -1)
|
|
continue;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
if (WtdRotMx[i] != -lsmx->s.R[i])
|
|
break;
|
|
|
|
if (i == 9) {
|
|
for (i = 0; i < 9; i++)
|
|
BufMx->s.R[i] = -lsmx->s.R[i];
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
BufMx->s.T[i] = -lsmx->s.T[i] % STBF;
|
|
if (BufMx->s.T[i] < 0)
|
|
BufMx->s.T[i] += STBF;
|
|
}
|
|
|
|
return BufMx;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static int BuildFreeMx(const int *EigenVector, int Order, int *FreeMx)
|
|
{
|
|
static const int GeneratorEigenVectors[] = {
|
|
001, 0, 0, 1,
|
|
010, 0, 1, 0,
|
|
100, 1, 0, 0,
|
|
110, 1, 1, 0,
|
|
-110, 1, -1, 0,
|
|
111, 1, 1, 1,
|
|
0
|
|
};
|
|
|
|
int i;
|
|
const int *gev;
|
|
|
|
|
|
for (i = 0; i < 9; i++)
|
|
FreeMx[i] = 0;
|
|
|
|
if (Order == -1 || Order == -3 || Order == -4 || Order == -6)
|
|
return 0;
|
|
|
|
for (gev = GeneratorEigenVectors; *gev++ != 0; gev += 3) {
|
|
for (i = 0; i < 3; i++)
|
|
if (EigenVector[i] != gev[i])
|
|
break;
|
|
|
|
if (i == 3)
|
|
break;
|
|
}
|
|
|
|
gev--;
|
|
|
|
if (Order == -2) {
|
|
switch (*gev) {
|
|
case 001:
|
|
FreeMx[0] = 1;
|
|
FreeMx[4] = 1;
|
|
return 0;
|
|
case 010:
|
|
FreeMx[8] = 1;
|
|
FreeMx[0] = 1;
|
|
return 0;
|
|
case 100:
|
|
FreeMx[4] = 1;
|
|
FreeMx[8] = 1;
|
|
return 0;
|
|
case 110:
|
|
FreeMx[1] = 1;
|
|
FreeMx[4] = -1;
|
|
FreeMx[8] = 1;
|
|
return 1;
|
|
case -110:
|
|
FreeMx[1] = 1;
|
|
FreeMx[4] = 1;
|
|
FreeMx[8] = 1;
|
|
return 1;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (Order > 1) {
|
|
switch (*gev) {
|
|
case 001:
|
|
FreeMx[8] = 1;
|
|
return 0;
|
|
case 010:
|
|
FreeMx[4] = 1;
|
|
return 0;
|
|
case 100:
|
|
FreeMx[0] = 1;
|
|
return 0;
|
|
case 110:
|
|
FreeMx[0] = 1;
|
|
FreeMx[3] = 1;
|
|
return 1;
|
|
case -110:
|
|
FreeMx[0] = 1;
|
|
FreeMx[3] = -1;
|
|
return 1;
|
|
case 111:
|
|
FreeMx[0] = 1;
|
|
FreeMx[3] = 1;
|
|
FreeMx[6] = 1;
|
|
return 1;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetSgError("Internal Error: BuildFreeMx()");
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int StartFixAxes(const T_SgInfo * SgInfo,
|
|
const T_SgInfo * GenSgI, const int *iGen,
|
|
T_RTMx * CBMx, T_RTMx * InvCBMx,
|
|
T_RTMx * SMxG, T_RTMx * SMxS_G,
|
|
int *FreeMx, int *TryAgain)
|
|
{
|
|
int iG, Order, i;
|
|
const int *EV;
|
|
T_RTMx SMxG_S, BufMx;
|
|
const T_RTMx *SMx;
|
|
const T_RotMxInfo *RMxI_G;
|
|
|
|
|
|
if (*iGen == -3)
|
|
iG = 1;
|
|
else
|
|
iG = *iGen;
|
|
|
|
if (iG == -1) {
|
|
Order = -1;
|
|
EV = NULL;
|
|
} else {
|
|
if (iG < 1 || iG >= GenSgI->nList)
|
|
goto ReturnError;
|
|
|
|
RMxI_G = &GenSgI->ListRotMxInfo[iG];
|
|
Order = RMxI_G->Order;
|
|
EV = RMxI_G->EigenVector;
|
|
|
|
if (iG != *iGen) {
|
|
Order *= -1;
|
|
if (Order != *iGen)
|
|
goto ReturnError;
|
|
}
|
|
}
|
|
|
|
if (Order == -1) {
|
|
if (GenSgI->Centric == -1) {
|
|
InitSeitzMx(SMxG, -1);
|
|
} else {
|
|
for (iG = 1; iG < GenSgI->nList; iG++)
|
|
if (GenSgI->ListRotMxInfo[iG].Order == -1)
|
|
break;
|
|
|
|
if (iG == GenSgI->nList)
|
|
goto ReturnError;
|
|
|
|
SMx = &GenSgI->ListSeitzMx[iG];
|
|
|
|
for (i = 0; i < 12; i++)
|
|
SMxG->a[i] = SMx->a[i];
|
|
}
|
|
} else {
|
|
SMx = &GenSgI->ListSeitzMx[iG];
|
|
|
|
if (iG == *iGen)
|
|
for (i = 0; i < 12; i++)
|
|
SMxG->a[i] = SMx->a[i];
|
|
else {
|
|
for (i = 0; i < 9; i++)
|
|
SMxG->s.R[i] = -SMx->s.R[i];
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
SMxG->s.T[i] = -SMx->s.T[i] % STBF;
|
|
if (SMxG->s.T[i] < 0)
|
|
SMxG->s.T[i] += STBF;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CB_SMx(&SMxG_S, InvCBMx, SMxG, CBMx) != 0)
|
|
return -1;
|
|
|
|
SMx = GetSMxWithSameRot(SMxG_S.s.R, SgInfo, &BufMx);
|
|
if (SMx == NULL)
|
|
return 0;
|
|
|
|
if (CB_SMx(SMxS_G, CBMx, SMx, InvCBMx) != 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
if (SMxS_G->s.R[i] != SMxG->s.R[i])
|
|
goto ReturnError;
|
|
|
|
*TryAgain = BuildFreeMx(EV, Order, FreeMx);
|
|
if (*TryAgain < 0)
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
ReturnError:
|
|
|
|
SetSgError("Internal Error: StartFixAxes()");
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int FindInvertableMx(const int *Mx, int *InvMx,
|
|
int *nActive, int *irActive, int *icActive)
|
|
{
|
|
int Init, deterMx, i;
|
|
|
|
|
|
if (*nActive == 0 || *nActive == 3)
|
|
return 0;
|
|
|
|
if (*nActive == -1) {
|
|
Init = 1;
|
|
|
|
deterMx = deterRotMx(Mx);
|
|
if (deterMx) {
|
|
InverseRotMx(Mx, InvMx);
|
|
|
|
*nActive = 3;
|
|
return deterMx;
|
|
}
|
|
} else
|
|
Init = 0;
|
|
|
|
if (Init || *nActive == 2) {
|
|
for (;;) {
|
|
if (Init) {
|
|
irActive[0] = 0;
|
|
irActive[1] = 1;
|
|
icActive[0] = 0;
|
|
icActive[1] = 1;
|
|
Init = 0;
|
|
} else {
|
|
if (++icActive[1] == 3) {
|
|
if (++icActive[0] == 2) {
|
|
if (++irActive[1] == 3) {
|
|
if (++irActive[0] == 2) {
|
|
Init = 1;
|
|
break;
|
|
} else {
|
|
irActive[1] = irActive[0] + 1;
|
|
icActive[0] = 0;
|
|
icActive[1] = 1;
|
|
}
|
|
} else {
|
|
icActive[0] = 0;
|
|
icActive[1] = 1;
|
|
}
|
|
} else {
|
|
icActive[1] = icActive[0] + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
InvMx[0] = Mx[irActive[1] * 3 + icActive[1]];
|
|
InvMx[1] = -Mx[irActive[0] * 3 + icActive[1]];
|
|
InvMx[2] = -Mx[irActive[1] * 3 + icActive[0]];
|
|
InvMx[3] = Mx[irActive[0] * 3 + icActive[0]];
|
|
|
|
deterMx = InvMx[3] * InvMx[0] - InvMx[1] * InvMx[2];
|
|
if (deterMx) {
|
|
*nActive = 2;
|
|
return deterMx;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*nActive == 2)
|
|
return 0;
|
|
|
|
if (Init)
|
|
i = 0;
|
|
else
|
|
i = irActive[0] * 3 + icActive[0] + 1;
|
|
|
|
for (; i < 9; i++) {
|
|
if (Mx[i]) {
|
|
irActive[0] = i / 3;
|
|
icActive[0] = i % 3;
|
|
*nActive = 1;
|
|
return Mx[i];
|
|
}
|
|
}
|
|
|
|
if (*nActive == 1)
|
|
return 0;
|
|
|
|
*nActive = 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int SetInvCBMxT(const int *CBMxT, const int *InvCBMxR,
|
|
int *InvCBMxT)
|
|
{
|
|
int i;
|
|
|
|
|
|
RotMx_t_Vector(InvCBMxT, InvCBMxR, CBMxT, CRBF * CTBF);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (InvCBMxT[i] % CRBF) {
|
|
SetSgError("Internal Error: SetInvCBMxT()");
|
|
return -1;
|
|
}
|
|
|
|
if (InvCBMxT[i])
|
|
InvCBMxT[i] = CTBF - InvCBMxT[i] / CRBF;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int FixAxes(const T_SgInfo * SgInfo,
|
|
const T_SgInfo * GenSgI, const int *iGen,
|
|
T_RTMx * CBMx, T_RTMx * InvCBMx,
|
|
int *FreeMx, int TryAgain)
|
|
{
|
|
int i, NextTryAgain;
|
|
int IniCBMxT[3], SingleFreeMx[9];
|
|
T_RTMx SMxG, SMxS_G;
|
|
int NextFreeMxBuf[9], R_I_FMxBuf[9];
|
|
int R_I[9], *R_I_FMx, InvR_I_FMx[9], deterR_I_FMx;
|
|
int S_G[3], CmpS_G[3], RedSh[3], Sh[3], *NextFreeMx;
|
|
int nActive, irActive[3], icActive[3];
|
|
int nTrV, iTrV;
|
|
const int *TrV;
|
|
|
|
|
|
if (FreeMx == NULL) {
|
|
for (i = 0; i < 3; i++) {
|
|
CBMx->s.T[i] = 0;
|
|
InvCBMx->s.T[i] = 0;
|
|
}
|
|
}
|
|
|
|
i = StartFixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx,
|
|
&SMxG, &SMxS_G, SingleFreeMx, &NextTryAgain);
|
|
if (i != 1)
|
|
return i;
|
|
|
|
if (FreeMx) {
|
|
RotMxMultiply(NextFreeMxBuf, SingleFreeMx, FreeMx);
|
|
NextFreeMx = NextFreeMxBuf;
|
|
} else
|
|
NextFreeMx = SingleFreeMx;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
R_I[i] = SMxG.s.R[i];
|
|
|
|
for (i = 0; i < 9; i += 4)
|
|
R_I[i] -= 1;
|
|
|
|
if (FreeMx) {
|
|
RotMxMultiply(R_I_FMxBuf, R_I, FreeMx);
|
|
R_I_FMx = R_I_FMxBuf;
|
|
} else
|
|
R_I_FMx = R_I;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
IniCBMxT[i] = CBMx->s.T[i];
|
|
|
|
nActive = -1;
|
|
|
|
for (;;) {
|
|
deterR_I_FMx = FindInvertableMx(R_I_FMx, InvR_I_FMx,
|
|
&nActive, irActive, icActive);
|
|
if (deterR_I_FMx == 0)
|
|
break;
|
|
|
|
nTrV = GenSgI->LatticeInfo->nTrVector;
|
|
TrV = GenSgI->LatticeInfo->TrVector;
|
|
|
|
for (iTrV = 0; iTrV < nTrV; iTrV++, TrV += 3) {
|
|
for (i = 0; i < 3; i++) {
|
|
S_G[i] = (CTBF / STBF)
|
|
* ((SMxS_G.s.T[i] - SMxG.s.T[i] - TrV[i]) % STBF);
|
|
RedSh[i] = 0;
|
|
}
|
|
|
|
switch (nActive) {
|
|
case 1:
|
|
RedSh[icActive[0]] = S_G[irActive[0]];
|
|
break;
|
|
case 2:
|
|
RedSh[icActive[0]] = InvR_I_FMx[0] * S_G[irActive[0]]
|
|
+ InvR_I_FMx[1] * S_G[irActive[1]];
|
|
RedSh[icActive[1]] = InvR_I_FMx[2] * S_G[irActive[0]]
|
|
+ InvR_I_FMx[3] * S_G[irActive[1]];
|
|
break;
|
|
case 3:
|
|
RotMx_t_Vector(RedSh, InvR_I_FMx, S_G, 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (FreeMx) {
|
|
RotMx_t_Vector(Sh, FreeMx, RedSh, 0);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
Sh[i] %= (CTBF * abs(deterR_I_FMx));
|
|
} else {
|
|
for (i = 0; i < 3; i++)
|
|
Sh[i] = RedSh[i] % (CTBF * abs(deterR_I_FMx));
|
|
}
|
|
|
|
RotMx_t_Vector(CmpS_G, R_I, Sh, 0);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
if ((CmpS_G[i] -
|
|
S_G[i] * deterR_I_FMx) % (CTBF * abs(deterR_I_FMx)))
|
|
break;
|
|
|
|
if (i < 3)
|
|
continue;
|
|
|
|
if (deterR_I_FMx != 1) {
|
|
for (i = 0; i < 3; i++) {
|
|
if (Sh[i] % abs(deterR_I_FMx))
|
|
goto ReturnError;
|
|
|
|
Sh[i] /= deterR_I_FMx;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
CBMx->s.T[i] = IniCBMxT[i] + Sh[i] % CTBF;
|
|
if (CBMx->s.T[i] < 0)
|
|
CBMx->s.T[i] += CTBF;
|
|
}
|
|
|
|
if (SetInvCBMxT(CBMx->s.T, InvCBMx->s.R, InvCBMx->s.T) != 0)
|
|
return -1;
|
|
|
|
if (iGen[1] == 0)
|
|
return 1;
|
|
|
|
i = FixAxes(SgInfo, GenSgI, &iGen[1], CBMx, InvCBMx,
|
|
NextFreeMx, NextTryAgain);
|
|
if (i != 0)
|
|
return i;
|
|
}
|
|
|
|
if (TryAgain == 0)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
ReturnError:
|
|
|
|
SetSgError("Internal Error: FixAxes()");
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int CompleteCBMx(const T_SgInfo * SgInfo,
|
|
const T_LatticeInfo * NewLI,
|
|
const T_SgInfo * GenSgI, const int *IniCBMxR,
|
|
const int *IniInvCBMxR, T_RTMx * CBMx,
|
|
T_RTMx * InvCBMx)
|
|
{
|
|
int iGen[5], i;
|
|
|
|
|
|
if (SgInfo->XtalSystem == XS_Triclinic) {
|
|
for (i = 0; i < 9; i++) {
|
|
CBMx->s.R[i] = IniCBMxR[i];
|
|
InvCBMx->s.R[i] = IniInvCBMxR[i];
|
|
}
|
|
|
|
if (GenSgI->PointGroup == PG_1) {
|
|
for (i = 0; i < 3; i++) {
|
|
CBMx->s.T[i] = 0;
|
|
InvCBMx->s.T[i] = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
iGen[0] = -1;
|
|
iGen[1] = 0;
|
|
|
|
return FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Monoclinic) {
|
|
int iCCs, BufRMx[9];
|
|
int RMxCCs_Buf[9], RMxCCn_Buf[9], InvRMxCCn_Buf[9], RotLTrV[3];
|
|
const int *RMxAA, *RMxCCs, *RMxCCn, *InvRMxCCn, *TrV;
|
|
T_RTMx BufCBMx, BufInvCBMx;
|
|
|
|
|
|
if (NewLI->nTrVector != 1 && NewLI->nTrVector != 2)
|
|
goto ReturnError;
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
BufCBMx.s.R[i] = IniCBMxR[i];
|
|
BufInvCBMx.s.R[i] = IniInvCBMxR[i];
|
|
}
|
|
|
|
i = AlignUniqueAxis(SgInfo, GenSgI,
|
|
BufCBMx.s.R, BufInvCBMx.s.R, &RMxAA);
|
|
if (i != 1)
|
|
return i;
|
|
|
|
if (GenSgI->nList < 2)
|
|
goto ReturnError;
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
RMxCCs_Buf[i] = RMx_2_110[i];
|
|
RMxCCn_Buf[i] = RMx_3_001[i];
|
|
}
|
|
|
|
switch (GenSgI->ListRotMxInfo[1].RefAxis) {
|
|
case 'z':
|
|
break;
|
|
case 'x':
|
|
RotateRotMx(RMxCCs_Buf, RMx_3_111, RMx_3i111);
|
|
RotateRotMx(RMxCCn_Buf, RMx_3_111, RMx_3i111);
|
|
break;
|
|
case 'y':
|
|
RotateRotMx(RMxCCs_Buf, RMx_3i111, RMx_3_111);
|
|
RotateRotMx(RMxCCn_Buf, RMx_3i111, RMx_3_111);
|
|
break;
|
|
default:
|
|
goto ReturnError;
|
|
}
|
|
|
|
InverseRotMx(RMxCCn_Buf, InvRMxCCn_Buf);
|
|
|
|
i = 0;
|
|
iGen[i++] = 1;
|
|
if (GenSgI->PointGroup == PG_2_m)
|
|
iGen[i++] = -1;
|
|
iGen[i] = 0;
|
|
|
|
RMxCCs = RMx_1_000;
|
|
|
|
for (iCCs = 0; iCCs < 2; iCCs++, RMxCCs = RMxCCs_Buf) {
|
|
RMxCCn = InvRMxCCn = RMx_1_000;
|
|
|
|
for (;;) {
|
|
if (NewLI->nTrVector == 2) {
|
|
RotMx_t_Vector(RotLTrV, RMxAA, &NewLI->TrVector[3], STBF);
|
|
RotMx_t_Vector(BufRMx, RMxCCn, RotLTrV, STBF);
|
|
RotMx_t_Vector(RotLTrV, RMxCCs, BufRMx, STBF);
|
|
|
|
TrV = &GenSgI->LatticeInfo->TrVector[3];
|
|
|
|
for (i = 0; i < 3; i++)
|
|
if (RotLTrV[i] != TrV[i])
|
|
break;
|
|
}
|
|
|
|
if (NewLI->nTrVector == 1 || i == 3) {
|
|
RotMxMultiply(BufRMx, RMxCCn, BufCBMx.s.R);
|
|
RotMxMultiply(CBMx->s.R, RMxCCs, BufRMx);
|
|
|
|
RotMxMultiply(BufRMx, BufInvCBMx.s.R, InvRMxCCn);
|
|
RotMxMultiply(InvCBMx->s.R, BufRMx, RMxCCs);
|
|
|
|
i = FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
if (i != 0)
|
|
return i;
|
|
}
|
|
|
|
if (RMxCCn == RMx_1_000) {
|
|
RMxCCn = RMxCCn_Buf;
|
|
InvRMxCCn = InvRMxCCn_Buf;
|
|
} else if (RMxCCn == RMxCCn_Buf) {
|
|
RMxCCn = InvRMxCCn_Buf;
|
|
InvRMxCCn = RMxCCn_Buf;
|
|
} else {
|
|
RMxCCn = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
CBMx->s.R[i] = IniCBMxR[i];
|
|
InvCBMx->s.R[i] = IniInvCBMxR[i];
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Orthorhombic) {
|
|
int iNextBasis;
|
|
int BufCBMxR[9], BufInvCBMxR[9];
|
|
int NLTrV_Buf1[3], NLTrV_Buf2[3];
|
|
const int *NLTrV, *GLTrV;
|
|
|
|
|
|
if ((GenSgI->LatticeInfo->Code == 'I') != (NewLI->Code == 'I'))
|
|
return 0;
|
|
|
|
if (NewLI->Code == 'A' || NewLI->Code == 'B' || NewLI->Code == 'C') {
|
|
NLTrV = &NewLI->TrVector[3];
|
|
GLTrV = &GenSgI->LatticeInfo->TrVector[3];
|
|
} else {
|
|
NLTrV = NULL;
|
|
GLTrV = NULL;
|
|
}
|
|
i = 0;
|
|
iGen[i++] = 1;
|
|
iGen[i++] = 2;
|
|
if (GenSgI->PointGroup == PG_mmm)
|
|
iGen[i++] = -1;
|
|
iGen[i] = 0;
|
|
|
|
for (iNextBasis = 0; iNextBasis < 6; iNextBasis++) {
|
|
if (iNextBasis % 2) {
|
|
RotMxMultiply(BufCBMxR, RMx_2_110, CBMx->s.R);
|
|
RotMxMultiply(BufInvCBMxR, InvCBMx->s.R, RMx_2_110);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
CBMx->s.R[i] = BufCBMxR[i];
|
|
InvCBMx->s.R[i] = BufInvCBMxR[i];
|
|
}
|
|
} else if (iNextBasis == 2) {
|
|
RotMxMultiply(CBMx->s.R, RMx_3_111, IniCBMxR);
|
|
RotMxMultiply(InvCBMx->s.R, IniInvCBMxR, RMx_3i111);
|
|
} else if (iNextBasis) {
|
|
RotMxMultiply(CBMx->s.R, RMx_3i111, IniCBMxR);
|
|
RotMxMultiply(InvCBMx->s.R, IniInvCBMxR, RMx_3_111);
|
|
}
|
|
|
|
if (NLTrV) {
|
|
if (iNextBasis % 2) {
|
|
RotMx_t_Vector(NLTrV_Buf1, RMx_2_110, NLTrV, STBF);
|
|
NLTrV = NLTrV_Buf1;
|
|
} else if (iNextBasis == 2) {
|
|
RotMx_t_Vector(NLTrV_Buf2, RMx_3_111, &NewLI->TrVector[3], STBF);
|
|
NLTrV = NLTrV_Buf2;
|
|
} else if (iNextBasis) {
|
|
RotMx_t_Vector(NLTrV_Buf2, RMx_3i111, &NewLI->TrVector[3], STBF);
|
|
NLTrV = NLTrV_Buf2;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
if (NLTrV[i] != GLTrV[i])
|
|
break;
|
|
|
|
if (i < 3)
|
|
continue;
|
|
}
|
|
|
|
i = FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
if (i != 0)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Tetragonal) {
|
|
i = AlignUniqueAxis(SgInfo, GenSgI, CBMx->s.R, InvCBMx->s.R, NULL);
|
|
if (i != 1)
|
|
return -1;
|
|
i = 0;
|
|
iGen[i++] = 1;
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_422:
|
|
case PG_4mm:
|
|
case PG_4b2m:
|
|
case PG_4bm2:
|
|
case PG_4_mmm:
|
|
iGen[i++] = 2;
|
|
}
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_4_m:
|
|
case PG_4_mmm:
|
|
iGen[i++] = -1;
|
|
}
|
|
iGen[i] = 0;
|
|
|
|
return FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Trigonal) {
|
|
i = AlignUniqueAxis(SgInfo, GenSgI, CBMx->s.R, InvCBMx->s.R, NULL);
|
|
if (i != 1)
|
|
return i;
|
|
i = 0;
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_3:
|
|
case PG_312:
|
|
case PG_32:
|
|
case PG_3m1:
|
|
case PG_3m:
|
|
iGen[i++] = 1;
|
|
break;
|
|
case PG_3b:
|
|
case PG_3bm1:
|
|
case PG_3b1m:
|
|
case PG_3bm:
|
|
iGen[i++] = -3;
|
|
}
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_321:
|
|
case PG_312:
|
|
case PG_32:
|
|
case PG_3m1:
|
|
case PG_31m:
|
|
case PG_3m:
|
|
case PG_3bm1:
|
|
case PG_3b1m:
|
|
case PG_3bm:
|
|
iGen[i++] = 2;
|
|
}
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_321:
|
|
case PG_31m:
|
|
iGen[i++] = 1;
|
|
}
|
|
iGen[i] = 0;
|
|
|
|
return FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Hexagonal) {
|
|
i = AlignUniqueAxis(SgInfo, GenSgI, CBMx->s.R, InvCBMx->s.R, NULL);
|
|
if (i != 1)
|
|
return -1;
|
|
i = 0;
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_6bm2:
|
|
case PG_6b2m:
|
|
iGen[i++] = 2;
|
|
}
|
|
iGen[i++] = 1;
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_622:
|
|
case PG_6mm:
|
|
case PG_6_mmm:
|
|
iGen[i++] = 2;
|
|
}
|
|
|
|
switch (GenSgI->PointGroup) {
|
|
case PG_6_m:
|
|
case PG_6_mmm:
|
|
iGen[i++] = -1;
|
|
}
|
|
iGen[i] = 0;
|
|
|
|
return FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
}
|
|
|
|
if (SgInfo->XtalSystem == XS_Cubic) {
|
|
i = 0;
|
|
iGen[i++] = 3;
|
|
iGen[i++] = 1;
|
|
iGen[i++] = 2;
|
|
if (GenSgI->PointGroup == PG_m3b || GenSgI->PointGroup == PG_m3bm)
|
|
iGen[i++] = -1;
|
|
iGen[i] = 0;
|
|
|
|
return FixAxes(SgInfo, GenSgI, iGen, CBMx, InvCBMx, NULL, 0);
|
|
}
|
|
|
|
return 0;
|
|
|
|
ReturnError:
|
|
|
|
SetSgError("Internal Error: CompleteCBMx()");
|
|
return -1;
|
|
}
|
|
|
|
|
|
const T_TabSgName *FindReferenceSpaceGroup(T_SgInfo * SgInfo,
|
|
T_RTMx * CBMx, T_RTMx * InvCBMx)
|
|
{
|
|
int stat, NewPG, SgInfo_CI, OL_SgInfo, OL_GenSgI;
|
|
const T_TabSgName *tsgn;
|
|
T_SgInfo GenSgI;
|
|
T_RTMx GenSgI_ListSeitzMx[5];
|
|
T_RotMxInfo GenSgI_ListRotMxInfo[5];
|
|
int iList, PrevSgNumber;
|
|
int FacIniCBMxR;
|
|
T_RotMxInfo *lrmxi;
|
|
const T_LatticeInfo *NewLI;
|
|
int IniCBMxR[9], IniInvCBMxR[9];
|
|
|
|
|
|
GenSgI.MaxList = 5;
|
|
GenSgI.ListSeitzMx = GenSgI_ListSeitzMx;
|
|
GenSgI.ListRotMxInfo = GenSgI_ListRotMxInfo;
|
|
|
|
FacIniCBMxR =
|
|
InitialCBMxR(SgInfo, &NewLI, &NewPG, IniCBMxR, IniInvCBMxR);
|
|
if (FacIniCBMxR < 0)
|
|
return NULL;
|
|
|
|
OL_SgInfo = SgInfo->OrderL;
|
|
if (OL_SgInfo % FacIniCBMxR)
|
|
goto ReturnError;
|
|
|
|
OL_SgInfo /= FacIniCBMxR;
|
|
|
|
SgInfo_CI = (SgInfo->Centric || SgInfo->InversionOffOrigin);
|
|
|
|
PrevSgNumber = 0;
|
|
|
|
for (tsgn = TabSgName; tsgn->HallSymbol; tsgn++) {
|
|
if (tsgn->HallSymbol[1] == 'R')
|
|
continue;
|
|
|
|
if (VolAPointGroups[tsgn->SgNumber] != NewPG)
|
|
continue;
|
|
|
|
if (tsgn->SgNumber == PrevSgNumber)
|
|
continue;
|
|
|
|
PrevSgNumber = tsgn->SgNumber;
|
|
|
|
InitSgInfo(&GenSgI);
|
|
GenSgI.GenOption = -1;
|
|
|
|
ParseHallSymbol(tsgn->HallSymbol, &GenSgI);
|
|
|
|
if (SgError != NULL)
|
|
return NULL;
|
|
|
|
if (ApplyOriginShift(&GenSgI) < 0)
|
|
return NULL;
|
|
|
|
if (SgInfo_CI != (GenSgI.Centric || GenSgI.InversionOffOrigin))
|
|
goto ReturnError;
|
|
|
|
OL_GenSgI = GenSgI.LatticeInfo->nTrVector;
|
|
|
|
if (SgInfo_CI)
|
|
OL_GenSgI *= 2;
|
|
|
|
lrmxi = &GenSgI.ListRotMxInfo[1];
|
|
|
|
for (iList = 1; iList < GenSgI.nList; iList++, lrmxi++) {
|
|
OL_GenSgI *= abs(lrmxi->Order);
|
|
|
|
if ((lrmxi->Order == -1 || lrmxi->Order == -3)
|
|
&& GenSgI.Centric == 0 && GenSgI.InversionOffOrigin == 0)
|
|
goto ReturnError;
|
|
}
|
|
|
|
if (OL_GenSgI == OL_SgInfo) {
|
|
if (NewLI->nTrVector != GenSgI.LatticeInfo->nTrVector)
|
|
goto ReturnError;
|
|
|
|
GenSgI.PointGroup = NewPG;
|
|
|
|
#if DEBUG_FindConventionalSetting
|
|
fprintf(stdout, "%s ?= %s (%d)\n",
|
|
SgInfo->HallSymbol, tsgn->HallSymbol, tsgn->SgNumber);
|
|
#endif
|
|
|
|
stat = CompleteCBMx(SgInfo, NewLI, &GenSgI,
|
|
IniCBMxR, IniInvCBMxR, CBMx, InvCBMx);
|
|
if (stat < 0)
|
|
return NULL;
|
|
|
|
if (stat)
|
|
return tsgn;
|
|
}
|
|
}
|
|
|
|
SetSgError("Internal Error: Space Group not found");
|
|
return NULL;
|
|
|
|
ReturnError:
|
|
|
|
SetSgError("Internal Error: FindReferenceSpaceGroup()");
|
|
return NULL;
|
|
}
|