Files
sics/sgio.c
koennecke 91d4af0541 - Adapted indenation to new agreed upon system
- Added support for second generation scriptcontext based counter
2009-02-13 09:00:03 +00:00

1844 lines
38 KiB
C

/*
Space Group Info's (c) 1994-96 Ralf W. Grosse-Kunstleve
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define SGCOREDEF__
#include "sginfo.h"
typedef struct {
int OriginChoice;
int CellChoice;
int BasisChoice;
const char *BT_or_UA;
} T_ExtInfo;
static const char *Ext_BT_or_UA[] = {
/* 0 */ "abc",
/* 1 */ "ba-c",
/* 2 */ "cab",
/* 3 */ "-cba",
/* 4 */ "bca",
/* 5 */ "a-cb",
/* 6 */ "bac",
/* 6 -> 1 */
/* 7 */ "cba",
/* 7 -> 3 */
/* 8 */ "acb",
/* 8 -> 5 */
/* 9 */ "-b", "b-", "bb", "bb",
/* 10, 11, 12 -> 9 */
/* 13 */ "-c", "c-", "bc", "cb",
/* 14, 15, 16 -> 13 */
/* 17 */ "-a", "a-", "ba", "ab",
/* 18, 19, 20 -> 17 */
/* 21 */ "b",
/* 22 */ "c",
/* 23 */ "a",
NULL
};
typedef struct {
int Improper, Rotation, RefAxis, DirCode, Screw;
T_RTMx SeitzMx;
} T_HallGenerator;
#define SkipWhite(cp) while (*(cp) && (*(cp) == '_' || isspace(*(cp)))) (cp)++
static const char *IErr_Corrupt_TabSgName =
"Internal Error: Corrupt TabSgName";
static int FindSchoenfliesSymbol(const char *SfSymbol)
{
int SgNumber;
const char **TabSymbol;
const char *s, *t;
TabSymbol = SchoenfliesSymbols + 1;
for (SgNumber = 1; SgNumber <= 230; SgNumber++) {
t = *TabSymbol;
s = SfSymbol;
while (*t && *s) {
if (toupper(*t) != toupper(*s)
&& (*t != '^' || isalpha(*s) || isdigit(*s)))
break;
t++;
s++;
}
if (*t == *s)
return SgNumber;
TabSymbol++;
}
return -1;
}
static int SgLabelCmp(const int SgNumber,
const char *SgLabel, const char *WtdLbl)
{
const char *sgl, *wl;
/* first try: plain strcmp
*/
sgl = SgLabel;
for (wl = WtdLbl;; wl++) {
SkipWhite(wl);
SkipWhite(sgl);
if (*sgl == '\0' || *sgl == '=') {
if (*wl == '\0')
return 0;
break;
}
if (*sgl == '-') {
if (*wl != '-' && toupper(*wl) != 'B')
break;
} else if (toupper(*sgl) != toupper(*wl))
break;
sgl++;
}
/* second try: swap the dash (there should be only one)
*/
sgl = SgLabel;
for (wl = WtdLbl;; wl++) {
SkipWhite(wl);
SkipWhite(sgl);
if (*sgl == '-') {
if (wl[1] != '-' && toupper(wl[1]) != 'B')
break;
if (toupper(sgl[1]) != toupper(*wl))
break;
sgl++;
wl++;
} else {
if (*sgl == '\0' || *sgl == '=') {
if (*wl == '\0')
return 0;
break;
}
if (toupper(*sgl) != toupper(*wl))
break;
}
sgl++;
}
if (SgNumber >= 195) { /* cubic space groups only */
/* third try: ignore the "-3" dash
*/
sgl = SgLabel;
for (wl = WtdLbl;; wl++) {
SkipWhite(wl);
SkipWhite(sgl);
if (*sgl == '-' && sgl[1] == '3')
sgl++;
if (*sgl == '\0' || *sgl == '=') {
if (*wl == '\0')
return 0;
break;
}
if (toupper(*sgl) != toupper(*wl))
break;
sgl++;
}
}
return -1;
}
static int ParseExtension(const char *Ext, T_ExtInfo * ExtInfo)
{
int i, mode;
const char *e, *t;
ExtInfo->OriginChoice = ExtInfo->CellChoice = ExtInfo->BasisChoice = ' ';
ExtInfo->BT_or_UA = "";
mode = 0;
while (*Ext) {
if (strchr("12", *Ext) != NULL) {
ExtInfo->CellChoice = ExtInfo->OriginChoice = *Ext++;
} else if (strchr("3", *Ext) != NULL) {
ExtInfo->CellChoice = *Ext++;
} else if (strchr("Ss", *Ext) != NULL) {
ExtInfo->OriginChoice = '1';
Ext++;
} else if (strchr("Zz", *Ext) != NULL) {
ExtInfo->OriginChoice = '2';
Ext++;
} else if (strchr("Hh", *Ext) != NULL) {
ExtInfo->BasisChoice = 'H';
Ext++;
} else if (strchr("Rr", *Ext) != NULL) {
ExtInfo->BasisChoice = 'R';
Ext++;
} else if (mode == 0)
mode = 1;
if (mode == 2)
break;
for (i = 0; Ext_BT_or_UA[i]; i++) {
for (e = Ext, t = Ext_BT_or_UA[i]; *t; e++, t++)
if (toupper(*e) != toupper(*t))
break;
if (*t == '\0') {
if (6 <= i && i <= 8)
i = 2 * i - 11;
else if (9 <= i && i <= 20)
i = 9 + ((i - 9) / 4) * 4;
ExtInfo->BT_or_UA = Ext_BT_or_UA[i];
Ext = e;
break;
}
}
if (mode == 0)
break;
mode = 2;
}
if (*Ext)
return -1;
return 0;
}
static void ExpandMonoclinic(int unique_axis, const char *o, char *m)
{
if (*o)
*m++ = *o++;
switch (tolower(unique_axis)) {
case 'a':
while (*o)
*m++ = *o++;
*m++ = '1';
*m++ = '1';
break;
case 'c':
*m++ = '1';
*m++ = '1';
while (*o)
*m++ = *o++;
break;
default:
*m++ = '1';
while (*o)
*m++ = *o++;
*m++ = '1';
break;
}
*m = '\0';
}
const T_TabSgName *FindTabSgNameEntry(const char *UserSgName,
int VolLetter)
{
#define MaxWtdLbl 20
char WtdLblOriginal[MaxWtdLbl + 1];
char WtdLblModified[MaxWtdLbl + 1];
char *WtdLbl;
#define MaxWtdExt 5
char WtdExt[MaxWtdExt + 1];
int WtdSgNumber;
int WtdLblOriginChoice;
int WtdLblBasisChoice;
int iwl, iwe;
char *wl, *we;
int i, IsExpanded, lbl_match;
const char *sgl;
const T_TabSgName *tsgn;
int WtdCC;
const char *WtdUA;
char WtdUA_Buf[2];
T_ExtInfo ExtInfo, WtdExtInfo;
if (VolLetter == 0 || isspace(VolLetter))
VolLetter = 'A';
else if (VolLetter == '1')
VolLetter = 'I';
else {
VolLetter = toupper(VolLetter);
if (VolLetter != 'I' && VolLetter != 'A')
return NULL;
}
WtdLbl = WtdLblOriginal;
wl = WtdLbl;
iwl = 0;
while (*UserSgName && *UserSgName != ':') {
if (isspace(*UserSgName) == 0 && *UserSgName != '_') {
if (iwl >= MaxWtdLbl)
return NULL;
*wl++ = *UserSgName;
iwl++;
}
UserSgName++;
}
*wl = '\0';
if (iwl == 0)
return NULL;
we = WtdExt;
iwe = 0;
*we = '\0';
if (*UserSgName) {
UserSgName++;
while (*UserSgName) {
if (isspace(*UserSgName) == 0 && *UserSgName != '_') {
if (iwe >= MaxWtdExt)
return NULL;
*we++ = *UserSgName;
iwe++;
}
UserSgName++;
}
}
*we = '\0';
WtdLblOriginChoice = ' ';
WtdLblBasisChoice = ' ';
if (iwl > 1) {
wl = &WtdLbl[iwl - 1];
if (*wl == 'S' || *wl == 's') {
WtdLblOriginChoice = '1';
*wl = '\0';
iwl--;
} else if (*wl == 'Z' || *wl == 'z') {
WtdLblOriginChoice = '2';
*wl = '\0';
iwl--;
} else if (*wl == 'H' || *wl == 'h') {
WtdLblBasisChoice = 'H';
*wl = '\0';
iwl--;
} else if (*wl == 'R' || *wl == 'r') {
WtdLblBasisChoice = 'R';
*wl = '\0';
iwl--;
}
}
if (isalpha(WtdLbl[0]))
WtdSgNumber = FindSchoenfliesSymbol(WtdLbl);
else {
for (wl = WtdLbl; *wl; wl++)
if (isdigit(*wl) == 0)
return NULL;
if (sscanf(WtdLbl, "%d", &WtdSgNumber) != 1
|| WtdSgNumber < 1 || WtdSgNumber > 230)
return NULL;
}
if (ParseExtension(WtdExt, &WtdExtInfo) != 0)
return NULL;
if (WtdExtInfo.OriginChoice == ' ')
WtdExtInfo.OriginChoice = WtdLblOriginChoice;
else if (WtdExtInfo.OriginChoice != WtdLblOriginChoice
&& WtdLblOriginChoice != ' ')
return NULL;
if (WtdExtInfo.BasisChoice == ' ')
WtdExtInfo.BasisChoice = WtdLblBasisChoice;
else if (WtdExtInfo.BasisChoice != WtdLblBasisChoice
&& WtdLblBasisChoice != ' ')
return NULL;
if (WtdExtInfo.OriginChoice != ' ' && WtdExtInfo.BasisChoice != ' ')
return NULL;
for (IsExpanded = 0; IsExpanded < 4; IsExpanded++) {
for (tsgn = TabSgName; tsgn->HallSymbol; tsgn++) {
if (IsExpanded != 0 && tsgn->SgNumber > 15)
break;
lbl_match = 0;
if (WtdSgNumber == -1) {
i = 1;
sgl = tsgn->SgLabels;
while (*sgl && i <= 2) {
while (*sgl && strchr(" =\t", *sgl) != NULL)
sgl++;
if (SgLabelCmp(tsgn->SgNumber, sgl, WtdLbl) == 0) {
lbl_match = i;
break;
}
while (*sgl && strchr(" =\t", *sgl) == NULL)
sgl++;
i++;
}
}
if (ParseExtension(tsgn->Extension, &ExtInfo) != 0) {
SetSgError(IErr_Corrupt_TabSgName);
return NULL;
}
if (WtdSgNumber == tsgn->SgNumber || lbl_match != 0) {
if (tsgn->SgNumber >= 3 && tsgn->SgNumber < 16) {
if (WtdLblOriginChoice != ' '
|| WtdExtInfo.BasisChoice != ' '
|| (int) strlen(WtdExtInfo.BT_or_UA) > 2)
continue; /* next tsgn */
if (WtdSgNumber == tsgn->SgNumber) {
if (WtdExtInfo.BT_or_UA[0])
WtdUA = WtdExtInfo.BT_or_UA;
else if (VolLetter == 'I') {
if (ExtInfo.BT_or_UA[0] != 'c' && ExtInfo.BT_or_UA[1] != 'c')
continue; /* next tsgn */
if (ExtInfo.CellChoice == ' '
&& (WtdExtInfo.CellChoice == ' '
|| WtdExtInfo.CellChoice == '1'))
return tsgn;
i = 0;
for (sgl = tsgn->SgLabels; *sgl; sgl++)
if (*sgl == '=')
i++;
if (i == 2
&& (WtdExtInfo.CellChoice == ' '
|| WtdExtInfo.CellChoice == ExtInfo.CellChoice))
return tsgn;
continue; /* next tsgn */
} else
WtdUA = "b";
} else { /* if (lbl_match != 0) */
if (WtdExtInfo.BT_or_UA[0])
WtdUA = WtdExtInfo.BT_or_UA;
else if (lbl_match > 1)
WtdUA = ExtInfo.BT_or_UA;
else if (VolLetter == 'I' && ExtInfo.CellChoice == ' ')
WtdUA = "c";
else
WtdUA = "b";
}
if (WtdExtInfo.CellChoice != ' ')
WtdCC = WtdExtInfo.CellChoice;
else if (ExtInfo.CellChoice == '1')
WtdCC = ExtInfo.CellChoice;
else
WtdCC = ' ';
if (strcmp(ExtInfo.BT_or_UA, WtdUA) == 0) {
if (WtdCC == ' ' && lbl_match > 1)
return tsgn;
if (ExtInfo.CellChoice == WtdCC)
return tsgn;
if (ExtInfo.CellChoice == ' ' && WtdCC == '1')
return tsgn;
if (ExtInfo.CellChoice == '1' && WtdCC == ' ')
return tsgn;
}
} else if (ExtInfo.BasisChoice != ' ') {
if (WtdExtInfo.OriginChoice != ' '
|| WtdExtInfo.CellChoice != ' '
|| WtdExtInfo.BT_or_UA[0] != '\0')
continue; /* next tsgn */
if (ExtInfo.BasisChoice == WtdExtInfo.BasisChoice)
return tsgn;
if (WtdExtInfo.BasisChoice == ' ') {
if (ExtInfo.BasisChoice == 'R' && VolLetter == 'I')
return tsgn;
if (ExtInfo.BasisChoice == 'H' && VolLetter != 'I')
return tsgn;
}
} else if (WtdExtInfo.BasisChoice == ' ') {
if ((WtdExtInfo.OriginChoice == ' '
&& ExtInfo.OriginChoice == '1')
|| (WtdExtInfo.OriginChoice == '1'
&& ExtInfo.OriginChoice == ' ')
|| WtdExtInfo.OriginChoice == ExtInfo.OriginChoice) {
if (WtdExtInfo.BT_or_UA[0]) {
if (WtdExtInfo.BT_or_UA == ExtInfo.BT_or_UA)
return tsgn;
if (WtdExtInfo.BT_or_UA == Ext_BT_or_UA[0]
&& ExtInfo.BT_or_UA[0] == '\0')
return tsgn;
} else {
if (lbl_match != 0)
return tsgn;
if (ExtInfo.BT_or_UA[0] == '\0')
return tsgn;
}
}
}
}
}
if (WtdSgNumber != -1)
return NULL;
if ((int) strlen(WtdExtInfo.BT_or_UA) > 2)
return NULL;
if (IsExpanded == 0) {
iwl += 2;
if (iwl > MaxWtdLbl)
IsExpanded = 2;
else {
if (WtdExtInfo.BT_or_UA[0])
WtdUA = WtdExtInfo.BT_or_UA;
else {
if (VolLetter == 'I')
WtdUA = "c";
else
WtdUA = "b";
}
ExpandMonoclinic(WtdUA[0], WtdLblOriginal, WtdLblModified);
WtdLbl = WtdLblModified;
}
} else if (IsExpanded == 1) {
if (WtdExtInfo.BT_or_UA[0])
return NULL;
if (VolLetter == 'I')
WtdUA = "b";
else
WtdUA = "c";
ExpandMonoclinic(WtdUA[0], WtdLblOriginal, WtdLblModified);
}
if (IsExpanded == 2) {
if (WtdExtInfo.BT_or_UA[0])
return NULL;
iwl -= 2;
if (iwl < 2)
return NULL;
iwl--;
WtdUA_Buf[0] = tolower(WtdLblOriginal[iwl]);
WtdLblOriginal[iwl] = '\0';
WtdUA_Buf[1] = '\0';
if (strchr("abc", WtdUA_Buf[0]) == NULL)
return NULL;
WtdUA = WtdUA_Buf;
iwl += 2;
if (iwl > MaxWtdLbl)
return NULL;
ExpandMonoclinic(WtdUA[0], WtdLblOriginal, WtdLblModified);
WtdLbl = WtdLblModified;
}
}
return NULL;
}
unsigned int SgID_Number(const T_TabSgName * tsgn)
{
unsigned int ID;
int iBT;
const char *UA;
T_ExtInfo ExtInfo;
ID = tsgn->SgNumber;
if (ParseExtension(tsgn->Extension, &ExtInfo) != 0)
ID = 0;
if (ID >= 3 && ID < 16) {
UA = ExtInfo.BT_or_UA;
if (*UA != 'b'
|| (ExtInfo.CellChoice != ' ' && ExtInfo.CellChoice != '1')) {
if (*UA == '-') {
ID += 3000;
UA++;
}
switch (*UA) {
case 'b':
ID += 10000;
break;
case 'c':
ID += 20000;
break;
case 'a':
ID += 30000;
break;
default:
ID = 0;
break;
}
if (ID != 0) {
switch (ExtInfo.CellChoice) {
case ' ':
break;
case '1':
ID += 1000;
break;
case '2':
ID += 2000;
break;
case '3':
ID += 3000;
break;
default:
ID = 0;
break;
}
}
}
} else {
if (ExtInfo.BasisChoice == 'R')
ID += 20000;
else {
if (ExtInfo.BT_or_UA[0]) {
for (iBT = 0; iBT < 6; iBT++)
if (ExtInfo.BT_or_UA == Ext_BT_or_UA[iBT])
break;
} else
iBT = 0;
if (iBT < 6) {
if (ExtInfo.OriginChoice == '2')
ID += 20000;
else if (iBT)
ID += 10000;
if (iBT)
ID += (iBT + 1) * 1000;
} else
ID = 0;
}
}
if (ID == 0)
SetSgError(IErr_Corrupt_TabSgName);
return ID;
}
int ParseSymXYZ(const char *SymXYZ, T_RTMx * SeitzMx, int FacTr)
{
unsigned int P_mode;
int Row, Column, Sign, GotXYZ, i;
double Value, Value1, Value2, Delta;
for (i = 0; i < 12; i++)
SeitzMx->a[i] = 0;
#define P_Blank 0x01u
#define P_Comma 0x02u
#define P_Plus 0x04u
#define P_Dash 0x08u
#define P_Slash 0x10u
#define P_Value1 0x20u
#define P_Value2 0x40u
#define P_XYZ 0x80u
Value1 = 0.;
Row = 0;
Sign = 1;
Value = 0.;
GotXYZ = 0;
P_mode = P_Blank | P_Plus | P_Dash | P_Value1 | P_XYZ;
do {
switch (*SymXYZ) {
case ' ':
case '\t':
case '_':
if ((P_mode & P_Blank) == 0)
return -1;
break;
case ',':
case ';':
if (Row == 2)
return -1;
case '\0':
if ((P_mode & P_Comma) == 0)
return -1;
if (GotXYZ == 0)
return -1;
if (P_mode & P_Slash)
Value += Value1;
Value *= FacTr;
if (Value < 0.)
i = Value - .5;
else
i = Value + .5;
Delta = Value - i;
if (Delta < 0.)
Delta = -Delta;
if (Delta > .01 * FacTr)
return -1;
i %= FacTr;
if (i < 0)
i += FacTr;
SeitzMx->s.T[Row] = i;
Row++;
Sign = 1;
Value = 0.;
P_mode = P_Blank | P_Plus | P_Dash | P_Value1 | P_XYZ;
GotXYZ = 0;
break;
case '+':
if ((P_mode & P_Plus) == 0)
return -1;
if (P_mode & P_Slash)
Value += Value1;
Sign = 1;
if (P_mode & P_Value2)
P_mode = P_Value2;
else
P_mode = P_Blank | P_Value1 | P_XYZ;
break;
case '-':
if ((P_mode & P_Dash) == 0)
return -1;
if (P_mode & P_Slash)
Value += Value1;
Sign = -1;
if (P_mode & P_Value2)
P_mode = P_Value2;
else
P_mode = P_Blank | P_Value1 | P_XYZ;
break;
case '/':
case ':':
if ((P_mode & P_Slash) == 0)
return -1;
Sign = 1;
P_mode = P_Blank | P_Plus | P_Dash | P_Value2;
break;
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (P_mode & P_Value1) {
if (sscanf(SymXYZ, "%lf%n", &Value1, &i) != 1)
return -1;
if (Sign == -1)
Value1 = -Value1;
P_mode = P_Blank | P_Comma | P_Plus | P_Dash | P_Slash;
} else if (P_mode & P_Value2) {
if (sscanf(SymXYZ, "%lf%n", &Value2, &i) != 1)
return -1;
if (Sign == -1)
Value2 = -Value2;
if (Value1 != 0.) {
if (Value2 == 0.)
return -1;
Value += Value1 / Value2;
}
P_mode = P_Blank | P_Comma | P_Plus | P_Dash;
} else
return -1;
SymXYZ += (i - 1);
break;
case 'X':
case 'x':
Column = 0;
goto Process_XYZ;
case 'Y':
case 'y':
Column = 1;
goto Process_XYZ;
case 'Z':
case 'z':
Column = 2;
Process_XYZ:
if ((P_mode & P_XYZ) == 0)
return -1;
i = Row * 3 + Column;
if (SeitzMx->s.R[i] != 0)
return -1;
SeitzMx->s.R[i] = Sign;
GotXYZ = 1;
P_mode = P_Blank | P_Comma | P_Plus | P_Dash;
break;
}
}
while (*SymXYZ++);
if (Row != 3)
return -1;
return 0;
#undef P_Blank
#undef P_Comma
#undef P_Plus
#undef P_Dash
#undef P_Slash
#undef P_Value1
#undef P_Value2
#undef P_XYZ
}
static int LookupRotMx(T_HallGenerator * HG)
{
int i, f, refaxis, dircode;
int iNextBasis, nNextBasis;
const T_TabXtalRotMx *txrmx;
if (HG->Rotation <= 0)
return 0;
refaxis = HG->RefAxis;
dircode = HG->DirCode;
if (HG->Rotation == 1) {
refaxis = 'o';
dircode = '.';
nNextBasis = 0;
} else if (dircode == '*') {
if (refaxis == 0)
refaxis = 'o';
nNextBasis = 0;
} else {
if (dircode == 0)
dircode = '=';
switch (refaxis) {
case 'z':
nNextBasis = 0;
break;
case 'x':
nNextBasis = 1;
break;
case 'y':
nNextBasis = 2;
break;
default:
return 0;
}
}
for (txrmx = TabXtalRotMx; txrmx->Order; txrmx++)
if (txrmx->Order == HG->Rotation)
break;
while (txrmx->Order == HG->Rotation) {
if (txrmx->DirCode == dircode) {
if (HG->Improper == 0)
f = 1;
else
f = -1;
for (i = 0; i < 9; i++)
HG->SeitzMx.s.R[i] = txrmx->RMx[i] * f;
for (iNextBasis = 0; iNextBasis < nNextBasis; iNextBasis++)
RotateRotMx(HG->SeitzMx.s.R, RMx_3_111, RMx_3i111);
return 1;
}
txrmx++;
}
return 0;
}
int ParseHallSymbol(const char *hsym, T_SgInfo * SgInfo)
{
int c, i, pos_hsym;
const int *ht;
int Centric;
const T_LatticeInfo *LatticeInfo;
int FieldType, PreviousFT;
int iOriginShift, SignOriginShift;
int digit, rotation, refaxis, dircode;
const int *translation;
int PreviousRotation, PreviousRefAxis;
int nHG, ClearHG;
T_HallGenerator HG;
enum ListOfFieldTypes {
FT_Delimiter,
FT_Improper,
FT_Digit,
FT_Rotation,
FT_RefAxis,
FT_DirCode,
FT_Translation,
FT_OriginShift
};
static const char *Err_Ill_ori_shi_val =
"Error: Illegal origin shift value";
static const char *Err_Too_ori_shi_val =
"Error: Too much origin shift values";
Centric = 0;
LatticeInfo = NULL;
HG.Rotation = HG.RefAxis = HG.DirCode = HG.Screw = 0;
nHG = 0;
ClearHG = 1;
FieldType = FT_Delimiter;
PreviousRotation = 0;
PreviousRefAxis = 0;
iOriginShift = 0;
SignOriginShift = 0;
pos_hsym = 0;
do {
if (*hsym == '_' || *hsym == '.' || *hsym == '\t' || *hsym == '\0')
c = ' ';
else
c = *hsym;
pos_hsym++;
if (LatticeInfo == NULL) {
if (Centric == 0 && c == '-') {
if (AddInversion2ListSeitzMx(SgInfo) < 0)
return pos_hsym;
Centric = 1;
} else if (c != ' ') {
c = toupper(c);
switch (c) {
case 'P':
LatticeInfo = LI_P;
break;
case 'A':
LatticeInfo = LI_A;
break;
case 'B':
LatticeInfo = LI_B;
break;
case 'C':
LatticeInfo = LI_C;
break;
case 'I':
LatticeInfo = LI_I;
break;
case 'R':
LatticeInfo = LI_R;
break;
case 'S':
LatticeInfo = LI_S;
break;
case 'T':
LatticeInfo = LI_T;
break;
case 'F':
LatticeInfo = LI_F;
break;
default:
SetSgError("Error: Illegal lattice code");
return pos_hsym;
}
if (AddLatticeTr2ListSeitzMx(SgInfo, LatticeInfo) < 0)
return pos_hsym;
}
} else if (FieldType != FT_OriginShift) {
c = tolower(c);
if (c == 'q')
c = '\'';
else if (c == '+')
c = '"';
PreviousFT = FieldType;
digit = rotation = refaxis = dircode = 0;
translation = NULL;
ht = HallTranslations;
while (*ht) {
if (c == *ht) {
translation = ht;
FieldType = FT_Translation;
break;
}
ht += 4;
}
if (translation == NULL) {
switch (c) {
case ' ':
FieldType = FT_Delimiter;
break;
case '-':
FieldType = FT_Improper;
break;
case '1':
digit = 1;
FieldType = FT_Digit;
break;
case '2':
digit = 2;
FieldType = FT_Digit;
break;
case '3':
digit = 3;
FieldType = FT_Digit;
break;
case '4':
digit = 4;
FieldType = FT_Digit;
break;
case '5':
digit = 5;
FieldType = FT_Digit;
break;
case '6':
digit = 6;
FieldType = FT_Digit;
break;
case 'x':
case 'y':
case 'z':
refaxis = c;
FieldType = FT_RefAxis;
break;
case '"':
case '\'':
case '*':
dircode = c;
FieldType = FT_DirCode;
break;
case '(':
FieldType = FT_OriginShift;
break;
default:
SetSgError("Error: Illegal character in Hall symbol");
return pos_hsym;
}
if (FieldType == FT_Digit) {
if (ClearHG == 0
&& HG.Rotation > digit && HG.Screw == 0 && HG.DirCode == 0) {
HG.Screw = digit;
FieldType = FT_Translation;
} else if (digit == 5) {
SetSgError("Error: Illegal 5-fold rotation");
return pos_hsym;
} else {
rotation = digit;
FieldType = FT_Rotation;
}
}
}
if (ClearHG == 0
&& (FieldType == FT_Delimiter
|| FieldType == FT_OriginShift
|| FieldType < PreviousFT
|| (FieldType == PreviousFT && FieldType != FT_Translation))
&& !(FieldType == FT_RefAxis && HG.RefAxis == 0
&& PreviousFT == FT_DirCode)) {
if (HG.RefAxis == 0) {
if (nHG == 0)
HG.RefAxis = 'z';
else {
if (HG.Rotation == 2) {
if (PreviousRotation == 2 || PreviousRotation == 4)
HG.RefAxis = 'x';
else if (PreviousRotation == 3 || PreviousRotation == 6) {
HG.RefAxis = PreviousRefAxis;
if (HG.DirCode == 0)
HG.DirCode = '\'';
}
} else if (HG.Rotation == 3) {
if (HG.DirCode == 0)
HG.DirCode = '*';
}
}
}
PreviousRefAxis = HG.RefAxis;
PreviousRotation = HG.Rotation;
if (LookupRotMx(&HG) == 0) {
SetSgError
("Error: Illegal generator or need explicit axis symbol");
return pos_hsym - 1;
}
if (HG.Screw) {
switch (HG.RefAxis) {
case 'x':
i = 0;
break;
case 'y':
i = 1;
break;
case 'z':
i = 2;
break;
default:
i = -1;
break;
}
if (HG.DirCode != 0 || i < 0) {
SetSgError("Error: Screw for non-principal direction");
return pos_hsym - 1;
}
HG.SeitzMx.s.T[i] += STBF * HG.Screw / HG.Rotation;
}
for (i = 0; i < 3; i++)
HG.SeitzMx.s.T[i] %= STBF;
if (Add2ListSeitzMx(SgInfo, &HG.SeitzMx) < 0)
return pos_hsym - 1;
if (SgInfo->StatusLatticeTr == -1) {
if (AddLatticeTr2ListSeitzMx(SgInfo, SgInfo->LatticeInfo) < 0)
return pos_hsym - 1;
}
nHG++;
ClearHG = 1;
}
if (FieldType != FT_Delimiter && FieldType != FT_OriginShift) {
if (ClearHG) {
HG.Improper = 0;
HG.Rotation = 1;
HG.RefAxis = 0;
HG.DirCode = 0;
HG.Screw = 0;
for (i = 0; i < 12; i++)
HG.SeitzMx.a[i] = 0;
ClearHG = 0;
}
switch (FieldType) {
case FT_Improper:
HG.Improper = 1;
break;
case FT_Rotation:
HG.Rotation = rotation;
break;
case FT_RefAxis:
HG.RefAxis = refaxis;
break;
case FT_DirCode:
HG.DirCode = dircode;
break;
case FT_Translation:
if (translation != NULL) {
for (i = 0; i < 3; i++)
HG.SeitzMx.s.T[i] += *(++translation);
}
break;
}
}
} else { /* FieldType == FT_OriginShift */
if (iOriginShift > 3) {
SetSgError(Err_Too_ori_shi_val);
return pos_hsym;
}
if (*hsym == '\0')
c = ')';
digit = -1;
switch (c) {
case ' ':
break;
case ')':
if (iOriginShift != 3) {
SetSgError("Error: Missing origin shift values");
return pos_hsym;
}
iOriginShift++;
FieldType = FT_Delimiter;
break;
case '-':
if (SignOriginShift != 0) {
SetSgError(Err_Ill_ori_shi_val);
return pos_hsym;
}
SignOriginShift = 1;
break;
case '0':
digit = 0;
break;
case '1':
digit = 1;
break;
case '2':
digit = 2;
break;
case '3':
digit = 3;
break;
case '4':
digit = 4;
break;
case '5':
digit = 5;
break;
case '6':
digit = 6;
break;
default:
SetSgError(Err_Ill_ori_shi_val);
return pos_hsym;
}
if (digit >= 0) {
if (iOriginShift >= 3) {
SetSgError(Err_Too_ori_shi_val);
return pos_hsym;
}
if (SignOriginShift)
digit *= -1;
SignOriginShift = 0;
SgInfo->OriginShift[iOriginShift++] = digit;
}
}
}
while (*hsym++ != '\0');
if (LatticeInfo == NULL) {
SetSgError("Error: Lattice type not specified");
return pos_hsym;
}
return pos_hsym;
}
static const char *PrintSgLabel(const char *lbl, int space, int *n,
FILE * fpout)
{
while (*lbl && *lbl != ' ') {
if (*lbl == '_') {
if (space) {
putc(space, fpout);
if (n)
(*n)++;
}
} else {
putc(*lbl, fpout);
if (n)
(*n)++;
}
lbl++;
}
return lbl;
}
int PrintFullHM_SgName(const T_TabSgName * tsgn, int space, FILE * fpout)
{
int n;
const char *lbl;
lbl = tsgn->SgLabels;
if (tsgn->SgNumber >= 3 && tsgn->SgNumber < 16)
while (*lbl)
if (*lbl++ == '=')
break;
SkipWhite(lbl);
n = 0;
PrintSgLabel(lbl, space, &n, fpout);
lbl = tsgn->Extension;
if (*lbl && strchr("12HhRr", *lbl)) {
putc(':', fpout);
putc(*lbl, fpout);
n += 2;
}
return n;
}
void PrintTabSgNameEntry(const T_TabSgName * tsgn, int Style, int space,
FILE * fpout)
{
int n;
const char *lbl, *SfSymbol;
if (Style)
n = fprintf(fpout, "%3d", tsgn->SgNumber);
else
n = fprintf(fpout, "%d", tsgn->SgNumber);
if (tsgn->Extension[0])
n += fprintf(fpout, ":%s", tsgn->Extension);
if (Style)
while (n < 9) {
putc(' ', fpout);
n++;
}
putc(' ', fpout);
n++;
putc(' ', fpout);
n++;
if (tsgn->SgNumber >= 1 && tsgn->SgNumber <= 230)
SfSymbol = SchoenfliesSymbols[tsgn->SgNumber];
else
SfSymbol = "";
n += fprintf(fpout, "%s", SfSymbol);
if (Style)
while (n < 23) {
putc(' ', fpout);
n++;
}
putc(' ', fpout);
n++;
putc(' ', fpout);
n++;
if (tsgn->SgNumber >= 3 && tsgn->SgNumber < 16) {
lbl = PrintSgLabel(tsgn->SgLabels, space, &n, fpout);
if (tsgn->Extension[0])
n += fprintf(fpout, ":%s", tsgn->Extension);
putc(' ', fpout);
putc('=', fpout);
putc(' ', fpout);
n += 3;
n += PrintFullHM_SgName(tsgn, space, fpout);
while (*lbl)
if (*lbl++ == '=')
break;
while (*lbl)
if (*lbl++ == '=')
break;
SkipWhite(lbl);
if (*lbl) {
putc(' ', fpout);
putc('=', fpout);
putc(' ', fpout);
n += 3;
PrintSgLabel(lbl, space, &n, fpout);
}
} else
n += PrintFullHM_SgName(tsgn, space, fpout);
if (Style)
while (n < 51) {
putc(' ', fpout);
n++;
}
putc(' ', fpout);
putc(' ', fpout);
fprintf(fpout, "%s", tsgn->HallSymbol);
}
static int FindGCD2(int ri, int rj)
{
int rk;
if (ri < 0)
ri = -ri;
if (rj) {
for (;;) {
rk = ri % rj;
if (rk == 0) {
ri = rj;
break;
}
ri = rj % rk;
if (ri == 0) {
ri = rk;
break;
}
rj = rk % ri;
if (rj == 0) {
break;
}
}
if (ri < 0)
ri = -ri;
}
return ri;
}
static void SimplifyFraction(int nume, int deno, int *o_nume, int *o_deno)
{
int gcd = FindGCD2(nume, deno);
if (gcd) {
*o_nume = nume / gcd;
*o_deno = deno / gcd;
if (*o_deno < 0) {
*o_nume *= -1;
*o_deno *= -1;
}
}
}
const char *FormatFraction(int nume, int deno, int Decimal,
char *Buffer, int SizeBuffer)
{
int n, d;
char *cp, *cpp;
static char StaticBuffer[40];
if (NULL == Buffer) {
Buffer = StaticBuffer;
SizeBuffer = sizeof StaticBuffer / sizeof(*StaticBuffer);
}
Buffer[SizeBuffer - 1] = '\0';
if (nume == 0) {
Buffer[0] = '0';
Buffer[1] = '\0';
}
if (Decimal) {
sprintf(Buffer, "%.6g", (double) nume / deno);
cp = Buffer;
if (*cp == '-')
cp++;
if (*cp == '0') {
cpp = cp + 1;
while (*cp)
*cp++ = *cpp++;
}
} else {
SimplifyFraction(nume, deno, &n, &d);
if (d == 1)
sprintf(Buffer, "%d", n);
else
sprintf(Buffer, "%d/%d", n, d);
}
if (Buffer[SizeBuffer - 1] != '\0') {
Buffer[SizeBuffer - 1] = '\0';
SetSgError("Internal Error: FormatFraction(): Buffer too small");
return NULL;
}
return Buffer;
}
const char *RTMx2XYZ(const T_RTMx * RTMx, int FacRo, int FacTr,
int Decimal, int TrFirst, int Low,
const char *Seperator,
char *BufferXYZ, int SizeBufferXYZ)
{
static const char *UpperXYZ = "XYZ";
static const char *LowerXYZ = "xyz";
int i, j, p, iRo, iTr;
char *xyz, buf_tr[32];
const char *sep, *LetterXYZ, *ro, *tr;
static char StaticBufferXYZ[80];
if (NULL == BufferXYZ) {
BufferXYZ = StaticBufferXYZ;
SizeBufferXYZ = sizeof StaticBufferXYZ / sizeof(*StaticBufferXYZ);
}
BufferXYZ[SizeBufferXYZ - 1] = '\0';
if (Low)
LetterXYZ = LowerXYZ;
else
LetterXYZ = UpperXYZ;
if (Seperator == NULL)
Seperator = ",";
xyz = BufferXYZ;
for (i = 0; i < 3; i++) {
if (i != 0)
for (sep = Seperator; *sep; sep++)
*xyz++ = *sep;
iTr = iModPositive(RTMx->s.T[i], FacTr);
if (iTr > FacTr / 2)
iTr -= FacTr;
tr = FormatFraction(iTr, FacTr, Decimal,
buf_tr, sizeof buf_tr / sizeof(*buf_tr));
if (tr == NULL)
return NULL;
p = 0;
if (TrFirst && iTr) {
if (*tr)
p = 1;
while (*tr)
*xyz++ = *tr++;
}
for (j = 0; j < 3; j++) {
iRo = RTMx->s.R[i * 3 + j];
if (iRo) {
ro = FormatFraction(iRo, FacRo, Decimal, NULL, 0);
if (ro == NULL)
return NULL;
if (*ro == '-')
*xyz++ = *ro++;
else if (*ro && p)
*xyz++ = '+';
if (ro[0] != '1' || ro[1] != '\0') {
while (*ro)
*xyz++ = *ro++;
*xyz++ = '*';
}
*xyz++ = LetterXYZ[j];
p = 1;
}
}
if (!TrFirst && iTr) {
if (*tr && *tr != '-' && p)
*xyz++ = '+';
while (*tr)
*xyz++ = *tr++;
}
}
*xyz = '\0';
if (BufferXYZ[SizeBufferXYZ - 1] != '\0') {
BufferXYZ[SizeBufferXYZ - 1] = '\0';
SetSgError("Internal Error: RTMx2XYZ(): BufferXYZ too small");
return NULL;
}
return BufferXYZ;
}
void PrintMapleRTMx(const T_RTMx * RTMx, int FacRo, int FacTr,
const char *Label, FILE * fpout)
{
int i, j, nt;
const int *r, *t;
const char *ff;
if (Label)
fprintf(fpout, "%s", Label);
fprintf(fpout, " := matrix(4,4, [");
r = RTMx->s.R;
t = RTMx->s.T;
for (i = 0; i < 3; i++, t++) {
putc(' ', fpout);
for (j = 0; j < 3; j++, r++) {
ff = FormatFraction(*r, FacRo, 0, NULL, 0);
if (ff == NULL)
return;
fprintf(fpout, "%s,", ff);
}
nt = iModPositive(*t, FacTr);
if (nt > FacTr / 2)
nt -= FacTr;
ff = FormatFraction(nt, FacTr, 0, NULL, 0);
if (ff == NULL)
return;
fprintf(fpout, "%s,", ff);
}
fprintf(fpout, " 0,0,0,1]);\n");
}
static void PrintSeitzMx(const T_RTMx * SMx, FILE * fpout)
{
int i, nt;
const char *ff;
const int *r, *t;
r = SMx->s.R;
t = SMx->s.T;
for (i = 0; i < 3; i++) {
fprintf(fpout, " %2d", *r++);
fprintf(fpout, " %2d", *r++);
fprintf(fpout, " %2d", *r++);
nt = iModPositive(*t++, STBF);
if (nt > STBF / 2)
nt -= STBF;
ff = FormatFraction(nt, STBF, 0, NULL, 0);
if (ff == NULL)
return;
fprintf(fpout, " %6s\n", ff);
}
putc('\n', fpout);
}
void ListSgInfo(const T_SgInfo * SgInfo, int F_XYZ, int F_Verbose,
FILE * fpout)
{
int iList, i_si_v;
char buf[8];
const char *xyz;
const T_RTMx *lsmx;
T_RotMxInfo *rmxi, RotMxInfo;
iList = PG_Index(SgInfo->PointGroup);
fprintf(fpout, "Point Group %s\n", PG_Names[iList]);
fprintf(fpout, "Laue Group %s\n",
PG_Names[PG_Index(LG_Code_of_PG_Index[iList])]);
fprintf(fpout, "%s\n", XS_Name[SgInfo->XtalSystem]);
if (SgInfo->UniqueRefAxis != 0 || SgInfo->UniqueDirCode != 0) {
fprintf(fpout, "Unique Axis ");
if (SgInfo->UniqueRefAxis != 0 && SgInfo->UniqueRefAxis != 'o')
fprintf(fpout, "%c", SgInfo->UniqueRefAxis);
if (SgInfo->UniqueDirCode != 0 && SgInfo->UniqueDirCode != '=')
fprintf(fpout, "%c", SgInfo->UniqueDirCode);
fprintf(fpout, "\n");
}
if (SgInfo->ExtraInfo != EI_Unknown)
fprintf(fpout, "%s\n", EI_Name[SgInfo->ExtraInfo]);
if (SgInfo->InversionOffOrigin)
fprintf(fpout, "Note: Inversion operation off origin\n");
putc('\n', fpout);
fprintf(fpout, "Order %3d\n", SgInfo->OrderL);
fprintf(fpout, "Order P %3d\n", SgInfo->OrderP);
putc('\n', fpout);
if (SgInfo->n_si_Vector >= 0) {
fprintf(fpout, "s.i.Vector Modulus\n");
for (i_si_v = 0; i_si_v < SgInfo->n_si_Vector; i_si_v++)
fprintf(fpout, " %2d %2d %2d %d\n",
SgInfo->si_Vector[i_si_v * 3 + 0],
SgInfo->si_Vector[i_si_v * 3 + 1],
SgInfo->si_Vector[i_si_v * 3 + 2],
SgInfo->si_Modulus[i_si_v]);
putc('\n', fpout);
}
if (F_XYZ || F_Verbose) {
fprintf(fpout, "#List %3d\n", SgInfo->nList);
putc('\n', fpout);
lsmx = SgInfo->ListSeitzMx;
rmxi = SgInfo->ListRotMxInfo;
if (rmxi == NULL)
rmxi = &RotMxInfo;
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
if (rmxi == &RotMxInfo) {
if (GetRotMxInfo(lsmx->s.R, &RotMxInfo) == 0) {
SetSgError("Error: Illegal SeitzMx in list");
return;
}
}
if (F_Verbose) {
sprintf(buf, "(%d)", iList + 1);
fprintf(fpout, "%-4s", buf);
fprintf(fpout, " %2d", rmxi->Order);
if (rmxi->Inverse)
fprintf(fpout, "^-1");
else
fprintf(fpout, " ");
fprintf(fpout, " [%2d %2d %2d]",
rmxi->EigenVector[0],
rmxi->EigenVector[1], rmxi->EigenVector[2]);
if (rmxi->RefAxis)
fprintf(fpout, " '%c'", rmxi->RefAxis);
else
fprintf(fpout, " ");
if (rmxi->DirCode)
fprintf(fpout, " '%c'", rmxi->DirCode);
else
fprintf(fpout, " ");
fprintf(fpout, " ");
}
xyz = RTMx2XYZ(lsmx, 1, STBF, 0, 0, 1, ", ", NULL, 0);
if (xyz)
fprintf(fpout, "%s", xyz);
putc('\n', fpout);
if (xyz == NULL)
return;
if (F_Verbose)
PrintSeitzMx(lsmx, fpout);
if (rmxi != &RotMxInfo)
rmxi++;
}
if (iList && F_Verbose == 0)
putc('\n', fpout);
}
}