1 //
2 // pointgrp.h
3 //
4 // Modifications are
5 // Copyright (C) 1996 Limit Point Systems, Inc.
6 //
7 // Author: Edward Seidl <seidl@janed.com>
8 // Maintainer: LPS
9 //
10 // This file is part of the SC Toolkit.
11 //
12 // The SC Toolkit is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU Library General Public License as published by
14 // the Free Software Foundation; either version 2, or (at your option)
15 // any later version.
16 //
17 // The SC Toolkit is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU Library General Public License for more details.
21 //
22 // You should have received a copy of the GNU Library General Public License
23 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
24 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25 //
26 // The U.S. Government is granted a limited license as per AL 91-7.
27 //
28 
29 /* pointgrp.h -- definition of the point group classes
30  *
31  *      THIS SOFTWARE FITS THE DESCRIPTION IN THE U.S. COPYRIGHT ACT OF A
32  *      "UNITED STATES GOVERNMENT WORK".  IT WAS WRITTEN AS A PART OF THE
33  *      AUTHOR'S OFFICIAL DUTIES AS A GOVERNMENT EMPLOYEE.  THIS MEANS IT
34  *      CANNOT BE COPYRIGHTED.  THIS SOFTWARE IS FREELY AVAILABLE TO THE
35  *      PUBLIC FOR USE WITHOUT A COPYRIGHT NOTICE, AND THERE ARE NO
36  *      RESTRICTIONS ON ITS USE, NOW OR SUBSEQUENTLY.
37  *
38  *  Author:
39  *      E. T. Seidl
40  *      Bldg. 12A, Rm. 2033
41  *      Computer Systems Laboratory
42  *      Division of Computer Research and Technology
43  *      National Institutes of Health
44  *      Bethesda, Maryland 20892
45  *      Internet: seidl@alw.nih.gov
46  *      June, 1993
47  */
48 
49 #ifdef __GNUC__
50 #pragma interface
51 #endif
52 
53 #ifndef _math_symmetry_pointgrp_h
54 #define _math_symmetry_pointgrp_h
55 
56 #include <iostream>
57 
58 #include <util/class/class.h>
59 #include <util/state/state.h>
60 #include <util/keyval/keyval.h>
61 #include <math/scmat/vector3.h>
62 
63 namespace sc {
64 
65 // //////////////////////////////////////////////////////////////////
66 
67 /** The SymmetryOperation class provides a 3 by 3 matrix
68     representation of a symmetry operation, such as a rotation or reflection.
69 */
70 class SymmetryOperation {
71   private:
72     double d[3][3];
73 
74   public:
75     SymmetryOperation();
76     SymmetryOperation(const SymmetryOperation &);
77     ~SymmetryOperation();
78 
79     /// returns the trace of the transformation matrix
trace()80     double trace() const { return d[0][0]+d[1][1]+d[2][2]; }
81 
82     /// returns the i'th row of the transformation matrix
83     double* operator[](int i) { return d[i]; }
84 
85     /// const version of the above
86     const double* operator[](int i) const { return d[i]; }
87 
88     /** returns a reference to the (i,j)th element of the transformation
89         matrix */
operator()90     double& operator()(int i, int j) { return d[i][j]; }
91 
92     /// const version of the above
operator()93     double operator()(int i, int j) const { return d[i][j]; }
94 
95     /// zero out the symop
zero()96     void zero() { memset(d,0,sizeof(double)*9); }
97 
98     /// This operates on this with r (i.e. return r * this).
99     SymmetryOperation operate(const SymmetryOperation& r) const;
100 
101     /// This performs the transform r * this * r~
102     SymmetryOperation transform(const SymmetryOperation& r) const;
103 
104     /// Set equal to a unit matrix
unit()105     void unit() { zero(); d[0][0] = d[1][1] = d[2][2] = 1.0; }
106 
107     /// Set equal to E
E()108     void E() { unit(); }
109 
110     /// Set equal to an inversion
i()111     void i() { zero(); d[0][0] = d[1][1] = d[2][2] = -1.0; }
112 
113     /// Set equal to reflection in xy plane
sigma_h()114     void sigma_h() { unit(); d[2][2] = -1.0; }
115 
116     /// Set equal to reflection in xz plane
sigma_xz()117     void sigma_xz() { unit(); d[1][1] = -1.0; }
118 
119     /// Set equal to reflection in yz plane
sigma_yz()120     void sigma_yz() { unit(); d[0][0] = -1.0; }
121 
122     /// Set equal to a clockwise rotation by 2pi/n
123     void rotation(int n);
124     void rotation(double theta);
125 
126     /// Set equal to C2 about the x axis
c2_x()127     void c2_x() { i(); d[0][0] = 1.0; }
128 
129     /// Set equal to C2 about the x axis
c2_y()130     void c2_y() { i(); d[1][1] = 1.0; }
131 
132     void transpose();
133 
134     /// print the matrix
135     void print(std::ostream& =ExEnv::out0()) const;
136 };
137 
138 // //////////////////////////////////////////////////////////////////
139 
140 /** The SymRep class provides an n dimensional matrix representation of a
141     symmetry operation, such as a rotation or reflection.  The trace of a
142     SymRep can be used as the character for that symmetry operation.  d is
143     hardwired to 5x5 since the H irrep in Ih is 5 dimensional.
144 */
145 class SymRep {
146   private:
147     int n;
148     double d[5][5];
149 
150   public:
151     SymRep(int =0);
152     SymRep(const SymmetryOperation&);
153     ~SymRep();
154 
155     /// Cast to a SymmetryOperation.
156     operator SymmetryOperation() const;
157 
158     /// returns the trace of the transformation matrix
159     inline double trace() const;
160 
161     /// set the dimension of d
set_dim(int i)162     void set_dim(int i) { n=i; }
163 
164     /// returns the i'th row of the transformation matrix
165     double* operator[](int i) { return d[i]; }
166     /// const version of the above
167     const double* operator[](int i) const { return d[i]; }
168 
169     /** returns a reference to the (i,j)th element of the transformation
170         matrix */
operator()171     double& operator()(int i, int j) { return d[i][j]; }
172     /// const version of double& operator()(int i, int j)
operator()173     double operator()(int i, int j) const { return d[i][j]; }
174 
175     /// zero out the symop
zero()176     void zero() { memset(d,0,sizeof(double)*25); }
177 
178     /// This operates on this with r (i.e. return r * this).
179     SymRep operate(const SymRep& r) const;
180 
181     /// This performs the transform r * this * r~
182     SymRep transform(const SymRep& r) const;
183 
184     /// Set equal to a unit matrix
unit()185     void unit() {
186       zero(); d[0][0] = d[1][1] = d[2][2] = d[3][3] = d[4][4] = 1.0;
187     }
188 
189     /// Set equal to the identity
E()190     void E() { unit(); }
191 
192     /// Set equal to an inversion
i()193     void i() { zero(); d[0][0] = d[1][1] = d[2][2] = d[3][3] = d[4][4] = -1.0;}
194 
195     /// Set equal to reflection in xy plane
196     void sigma_h();
197 
198     /// Set equal to reflection in xz plane
199     void sigma_xz();
200 
201     /// Set equal to reflection in yz plane
202     void sigma_yz();
203 
204     /// Set equal to a clockwise rotation by 2pi/n
205     void rotation(int n);
206     void rotation(double theta);
207 
208     /// Set equal to C2 about the x axis
209     void c2_x();
210 
211     /// Set equal to C2 about the x axis
212     void c2_y();
213 
214     /// print the matrix
215     void print(std::ostream& =ExEnv::out0()) const;
216 };
217 
218 inline double
trace()219 SymRep::trace() const
220 {
221   double r=0;
222   for (int i=0; i < n; i++)
223     r += d[i][i];
224   return r;
225 }
226 
227 // //////////////////////////////////////////////////////////////////
228 
229 
230 class CharacterTable;
231 
232 /** The IrreducibleRepresentation class provides information associated
233     with a particular irreducible representation of a point group.  This
234     includes the Mulliken symbol for the irrep, the degeneracy of the
235     irrep, the characters which represent the irrep, and the number of
236     translations and rotations in the irrep.  The order of the point group
237     is also provided (this is equal to the number of characters in an
238     irrep).  */
239 class IrreducibleRepresentation {
240   friend class CharacterTable;
241 
242   private:
243     int g;         // the order of the group
244     int degen;     // the degeneracy of the irrep
245     int nrot_;     // the number of rotations in this irrep
246     int ntrans_;   // the number of translations in this irrep
247     int complex_;  // true if this irrep has a complex representation
248     char *symb;    // mulliken symbol for this irrep
249     char *csymb;    // mulliken symbol for this irrep w/o special characters
250 
251     SymRep *rep;   // representation matrices for the symops
252 
253   public:
254     IrreducibleRepresentation();
255     IrreducibleRepresentation(const IrreducibleRepresentation&);
256     /** This constructor takes as arguments the order of the point group,
257      the degeneracy of the irrep, and the Mulliken symbol of the irrep.
258      The Mulliken symbol is copied internally. */
259     IrreducibleRepresentation(int,int,const char*,const char* =0);
260 
261     ~IrreducibleRepresentation();
262 
263     IrreducibleRepresentation& operator=(const IrreducibleRepresentation&);
264 
265     /// Initialize the order, degeneracy, and Mulliken symbol of the irrep.
266     void init(int =0, int =0, const char* =0, const char* =0);
267 
268     /// Returns the order of the group.
order()269     int order() const { return g; }
270 
271     /// Returns the degeneracy of the irrep.
degeneracy()272     int degeneracy() const { return degen; }
273 
274     /// Returns the value of complex_.
complex()275     int complex() const { return complex_; }
276 
277     /// Returns the number of projection operators for the irrep.
nproj()278     int nproj() const { return degen*degen; }
279 
280     /// Returns the number of rotations associated with the irrep.
nrot()281     int nrot() const { return nrot_; }
282 
283     /// Returns the number of translations associated with the irrep.
ntrans()284     int ntrans() const { return ntrans_; }
285 
286     /// Returns the Mulliken symbol for the irrep.
symbol()287     const char * symbol() const { return symb; }
288 
289     /** Returns the Mulliken symbol for the irrep without special
290         characters.
291     */
symbol_ns()292     const char * symbol_ns() const { return (csymb?csymb:symb); }
293 
294     /** Returns the character for the i'th symmetry operation of the point
295      group. */
character(int i)296     double character(int i) const {
297       return complex_ ? 0.5*rep[i].trace() : rep[i].trace();
298     }
299 
300     /// Returns the element (x1,x2) of the i'th representation matrix.
p(int x1,int x2,int i)301     double p(int x1, int x2, int i) const { return rep[i](x1,x2); }
302 
303     /** Returns the character for the d'th contribution to the i'th
304      representation matrix. */
p(int d,int i)305     double p(int d, int i) const {
306       int dc=d/degen; int dr=d%degen;
307       return rep[i](dr,dc);
308     }
309 
310     /** This prints the irrep to the given file, or stdout if none is
311      given.  The second argument is an optional string of spaces to offset
312      by. */
313     void print(std::ostream& =ExEnv::out0()) const;
314 };
315 
316 // ///////////////////////////////////////////////////////////
317 /** The CharacterTable class provides a workable character table
318  for all of the non-cubic point groups.  While I have tried to match the
319  ordering in Cotton's book, I don't guarantee that it is always followed.
320  It shouldn't matter anyway.  Also note that I don't lump symmetry
321  operations of the same class together.  For example, in C3v there are two
322  distinct C3 rotations and 3 distinct reflections, each with a separate
323  character.  Thus symop has 6 elements rather than the 3 you'll find in
324  most published character tables. */
325 class CharacterTable {
326   public:
327     enum pgroups {C1, CS, CI, CN, CNV, CNH, DN, DND, DNH, SN, T, TH, TD, O,
328                   OH, I, IH};
329 
330   private:
331     int g;                               // the order of the point group
332     int nt;                              // order of the princ rot axis
333     pgroups pg;                          // the class of the point group
334     int nirrep_;                         // the number of irreps in this pg
335     IrreducibleRepresentation *gamma_;   // an array of irreps
336     SymmetryOperation *symop;            // the matrices describing sym ops
337     int *_inv;                           // index of the inverse symop
338     char *symb;                          // the Schoenflies symbol for the pg
339 
340     /// this determines what type of point group we're dealing with
341     int parse_symbol();
342     /// this fills in the irrep and symop arrays.
343     int make_table();
344 
345     // these create the character tables for the cubic groups
346     void t();
347     void th();
348     void td();
349     void o();
350     void oh();
351     void i();
352     void ih();
353 
354   public:
355     CharacterTable();
356     /** This constructor takes the Schoenflies symbol of a point group as
357         input. */
358     CharacterTable(const char*);
359     /** This is like the above, but it also takes a reference to a
360         SymmetryOperation which is the frame of reference.  All symmetry
361         operations are transformed to this frame of reference. */
362     CharacterTable(const char*,const SymmetryOperation&);
363 
364     CharacterTable(const CharacterTable&);
365     ~CharacterTable();
366 
367     CharacterTable& operator=(const CharacterTable&);
368 
369     /// Returns the number of irreps.
nirrep()370     int nirrep() const { return nirrep_; }
371     /// Returns the order of the point group
order()372     int order() const { return g; }
373     /// Returns the Schoenflies symbol for the point group
symbol()374     const char * symbol() const { return symb; }
375     /// Returns the i'th irrep.
gamma(int i)376     IrreducibleRepresentation& gamma(int i) { return gamma_[i]; }
377     /// Returns the i'th symmetry operation.
symm_operation(int i)378     SymmetryOperation& symm_operation(int i) { return symop[i]; }
379 
380     /** Cn, Cnh, Sn, T, and Th point groups have complex representations.
381         This function returns 1 if the point group has a complex
382         representation, 0 otherwise. */
complex()383     int complex() const {
384       if (pg==CN || pg==SN || pg==CNH || pg==T || pg==TH)
385         return 1;
386       return 0;
387     }
388 
389     /// Returns the index of the symop which is the inverse of symop[i].
inverse(int i)390     int inverse(int i) const { return _inv[i]; }
391 
ncomp()392     int ncomp() const {
393       int ret=0;
394       for (int i=0; i < nirrep_; i++) {
395         int nc = (gamma_[i].complex()) ? 1 : gamma_[i].degen;
396         ret += nc;
397       }
398       return ret;
399     }
400 
401     /// Returns the irrep component i belongs to.
which_irrep(int i)402     int which_irrep(int i) {
403       for (int ir=0, cn=0; ir < nirrep_; ir++) {
404         int nc = (gamma_[ir].complex()) ? 1 : gamma_[ir].degen;
405         for (int c=0; c < nc; c++,cn++)
406           if (cn==i)
407             return ir;
408       }
409       return -1;
410     }
411 
412     /// Returns which component i is.
which_comp(int i)413     int which_comp(int i) {
414       for (int ir=0, cn=0; ir < nirrep_; ir++) {
415         int nc = (gamma_[ir].complex()) ? 1 : gamma_[ir].degen;
416         for (int c=0; c < nc; c++,cn++)
417           if (cn==i)
418             return c;
419       }
420       return -1;
421     }
422 
423     /// This prints the irrep to the given file, or stdout if none is given.
424     void print(std::ostream& =ExEnv::out0()) const;
425 };
426 
427 // ///////////////////////////////////////////////////////////
428 
429 /** The PointGroup class is really a place holder for a CharacterTable.  It
430  contains a string representation of the Schoenflies symbol of a point
431  group, a frame of reference for the symmetry operation transformation
432  matrices, and a point of origin.  The origin is not respected by the
433  symmetry operations, so if you want to use a point group with a nonzero
434  origin, first translate all your coordinates to the origin and then set
435  the origin to zero.  */
436 class PointGroup: public SavableState {
437   private:
438     char *symb;
439     SymmetryOperation frame;
440     SCVector3 origin_;
441 
442   public:
443     PointGroup();
444     /** This constructor takes a string containing the Schoenflies symbol
445         of the point group as its only argument. */
446     PointGroup(const char*);
447     /** Like the above, but this constructor also takes a frame of reference
448         as an argument. */
449     PointGroup(const char*,SymmetryOperation&);
450     /** Like the above, but this constructor also takes a point of origin
451         as an argument. */
452     PointGroup(const char*,SymmetryOperation&,const SCVector3&);
453     /** The PointGroup KeyVal constructor looks for three keywords:
454        symmetry, symmetry_frame, and origin. symmetry is a string
455        containing the Schoenflies symbol of the point group.  origin is an
456        array of doubles which gives the x, y, and z coordinates of the
457        origin of the symmetry frame.  symmetry_frame is a 3 by 3 array of
458        arrays of doubles which specify the principal axes for the
459        transformation matrices as a unitary rotation.
460 
461        For example, a simple input which will use the default origin and
462        symmetry_frame ((0,0,0) and the unit matrix, respectively), might
463        look like this:
464 
465        <pre>
466        pointgrp<PointGroup>: (
467          symmetry = "c2v"
468        )
469        </pre>
470 
471        By default, the principal rotation axis is taken to be the z axis.
472        If you already have a set of coordinates which assume that the
473        rotation axis is the x axis, then you'll have to rotate your frame
474        of reference with symmetry_frame:
475 
476        <pre>
477        pointgrp<PointGroup>: (
478          symmetry = "c2v"
479          symmetry_frame = [
480            [ 0 0 1 ]
481            [ 0 1 0 ]
482            [ 1 0 0 ]
483          ]
484        )
485        </pre>
486      */
487     PointGroup(const Ref<KeyVal>&);
488 
489     PointGroup(StateIn&);
490     PointGroup(const PointGroup&);
491     PointGroup(const Ref<PointGroup>&);
492     ~PointGroup();
493 
494     PointGroup& operator=(const PointGroup&);
495 
496     /// Returns 1 if the point groups are equivalent, 0 otherwise.
497     int equiv(const Ref<PointGroup> &, double tol = 1.0e-6) const;
498 
499     /// Returns the CharacterTable for this point group.
500     CharacterTable char_table() const;
501     /// Returns the Schoenflies symbol for this point group.
symbol()502     const char * symbol() const { return symb; }
503     /// Returns the frame of reference for this point group.
symm_frame()504     SymmetryOperation& symm_frame() { return frame; }
505     /// A const version of the above
symm_frame()506     const SymmetryOperation& symm_frame() const { return frame; }
507     /// Returns the origin of the symmetry frame.
origin()508     SCVector3& origin() { return origin_; }
origin()509     const SCVector3& origin() const { return origin_; }
510 
511     /// Sets (or resets) the Schoenflies symbol.
512     void set_symbol(const char*);
513 
514     void save_data_state(StateOut& so);
515 
516     void print(std::ostream&o=ExEnv::out0()) const;
517 };
518 
519 }
520 
521 #endif
522 
523 // Local Variables:
524 // mode: c++
525 // c-file-style: "ETS"
526 // End:
527