SgInfo - Space group Info


SgInfo|ofnIgS

A comprehensive Collection of ANSI C Routines for the Handling of
Space Group Symmetry


Latest developments

SgInfo has been superseded by the space group toolbox (sgtbx), which is a part of the open source package Computational Crystallography Toolbox (cctbx).

Update August 2015


Introduction

SgInfo is library of ANSI C routines

The design of the routines is based on the notation introduced by Hall which enables unambiguous and practically unrestricted definition of space group, setting, and origin. Input Hall symbols are translated into Seitz matrices, which, in turn, are used to generate the full set of symmetry operations. After the input Hall symbol has been translated, the matrices are sorted and reduced back to an output Hall symbol. For a given space group and setting, the reduction process will always result in the same Hall symbol, regardless of the way the group was generated; i.e., Seitz matrices from any source may be passed to the symmetry generating routines and a well defined Hall symbol will be produced.

Part of the library is a table which associates ITVA space group numbers, Schönflies symbols, Hermann-Mauguin symbols, and Hall symbols. This table is used in two ways. Space group numbers and symbols can be translated to a Hall symbol, which is used to generate the symmetry matrices. Alternatively, the Hall symbol produced by the reduction algorithm of the library is used to find the appropriate entry in the table.


What follows in this document, is meant to be an

Introduction and Tutorial.

There is also a

Comprehensive Reference Section,

where each structure, subroutine, and macro is explained in detail.


Table of Content for this document:


SgInfo Demonstration Program

sginfo WWW gateway

The SgInfo package comes with a demonstration program which also has a certain value on its own. Running sginfo without arguments will produce a little help screen:


usage: sginfo [options] [SpaceGroupName_or_# [SpaceGroupName_or_#]]
  -Hall|VolA|VolI   select conventions
  -ListTable[=#]    print [parts of] internal table
  -CIF              print internal table in CIF format
  -XYZ              print something like "-x, y+1/2, z"
  -AllXYZ           print all symmetry operations
  -Maple            print symmetry matrices in Maple format
  -Space            print symmetry file for AVS SpaceModule
  -Shelx            print Shelx LATT & SYMM cards
  -Schakal          print Schakal DU & SY cards
  -hklList          print simple hkl listing
  -Standard         compute transformation to "standard" setting
  -UnitCell="a..g"  unit cell constants a, b, c, alpha, beta, gamma
  -v                be more verbose
  -Verify           debug option: verify transformations
  -ClearError       debug option: clear errors and continue

examples: sginfo 68
          sginfo C2/m:c2 -XYZ
          sginfo "Oh^3" -Shelx
          sginfo -Hall "-F 4y 2" -Standard
          sginfo -VolI 15 -VolA 15
          sginfo -ListTable=68

Try some of the examples:


% sginfo 68

Space Group  68:1  D2h^22  Ccca:1   C 2 2 -1bc
Point Group  mmm
Laue  Group  mmm
Orthorhombic
Note: Inversion operation off origin

Order    16
Order P   8

s.i.Vector  Modulus
  1  0  0   2
  0  0  1   2

What does all this mean?

The first line tells you what the lookup in the internal table has produced for "68". This is the entry for space group 68, Origin Choice 1 (:1). This space group has the Schönflies symbol D2h^22, the Herman-Mauguin symbol Ccca and the Hall symbol "C 2 2 -1bc".

After sginfo has found the table entry, it translates the Hall symbol to symmetry matrices. Next - through repetive multiplication of these generator matrices - the whole group, i.e. all symmetry matrices of this space group, are computed.

Knowing all symmetry matrices, sginfo derives that space group 68 belongs to point group mmm, laue group mmm, and the orthorhombic crystal system. Furthermore, space group 68 is centro-symmetric, but the inversion operation is not at the origin (of course this is what ITVA Origin Choice 1 means, but sginfo finds out without looking at this).

The maximum number of equivalent positions in space group 68 is indicated by Order 16. To help people who want to use the SgInfo library routines in their own applications, SgInfo also stores the maximum number of positions of the primitive "P" subgroup of the space group. In this case Order P 8 is reported.

Direct Methods people might be delighted to see that SgInfo also knows how to derive semi-invariant vectors and moduli from a set of symmetry matrices. Here we have two semi-invariant vectors - one along x (1 0 0), one along z (0 0 1) - with modulus "2".

In the next example, sginfo demonstrates its ability to look up Schönflies symbols. In addition, a list of the symmetry operations in SHELX format is requested. For all who do not have SHELX-TL(TM), this could help avoiding a lot of typos:


% sginfo "Oh^3" -Shelx

Space Group  223  Oh^3  Pm-3n  -P 4n 2 3
Point Group  m-3m
Laue  Group  m-3m
Cubic

Order    48
Order P  48

s.i.Vector  Modulus
  1  1  1   2

LATT  1
SYMM .5-Y, .5+X, .5+Z
SYMM -X, -Y, Z
SYMM .5+Y, .5-X, .5+Z
SYMM .5+X, .5-Z, .5+Y
SYMM X, -Y, -Z
SYMM .5+X, .5+Z, .5-Y
SYMM .5+Z, .5+Y, .5-X
SYMM -X, Y, -Z
SYMM .5-Z, .5+Y, .5+X
SYMM Z, X, Y
SYMM Y, Z, X
SYMM -Y, -Z, X
SYMM Z, -X, -Y
SYMM -Y, Z, -X
SYMM -Z, -X, Y
SYMM -Z, X, -Y
SYMM Y, -Z, -X
SYMM .5+Y, .5+X, .5-Z
SYMM .5-Y, .5-X, .5-Z
SYMM .5-X, .5+Z, .5+Y
SYMM .5-X, .5-Z, .5-Y
SYMM .5+Z, .5-Y, .5+X
SYMM .5-Z, .5-Y, .5-X

The next example again demonstrates two new features: how to enter a Hall symbol from the command line and how to find out which space group is generated by this Hall symbol:


% sginfo -Hall "-F 4y 2" -Standard

Setting A:

Hall Symbol  -F 4y 2
Point Group  4/mmm
Laue  Group  4/mmm
Tetragonal
Unique Axis  y

Order    64
Order P  16

s.i.Vector  Modulus
  1  1  1   2


Setting B:

Space Group  139  D4h^17  I4/mmm  -I 4 2
Point Group  4/mmm
Laue  Group  4/mmm
Tetragonal
Unique Axis  z

Order    32
Order P  16

s.i.Vector  Modulus
  0  0  1   2


Change of Basis Setting A -> Setting B:
   CBMx = x+z, x-z, y
InvCBMx = 1/2*x+1/2*y, z, 1/2*x-1/2*y

First of all, sginfo processes the Hall symbol and reports the results under "Setting A". Since "Unique Axis y" is a very strange setting for a tetragonal space group, sginfo cannot find an entry in the internal table and hence only reports the (newly generated) Hall symbol.

Fortunately there is the "-Standard" option, which tells sginfo to try harder to find out about the ITVA space group number. Therefore sginfo tries to match the generators of all space groups in the internal table (which do belong to the same point group) to the actual set of symmetry matrices by building the proper change-of-basis matrix, in this case coming up with space group I4/mmm.

The result of the space group finding process is not necessarily the "standard" setting, but a certain reference setting. Therefore sginfo evaluates which "conventions", either option "-VolI" or "-VolA" (which is the default) are currently selected, obtains the corresponding standard setting und reports the results under "Setting B". Again sginfo starts to search for the reference setting, this time only to get the corresponding change-of-basis matrix.

In the last step, sginfo combines the change-of-basis matrices for "Setting A -> Reference Setting" and "Setting B -> Reference Setting" to obtain the matrix and its inverse for "Setting A -> Setting B".

If you do not trust sginfo and/or want to see the individual change-of-basis matrices to the reference setting, run sginfo with the "-Verify" option set.

Maybe it is sensible to add the following short definition:

   "CBMx" transforms the coordinates of Setting A to coordinates of Setting B.
"InvCBMx" transforms the coordinates of Setting B to coordinates of Setting A.

BTW: the execution time on a 486 DX2 66 MHz PC running Linux is less than 0.5 seconds for the whole process above (two times generation of the symmetry operations, two times finding the space group with construction of the change-of-basis matrix).

The last example illustrates how easy it is to get the change-of-basis matrix for the transformation of the "old" standard setting of ITVI to the "new" standard setting of ITVA:


% sginfo -VolI 15 -VolA 15

Setting A:

Space Group  15:-c1  C2h^6  C2/c:-c1 = B112/b = B2/b  -B 2b
Point Group  2/m
Laue  Group  2/m
Monoclinic
Unique Axis  z

Order     8
Order P   4

s.i.Vector  Modulus
  0  1  0   2
  0  0  1   2


Setting B:

Space Group  15:b1  C2h^6  C2/c:b1 = C12/c1  -C 2yc
Point Group  2/m
Laue  Group  2/m
Monoclinic
Unique Axis  y

Order     8
Order P   4

s.i.Vector  Modulus
  1  0  0   2
  0  0  1   2


Change of Basis Setting A -> Setting B:
   CBMx = x-y-1/4, z+1/4, -y
InvCBMx = x-z+1/4, -z, y-1/4

A real life example

A xray powder pattern has been indexed with the POWDER program of D. Taupin [1]. The unit cell as found by the program was monoclinic, a=8.63289, b=9.10859, c=17.699, gamma=108.45. Examination of systematic absences suggested space group P 1 1 21/n.

What is the standard setting of this space group and what are the corresponding cell constants?


% sginfo "P 1 1 21/n" -Standard -UnitCell="8.63289 9.10859 17.699 108.45"

Setting A:

Space Group  14:c2  C2h^5  P21/c:c2 = P1121/n  -P 2n
Point Group  2/m
Laue  Group  2/m
Monoclinic
Unique Axis  z

Order     4
Order P   4

s.i.Vector  Modulus
  1  0  0   2
  0  1  0   2
  0  0  1   2


Setting B:

Space Group  14:b1  C2h^5  P21/c:b1 = P121/c1  -P 2ybc
Point Group  2/m
Laue  Group  2/m
Monoclinic
Unique Axis  y

Order     4
Order P   4

s.i.Vector  Modulus
  1  0  0   2
  0  1  0   2
  0  0  1   2


Change of Basis Setting A -> Setting B:
   CBMx = x-y, z, -y
InvCBMx = x-z, -z, y

Setting A UnitCell  8.63289 9.10859 17.699 90 90 108.45
Setting B UnitCell  8.63289 17.699 10.3789 90 123.644 90

If you have the ITVA at hand, it is not a big trick to obtain the standard setting P 1 21/c 1. What is more of a problem is to find the correct change-of-basis matrix, even if you have the ITVA. This is where sginfo steps in and can save you a lot of cumbersome reasoning. Having CBMx, it is now straightforward to compute the new cell parameters.

The formula for the transformation of the metrical matrix G(A) of Setting A to the metrical matrix G(B) of Setting B is (see e.g. Boisen & Gibbs [2]):

            G(B) = transpose(InvCBMx) * G(A) * InvCBMx

By applying this formula sginfo finally produces the cell parameters for Setting B.


Getting SgInfo

For those who not want to learn more about SgInfo at this point and want to play on their own machine right away: here are some hot links:


[*] Courtesy Jon Tischler (TischlerJZ@ornl.gov)
[+] Courtesy Andreas Karrer (karrer@ife.ee.ethz.ch)

For all who want to test their compilier: some source code:


Other space group software and web sites

You are not entirely happy with SgInfo?

You want more Space Group Info?

There is more available:


Warning: If you do not know the basics of C, the rest of this document will be very boring.


Known Bugs (as of May 2001)


Using SgInfo in your application

The SgInfo library routines are grouped into five C source code files and one C header file:

        sginfo.h        header file with global definitions
        sgclib.c        core library routines
        sgio.c          input/output routines
        sgfind.c        space group finding routines
        sghkl.c         reciprocal space routines
        sgsi.c          semi-invariant routines

To demonstrate how to use the library there are two additional files with driver routines:

        sginfo.c        the driver for the examples above
        sgquick.c       a very simple template driver

Have a look at sgquick.c. This driver takes one command line argument, e.g. sgquick "VolA P2", and sends this string to BuildSpgrInfo().

The first half of BuildSgInfo() does nothing more than splitting the input string SgName into the part which selects the conventions (like the -Hall|VolA|VolI options in the preceding examples) and the space group symbol itself.

The first call to the SgInfo library is FindTabSgNameEntry(). This routine maps space group numbers, Schönflies symbols, and Hermann-Mauguin symbols to Hall symbols.

In the next section we allocate memory to hold the Seitz matrices and some additional parameters. Then the SgInfo structure is initialized, the Hall symbol is translated to Seitz matrices, thereby generating the whole group through multiplication.

The final step is a call to CompleteSgInfo(). This routine sorts and reduces the list of Seitz matrices, determines crystal system and point group, and a new Hall symbol is derived from the symmetry operations. This new Hall symbol is used to find the entry in the internal table; if the entry is known in advance, SgInfo just verifies if the new result is the same (or signals an "Internal Error" otherwise). If there is no matching entry, SgInfo does not report the ITVA space group name and number at this point.


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>


#include "sginfo.h"


static int str_ibegin(const char *s1, const char *s2) /* string ignore-case */
{                                                     /* begin              */
  char     u1, u2;

  while (*s1 && *s2)
  {
    u1 = toupper(*s1++);
    u2 = toupper(*s2++);
    if      (u1 < u2) return -1;
    else if (u1 > u2) return  1;
  }
  if (*s2) return -1;
  return 0;
}


int BuildSgInfo(T_SgInfo *SgInfo, const char *SgName)
{
  int                VolLetter;
  const T_TabSgName  *tsgn;


  /* look for "VolA", "VolI", or "Hall"
   */

  while (*SgName && isspace(*SgName)) SgName++;

  VolLetter = -1;

  if      (isdigit(*SgName))
    VolLetter = 'A';
  else if (str_ibegin(SgName, "VolA") == 0)
  {
    VolLetter = 'A';
    SgName += 4;
  }
  else if (   str_ibegin(SgName, "VolI") == 0
           || str_ibegin(SgName, "Vol1") == 0)
  {
    VolLetter = 'I';
    SgName += 4;
  }
  else if (str_ibegin(SgName, "Hall") == 0)
  {
    VolLetter = 0;
    SgName += 4;
  }

  while (*SgName && isspace(*SgName)) SgName++;

  /* default is "VolA"
   */

  if (VolLetter == -1)
    VolLetter = 'A';

  /* if we do not have a Hall symbol do a table look-up
   */

  tsgn = NULL;

  if (VolLetter)
  {
    tsgn = FindTabSgNameEntry(SgName, VolLetter);
    if (tsgn == NULL) return -1; /* no matching table entry */
    SgName = tsgn->HallSymbol;
  }

  /* Allocate memory for the list of Seitz matrices and
     a supporting list which holds the characteristics of
     the rotation parts of the Seitz matrices
   */

  SgInfo->MaxList = 192; /* absolute maximum number of symops */

  SgInfo->ListSeitzMx
    = malloc(SgInfo->MaxList * sizeof (*SgInfo->ListSeitzMx));

  if (SgInfo->ListSeitzMx == NULL) {
    SetSgError("Not enough core");
    return -1;
  }

  SgInfo->ListRotMxInfo
    = malloc(SgInfo->MaxList * sizeof (*SgInfo->ListRotMxInfo));

  if (SgInfo->ListRotMxInfo == NULL) {
    SetSgError("Not enough core");
    return -1;
  }

  /* Initialize the SgInfo structure
   */

  InitSgInfo(SgInfo);
  SgInfo->TabSgName = tsgn; /* in case we know the table entry */

  /* Translate the Hall symbol and generate the whole group
   */

  ParseHallSymbol(SgName, SgInfo);
  if (SgError != NULL) return -1;

  /* Do some book-keeping and derive crystal system, point group,
     and - if not already set - find the entry in the internal
     table of space group symbols
   */

  return CompleteSgInfo(SgInfo);
}


int main(int argc, char *argv[])
{
  T_SgInfo  SgInfo;


  if (argc == 2)
  {
    if (BuildSgInfo(&SgInfo, argv[1]) != 0)
      fprintf(stderr, "%s\n", SgError);
    else
    {
      ListSgInfo(&SgInfo, 1, 0, stdout);

      if (SgError)
        fprintf(stderr, "%s\n", SgError);
    }
  }

  return 0;
}

Understanding the SgInfo structure

Of course there is no big point in passing a pointer to a structure to some strange routine without knowing what you get back. We need to investigate the definition of T_SgInfo, taken from sginfo.h:


typedef struct
  {
    int                  GenOption;
    int                  Centric;
    int                  InversionOffOrigin;
    const T_LatticeInfo  *LatticeInfo;
    int                  StatusLatticeTr;
    int                  OriginShift[3];
    int                  nList;
    int                  MaxList;
    T_RTMx               *ListSeitzMx;
    T_RotMxInfo          *ListRotMxInfo;
    int                  OrderL;
    int                  OrderP;
    int                  XtalSystem;
    int                  UniqueRefAxis;
    int                  UniqueDirCode;
    int                  ExtraInfo;
    int                  PointGroup;
    int                  nGenerator;
    int                   Generator_iList[4];
    char                 HallSymbol[MaxLenHallSymbol + 1];
    const T_TabSgName    *TabSgName;
    const int            *CCMx_LP;
    int                  n_si_Vector;
    int                  si_Vector[9];
    int                  si_Modulus[3];
  }
  T_SgInfo;

Live is not that easy, the definition of T_SgInfo obviously needs four previous definitions, namely of T_LatticeInfo, T_RTMx, T_RotMxInfo, and T_TabSgName.

Now we approach T_SgInfo the following way: we just want to know how to get hold of the symmetry matrices.

In case of a primitive and acentric space group this is pretty simple: you need

Here we go:


typedef union
  {
    struct { int R[9], T[3]; } s;
    int                        a[12];
  }
  T_RTMx;

T_RTMx is a union of a struct with 12 int and a simple array of 12 int.

If you are scared by unions of structs and arrays, you might be delighted to learn that T_LatticeInfo as well as T_RotMxInfo as well as T_TabSgName are simple structs of basic data types. But we save this for later.

How does a "Rotation-Translation-Matrix" T_RTMx look like for, e.g., a 2-fold screw along z, also known as as "-x, -y, z+1/2"?

The debugger always knows the truth:


(dbx) print SgInfo->ListSeitzMx[1]
union  {
    s = struct  {
        R = {
            [0] -1
            [1] 0
            [2] 0
            [3] 0
            [4] -1
            [5] 0
            [6] 0
            [7] 0
            [8] 1
        }
        T = {
            [0] 0
            [1] 0
            [2] 6
        }
    }
    a = {
        [0] -1
        [1] 0
        [2] 0
        [3] 0
        [4] -1
        [5] 0
        [6] 0
        [7] 0
        [8] 1
        [9] 0
        [10] 0
        [11] 6
    }
}

The rotation part R is pretty obvious, "1" encodes "x" or "y" or "z", depending on the position; "-1" encodes "-x" or "-y" or "-z".
The translation part T needs a further definition: the Seitz Matrix Translation Base Factor "STBF". This factor is defined to be 12 in sginfo.h. Therefore T[2] = 6 translates to "+6/12 = +1/2".

Using the ITVA "augmented 4*4 matrix" notation, the mapping of a position (x,y,z) to the symmetry equivalent position (xs,ys,zs) by an element of SgInfo.ListSeitzMx can be summerized by:


        ( xs )     ( R[0]  R[1]  R[2]  T[0]/STBF )  ( x )
        ( ys )  =  ( R[3]  R[4]  R[5]  T[1]/STBF )  ( y )
        ( zs )     ( R[6]  R[7]  R[8]  T[2]/STBF )  ( z )
        ( 1  )     (  0     0     0     1        )  ( 1 )

For primitve centro-symmetric space groups things are slightly more involved. You have to evaluate two variables, SgInfo.Centric and SgInfo.InversionOffOrigin.

If - after calling CompleteSgInfo() - both variables are set to 0, the space group is acentric. If SgInfo.Centric is set to -1, there is an inversion operation at the origin and SgInfo.ListSeitzMx will contain only an acentric subset of the space group. If you need all symmetry operations you have to - mathematically spoken - multiply each of the matrices in SgInfo.ListSeitzMx with the inversion matrix. In practive this means you simply have to take each element of a matrix with reversed sign.

If SgInfo.Centric is 0 but SgInfo.InversionOffOrigin is set to 1, SgInfo.ListSeitzMx will contain the whole (primitive) space group. No further action has to be taken to get all symmetry operations. In fact, if you only need to know how to get all operations, you just need to take care of SgInfo.Centric.


Using SgInfo.LatticeInfo

For centred space groups you need to evaluate SgInfo.LatticeInfo. This is the definition of T_LatticeInfo:
        typedef struct
          {
            int        Code;
            int        nTrVector;
            const int  *TrVector;
          }
          T_LatticeInfo;

LatticeInfo.Code is one of {'P', 'A', 'B', 'C', 'I', 'R', 'S', 'T', 'F'}. Except for 'S' and 'T' this should be clear. For now forget about these strange lattice codes 'S' and 'T'.

Understanding LatticeInfo.nTrVector is equally straightforward. It gives the number of lattice translation vectors which are stored in the location to which LatticeInfo.TrVector points.

TrVector[0..2] gives the first vector (in any case { 0,0,0 }), TrVector[3..5] gives the second, and so on, four at maximum. The elements of LatticeInfo.TrVector are multiplied by STBF, hence compatible to the translation parts of the Seitz matrices.

A little table summarizes all possibilities for SgInfo.LatticeInfo:


        Code  nTrVector  TrVector
         'P'      1      0,0,0
         'A'      2      0,0,0   0 ,1/2,1/2
         'B'      2      0,0,0  1/2, 0 ,1/2
         'C'      2      0,0,0  1/2,1/2, 0
         'I'      2      0,0,0  1/2,1/2,1/2
         'R'      3      0,0,0  2/3,1/3,1/3  1/3,2/3,2/3
         'S'      3      0,0,0  1/3,1/3,2/3  2/3,2/3,1/3
         'T'      3      0,0,0  1/3,2/3,1/3  2/3,1/3,2/3
         'F'      4      0,0,0   0 ,1/2,1/2  1/2, 0 ,1/2  1/2,1/2, 0

Maybe the whole SgInfo structure stuff got somewhat abstract. A small piece of code says more than 1000 words!


Using the space group finder

So far you have seen how to pass a space group symbol or number to SgInfo and how to obtain the symmetry matrices. But this is not all you can do with SgInfo.

Say, you have a program which takes atom coordinates, looks for symmetry elements and produces a list of the operations found. Now you can either take the International Tables to find out what space group you are dealing with, or you can make life easier for yourself and use SgInfo: just pass the list of operations to the library and wait a few milli-seconds for the space group finder to do the job for you. You will not only get the space group number, but also the change-of-basis matrix from your arbitrary setting to a reference setting.

Here is how to do that:


#include <everything_you_like.h>
#include "sginfo.h"

int main(int argc, char *argv[])
{
  /* This is your program, you do anything you can
     to find weird symmetry matrices.

     You did not forget to declare SgInfo
     plus making two calls to malloc() to get memory
     for SgInfo.ListSeitzMx and SgInfo.ListRotMxInfo.
     Copy this from sgquick.c.

     This time you do not have space group symbols
     in advance and you do not need the table look-up.
     You just start with:
   */

  InitSgInfo(&SgInfo);

  while (you_think_you_have_to_loop)
  {
    /* Fine. Now, everytime you found a new operation,
       you set up a buffer SeitzMx (do never, never, never
       ever set SgInfo.ListSeitzMx directly!). Passing
       the buffer SeitzMx to the library is exceptionally
       simple:
     */

    if (Add2ListSeitzMx(&SgInfo, &SeitzMx) < 0)
    {
      /* if Add2ListSeitzMx() returns a value < 0
         an error has occured and the global variable
         SgError has been set. A possible consequence:
       */

      fprintf(stderr, "%s\n", SgError);
      exit(1);
    }
  }

  /* Fine. After you have passed _all_ symmetry operations
     - including a possible inversion operation and
     lattice centring vectors (rotation part of SeitzMx
     = identity, translation part = centring vector) -
     via Add2ListSeitzMx() you are ready to call:
   */

  if (CompleteSgInfo(&SgInfo) != 0)
  {
    /* an error has occured, evaluate SgError, terminate */
  }

  /* Fine. Now you know you have a "legal" space
     group. Maybe you are lucky and you hit a
     setting which is in the internal table.
     Simply ask:
   */

  if (SgInfo.TabSgName != NULL)
  {
    /* Yes, really! If you are not interested in
       change-of-basis matrices you are done.
       You could, e.g., print out the table entry
       and terminate:
     */

    PrintTabSgNameEntry(SgInfo.TabSgName, 0, 0, stdout);
    putc('\n', stdout);
    exit(0);
  }

  /* Hm. Now you have to have declared
       const T_TabSgName  *ReferenceTabSgName;
       T_RTMx             CBMx, InvCBMx;
     somewhere before. Try the hard way:
   */

  ReferenceTabSgName = FindReferenceSpaceGroup(&SgInfo,
                                               &CBMx, &InvCBMx);
  if (ReferenceTabSgName == NULL)
  {
    /* This is really bad! If you arrive here an internal
       error has occured and SgError has been set. This
       means, either you have corrupted SgInfo in some way
       or I (see bottom line) have made some stupid error.
       Let me know! Do it right now!
     */
  }

  /* Bingo! For the sake of simplicity we ignore
     CBMx and InvCBMx here. Print the reference setting
     and finish:
   */

  PrintTabSgNameEntry(ReferenceTabSgName, 0, 0, stdout);
  putc('\n', stdout);

  return 0;
}

/* P.S.: If you made it to this point you might like to
   learn that there are two routines which help you
   adding the inversion operation and lattice centring
   vectors:
      AddInversion2ListSeitzMx();
      AddLatticeTr2ListSeitzMx();
   Look for more details in the reference section.
 */

Copyright Notice & License

SgInfo - Space Group Info (c) 1994-96 Ralf W. Grosse-Kunstleve

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

(1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

(2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

(3) Neither the name of the SgInfo - Space Group Info copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

You are under no obligation whatsoever to provide any bug fixes, patches, or upgrades to the features, functionality or performance of the source code ("Enhancements") to anyone; however, if you choose to make your Enhancements available either publicly, or directly to the SgInfo - Space Group Info copyright holder, without imposing a separate written license agreement for such Enhancements, then you hereby grant the following license: a nonexclusive, royalty-free perpetual license to install, use, modify, prepare derivative works, incorporate into other computer software, distribute, and sublicense such enhancements or derivative works thereof, in binary and source code form.


References

[1] D. Taupin; Enhancements in Powder-Pattern Indexing; J.Appl.Cryst.(1989), V22, 455-459.
[2] M.B. Boisen, Jr. & G.V. Gibbs; Mathematical Crystallography; Reviews in Mineralogy, Volume 15, Revised Edition; Mineralogical Society of America; Washington D.C. 1990

Ralf W. Grosse-Kunstleve <rwgkio+sginfo@gmail.com>