/* Space Group Info's (c) 1994-96 Ralf W. Grosse-Kunstleve */ #include #include #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; }