\section{Symmetry}
\label{sec:sym}

The symmetry functionality is intended to work for both molecular and
periodic systems, so bits and pieces will change over time as the
capability to solve periodic systems is developed in the code.
All of the the symmetry information is buried in the geometry
object, so unless changes are required in the orbitals or basis, the
geometry handle alone is sufficient to obtain all required information.

\subsection{Symmetry Group and Operations Functions}

The symmetry module functions that define the group name and operations
are described in this section.

\subsubsection{{\tt sym\_group\_name}}
\begin{verbatim}
  subroutine sym_group_name(geom, name)
  integer geom              ! [input]
  character*(*) name        ! [output] returns the group name
\end{verbatim}

\subsubsection{{\tt sym\_number\_ops}}
\begin{verbatim}
  integer function sym_number_ops(geom)
  integer geom              ! [input]
\end{verbatim}
This routine  returns the number of operations in the group, {\em excluding} the
identity.  Thus, $C_1$ is represented as containing zero operators and
$C_{2v}$ has three operators.

\subsubsection{{\tt sym\_center\_map}}
\begin{verbatim}
  integer function sym_center_map(geom, cent, op)
  integer geom             ! [input]
  integer cent             ! [input] Geometrical center
  integer op               ! [input] Operator
\end{verbatim}
Returns the index of the center that the input center
(\verb+cent+) maps into under the action of the operator
(numbered 1, \ldots, \verb+sym_number_ops(geom)+).

\subsubsection{{\tt sym\_inv\_op}}
\label{sec:syminvop}
\begin{verbatim}
  subroutine sym_inv_op(geom, op, opinv)
  integer geom             ! [input]
  integer op               ! [input] Operator number
  integer opinv            ! [output] Inverse operator
\end{verbatim}
Returns in \verb+opinv+ the index of the operator that is
the inverse to the operator \verb+op+.

\subsubsection{{\tt sym\_apply\_op}}
\begin{verbatim}
  subroutine sym_apply_op(geom, op, r, rnew)
  integer geom
  integer op
  double precision r(3)
  double precision rnew(3)
\end{verbatim}
This routine  applies the operator \verb+op+ to the 3-vector \verb+r+ returning the
result in \verb+rnew+.  {\em Note that this routine acts on
  coordinates natural to the system --- Cartesian for molecules and
  fractional for periodic systems.}

\subsubsection{{\tt sym\_apply\_cart\_op}}
\begin{verbatim}
  subroutine sym_apply_cart_op(geom, op, r, rnew)
  integer geom
  integer op
  double precision r(3)
  double precision rnew(3)
\end{verbatim}
This routine  applies the operator \verb+op+ to the Cartesian 3-vector \verb+r+
returning the result in \verb+rnew+.  {\em Note that this routine acts
  only on Cartesian coordinates.}

\subsubsection{{\tt sym\_get\_cart\_op}}
\begin{verbatim}
  subroutine sym_get_cart_op(geom, op, matrix)
  integer geom                 ! [input]
  integer op                   ! [input] Operator
  double precision matrix(3,4) ! [output] Returns cartesian operator
\end{verbatim}
This routine  returns the matrix representation of the operator that acts on
Cartesian coordinates.  The first three columns correspond to the
point group operator and the final column is the translation.

\begin{verbatim}
    OP * r(1:3) = r'(1:3) = matrix(1:3,1:3)*r(1:3) + matrix(1:3,4)
\end{verbatim}

\subsubsection{{\tt sym\_ops\_get}}
\begin{verbatim}
  subroutine sym_ops_get(geom, numops, symops)
  integer geom                        ! [input]
  integer numops                      ! [input] Leading dim. of symops
  double precision symops(numops*3,4) ! [input] Returns operators
\end{verbatim}
Returns in \verb+symops+ the first \verb+numops+ operators.  It's 
probably not necessary to use this routine.

\subsubsection{{\tt sym\_op\_mult\_table}}
\begin{verbatim}
  subroutine sym_op_mult_table(geom, table, ld)
  integer geom              ! [input]
  integer ld
  integer table(ld,*)
c
c !! THIS ROUTINE HAS NOT BEEN COMPILED OR TESTED !!
c
\end{verbatim}
This routine returns in \verb+table+ the multiplication table for the operators
excluding the identity --- inside the table the identity is labelled
as zero.

\subsection{Geometries and Gradients}

The two routines {\tt sym\_geom\_project} and {\tt sym\_grad\_symmetrize} 
 actually do exactly the same thing internally, but the
interface differs according to their natural usage.

\subsubsection{{\tt sym\_geom\_project}}
\begin{verbatim}
  subroutine sym_geom_project(geom, tol)
  integer geom             ! [input]
  double precision tol     ! [input]
\end{verbatim}

This routine applies a projection operator to the geometry so that it posesses the
symmetry of the group, to machine precision.  An atom and the image of
that atom under the operations of the group are considered to be
identical if (and only if) they are less than \verb+tol+ distant from each
other.  If two centers that should be symmetry equivalent differ
by more than \verb+tol+, then a fatal error results.  This operation
should be idempotent; that is, the square of the projection operator, {\em P\_a}, is 
equal to the operator itself, {\em P\_a}.

\subsubsection{{\tt sym\_grad\_symmetrize}}
\begin{verbatim}
  subroutine sym_grad_symmetrize(geom, grad)
  integer geom                ! [input]
  double precision grad(3,*)  ! [input/output]
\end{verbatim}

This routine also applies a projection operator
 to the gradient so that it posesses the
symmetry of the group, to machine precision.  This is appropriate for
projecting out the totally symmetric component of a gradient
constructed from a skeleton integral list.  This operation should also be
idempotent. 

\subsection{Character Tables}

In order to make use of the character table you need to determine the
class of each operator.  Note that the identity is the only operator
in the first class.

\subsubsection{{\tt sym\_char\_table}}
\begin{verbatim}
  logical function sym_char_table(zname, nop, nir, class_dim,
 &     zir, zclass, chars)
  character*8 zname         ! [input]
  integer nop               ! [output] Returns no. ops (with identity)
  integer nir               ! [output] Returns no. irreducible reps.
  integer class_dim(*)      ! [output] Returns dim. of each class
  character*8 zir(*)        ! [output] Returns name of each irrep
  character*8 zclass(*)     ! [output] Returns name of each class
  double precision chars(*) ! [output] Returns the character table
\end{verbatim}
Given the name of the group, this routine returns the
total number of operators (\verb+nop+) including the identity, the
number of irreducible representations (\verb+nir+), the name of each
irreducible representation (\verb+zir(i)+, \verb+i=1,...,nir+), the
dimension and name of each class (\verb+class_dim(i)+,
\verb+zclass(i)+, \verb+i=1,...,nir+), and the character table.  
Returns \TRUE\ if group character table was available, \FALSE\ 
otherwise.

The character of class \verb+C+ in irreducible representation \verb+R+
is stored in \verb+char(C,R)+ if \verb+char+ is dimensioned as
\begin{verbatim}
   double precision char(nir,nir)
\end{verbatim}
The maximum number of irreducible representations in any point group
is 20 and the maximum number of operators is 120.  Thus, you can just
paste these declarations into your code to call this routine
\begin{verbatim}
  integer maxop, maxireps     
  parameter (maxop = 120, maxireps=20)
  integer nop, nir,  nop_table, class_dim(maxireps)
  character*8 zir(maxireps), zclass(maxireps)
  double precision chars(maxireps*maxireps)

  if (.not. sym_char_table(zname, nop, nir, class_dim,
 $     zir, zclass, chars)) call errquit(' ... ',0)
\end{verbatim}

All is simple except for complex conjugate pairs of irreducible
representations that are stored with one having the real pieces of the
characters and the other the imaginary.  This leads to the second
having a zero character for the identity, however a valid projection
operator can still be constructed (look in \verb+sym_movecs_adapt()+).

\subsubsection{{\tt sym\_op\_classify}}
\begin{verbatim}
  subroutine sym_op_classify(geom, op_class_index)
  integer geom              ! [input] Geometry handle
  integer op_class_index(*) ! [output] Class number of each op
\end{verbatim}
Return an array that has for each operator the number of the class to
which it belongs.  This index makes the connection between the
operator and the character table.  The operators are numbered,
exluding the identity, from 1 to \verb+sym_number_ops()+.

\subsection{Atomic/Molecular Orbitals}

\subsubsection{{\tt sym\_bas\_irreps}}
\begin{verbatim}
  subroutine sym_bas_irreps(basis, oprint, nbf_per_ir)
  integer basis             ! [input] basis handle
  logical oprint            ! [input] if true then print
  integer nbf_per_ir(*)     ! [output] no. of functions per irr. rep.
\end{verbatim}
Returns in \verb+nbf_per_ir+ the number of functions per irreducible
representation that are present in the specified basis set.  The
maximim number of irreducible represenations in any point group is 20.

\subsubsection{{\tt sym\_movecs\_adapt}}
\begin{verbatim}
  subroutine sym_movecs_adapt(basis, thresh, g_vecs, irs, nmixed)
  integer basis             ! [input]
  double precision thresh   ! [input]
  integer g_vecs            ! [input]
  integer irs(*)            ! [output]
  integer nmixed            ! [output]
\end{verbatim}
Symmetry adapts the molecular orbitals in the GA \verb+ga_vecs+,
returning in \verb+irs(i)+ the number of the irreducible
representation of the i'th molecular orbital.  In \verb+nmixed+ is
returned the number of input molecular orbitals that were symmetry
contaminated greater than \verb+thresh+.  An MO is deemed contaminated
if it contains two or more irreps. with coefficients greater than
\verb+thresh+.

{\em Note:} If the input MOs are nearly linearly dependent then the
output MOs may be exactly linearly dependent since if the component
distinguishing two vectors is not the dominant symmetry component it
will be projected out.  If there is reason to suspect linear depencence,
\verb+ga_orthog()+ should be called  before
calling this routine.

{\em Note:} If mixing was present it may be necessary to call
\verb+ga_orthog()+ to reorthogonalize the output vectors.

\subsubsection{{\tt sym\_movecs\_apply\_op}}
\begin{verbatim}
  subroutine sym_movecs_apply_op(basis, op, v, t)
  integer basis             ! [input]
  integer  op               ! [input]
  double precision v(*)     ! [input]
  double precision t(*)     ! [output]
\end{verbatim}
Apply the group operation \verb+op+ to the vector of basis function
coefficients (i.e., a MO vector) in \verb+v(*)+, returning the result
in \verb+t(*)+.

\subsubsection{{\tt sym\_bas\_op}}
\begin{verbatim}
  subroutine sym_bas_op(geom, op, r, maxf, ang_max)
  integer geom              ! [input]
  integer op                ! [input] Desired operator
  integer maxf              ! [input] Leading dimension of r
  integer ang_max           ! [input] Max. ang. momentum of shell
  double precision r(1:maxf,1:maxf,0:ang_max) ! [output] The operator
\end{verbatim}
Return the transformation matrices for basis functions up to the
specified maximum angular momentum under the specified group
operation.

{\em Note} that the identity operation is not included.

{\em Note} that only cartesian shells are supported, but sphericals
will be integrated when available.

Let \verb+X(I,L)+ be the I'th function in a shell with angular
momentum L.  The application of a symmetry operator will
map shell X into an equivalent shell on a possibly different
center and will also mix up the components of the shell
according to
\begin{verbatim}
    R op X(I,L) = sum(J) X(J,L)*R(J,I,L)
\end{verbatim}

In dealing with Cartesian functions it is necessary to pay careful
attention to the difference between using the inverse of an operator
or its transpose
(see Dupuis and King, IJQC 11, 613-625, 1977).  To apply the inverse
operator simply use both the center mapping and transformation
matrices of the inverse operator.  However, since the representation
matrices are {\em not} unitary in the Cartesian basis then to generate
the effect the transposed matrices of an operator you must
\begin{itemize}
\item map (atomic or basis function) centers according to the mapping
  provided for the inverse operation (see section \ref{sec:syminvop})
\item apply the transpose of coefficients (i.e., use \verb+R(I,J,L)+
  instead of \verb+R(J,I,L)+ in the above transformation).
\end{itemize}

For examples of how this routine is used in practice look in
\verb+symmetry/sym_mo_adapt.F+ or \verb+symmetry/sym_sym.F+.

\subsection{`Skeleton' integral lists}

Note that the consituency number (point group component only) for
shells is exactly the same as that for the atoms on which they reside.

\subsubsection{{\tt sym\_atom\_pair}}
\begin{verbatim}
  logical function sym_atom_pair(geom, iat, jat, q2)
  integer geom              ! [input] Geometry handle
  integer iat, jat          ! [input] Atom indices
  double precision q2       ! [output] Constituency number
\end{verbatim}
Return \TRUE\ if \verb+(iat,jat)+ is the lexically highest pair of
symmetry equivalent atoms. If \TRUE\ also return the constituency
factor \verb+q2+ (which is the number of symmetry equivalent pairs).

This routine uses the exchange symmetry \verb+iat <-> jat+ but does
not incorporate any factors into \verb+q2+ to account for this (i.e.,
\verb+q2+ includes point group symmetry only).

\subsubsection{{\tt sym\_atom\_quartet} and {\tt sym\_atom\_gen\_quartet}}
\begin{verbatim}
  logical function sym_atom_quartet(geom, iat, jat, kat, lat, q4)
  integer geom               ! [input] Geometry handle
  integer iat, jat, kat, lat ! [input] Atom indices
  double precision q4        ! [output] Constituency number
\end{verbatim}
Return \TRUE\ if \verb+(iat,jat,kat,lat)+ is the lexically highest
quartet of symmetry equivalent atoms. If \TRUE\ also return the
constituency factor \verb+q4+ (which is the number of symmetry
equivalent quartets).

This routine uses the standard three index exchange symmetries
\verb+(iat<->jat)+ \verb+<->+ \verb+(kat<->lat)+ but does not
incorporate any additional factors into \verb+q4+ (i.e., \verb+q4+
reflects only the point group symmetry).  Look in the \verb+ddscf/+
directory for examples of its use.

\begin{verbatim}
  logical function sym_atom_gen_quartet(geom, iat, jat, kat, lat, q4)
\end{verbatim}
This routine differs from \verb+sym_atom_quartet+ only in that it
uses just two index exchage symmetries \verb+(iat<->jat)+ and
\verb+(kat<->lat)+.  Look in the \verb+moints/+ directory for examples
of its use.

\subsubsection{{\tt sym\_shell\_pair}}
\begin{verbatim}
  logical function sym_shell_pair(basis, ishell, jshell, q2)
  integer basis             ! Basis set handle [input]
  integer ishell, jshell    ! Shell indices [input]
  double precision q2       ! Constituency number [output]
\end{verbatim}
Return |TRUE\ if \verb+(ishell,jshell)+ is the lexically highest pair
of symmetry equivalent shells. If \TRUE\, also return the constituency
factor \verb+q2+ (which is equal to the number of symmetry equivalent
pairs).

This routine uses the exchange symmetry \verb+ishell <-> jshell+ and
{\em incorporates a factor of two into \verb+q2+ to account for this}.
However, this factor of two may be removed at some point in order to
make the shell based routines exactly consistent with the atom based
code.

\subsubsection{{\tt sym\_shell\_quartet}}
\begin{verbatim}
  logical function sym_shell_quartet(basis,
 &     ishell, jshell, kshell, lshell, q4)
  integer basis             ! Basis set handle [input]
  integer ishell, jshell    ! Shell indices [input]
  integer kshell, lshell    ! Shell indices [input]
  double precision q4       ! Constituency number [output]
\end{verbatim}
Return \TRUE\ if \verb+(ishell,jshell,kshell,lshell)+ is the lexically highest
quartet of symmetry equivalent shells. If \TRUE\ also return the
constituency factor \verb+q4+ (which is the number of symmetry
equivalent quartets).

This routine uses the standard three index exchange symmetries
\verb+(ishell<->jshell)+ \verb+<->+ \verb+(kshell<->lshell)+ but does
not incorporate any additional factors into \verb+q4+ (i.e., \verb+q4+
reflects only the point group symmetry).  Look in the \verb+ddscf/+
directory for examples of its use.

\subsubsection{{\tt sym\_symmetrize}}
\begin{verbatim}
  subroutine sym_symmetrize(geom, basis, odensity, g_a)
  integer geom       ! [input] Geometry handle
  integer basis      ! [input] Basis handle
  integer g_a        ! [input] Global array to be symmetrized
  logical odensity   ! [input] true=density, false=hamiltonian
\end{verbatim}
Symmetrize a skeleton AO matrix (in global array with handle
\verb+g_a+) in the given basis set.  This is nothing more than
applying the projection operator for the totally symmetric
representation.
\begin{verbatim}
   B = (1/2h) * sum(R) [RT * (A + AT) * R]
\end{verbatim}
where \verb+R+ runs over all operators in the group (including
identity) and \verb+h+ is the order of the group.

Note that density matrices tranform according to slightly different
rules to Hamiltonian matrices if components of a shell (e.g.,
cartesian d's) are not orthonormal.  (see Dupuis and King, IJQC 11,
613-625, 1977).  Hence, specify \verb+odensity+ as \TRUE\ for
density-like matrices and \FALSE\ for all other totally symmetric
Hamiltonian-like operators.

\subsection{Printing Symmetry Information}

\subsubsection{{\tt sym\_print\_all}}
\begin{verbatim}
  subroutine sym_print_all(geom, oinfo, ouniq, omap, oops, ochar)
  integer geom              ! [input]
  logical oinfo             ! [input] print information
  logical ouniq             ! [input] print list of unique atoms
  logical omap              ! [input] print mapping of atoms under ops
  logical oops              ! [input] print operator matrices
  logical ochar             ! [input] print character table
\end{verbatim}
Print out all symmetry related information inside the geometry object
\begin{description}
\item{\tt oinfo} --- prints the name and order of the group
\item{\tt ouniq} --- prints the list of symmetry unique atoms
\item{\tt omap} --- prints the transformation of atoms under group operations
\item{\tt oops} --- prints the matrix representation of operators including
  class information
\item {\tt ochar} --- prints the character table
\end{description}

\subsubsection{{\tt sym\_print\_char\_table}}
\begin{verbatim}
  subroutine sym_print_char_table(geom)
  integer geom              ! [input]
\end{verbatim}
Print the character table for the group to Fortran unit 6.


\subsubsection{{\tt sym\_print\_ops}}
\begin{verbatim}
  subroutine sym_print_ops(geom)
  integer geom              ! [input]
\end{verbatim}
Called by \verb+sym_print_all+ to print the operators.  You can call
it too if you like.

\subsection{Internal symmetry stuff that might be useful}

\subsubsection{{\tt sym\_op\_type}}

\subsubsection{{\tt sym\_op\_class\_name}}

\subsection{Miscellaneous}

\subsubsection{{\tt cross\_product}}

\subsubsection{{\tt deter3}}


