###########################################################
# This function test the equality between two OP_cella
# objects. The OP_cella is defined further

def OP_isDifferent(cella, cellb):

############################################################
# class  OP_cella
# This class stores things like atom names, their positions,
# cell axis, shift ......
# it has methods for rotation, reflection,
# to calculate Fourier transform, for finding the way one can rotate a set
# of atoms to another set of atoms, for traking interactions and so on......

class OP_cella:
  

  #########################################################"
  # Constructor of OP_cella.
  # Here one passes  the relevant parameter (see default list)
  def __init__(self, 
                     cellvectors=Numeric.array( [ (1.0,0.0,0.0),(0.0,1.0,0.0), (0.0,0.0,1.0) ] ),
                     AtomNames=['a','b'],
                     PositionsList=[Numeric.array(  [ Numeric.array((0.0,0.0,0.0)),Numeric.array((0.5,0.,0.))]    ),
                                    Numeric.array( (Numeric.array((1.0,0.5,0.5)),)  )
                                   ]
      ):

  ####################################################
  # OP_cella.Reflection(self)
  # Reflection reflects all the position on the cell origin.
  # The shift is left untouched because it is the shift of the origin itself.

  def Reflection(self):


  ##########################################################
  # OP_cella.getK(self, N=2)
  # Returns an array of 3D vectors, that are spanned by
  # integer multiples of cell's Brillouin vectors.
  # integers run form -N to N.
  # (the vectors are already multiplied by imaginary unit
  #  in order to be ready for fourier transforming)
  
  def getK(self, N=2):


  ###########################################################
  # OP_cella.getFourier(self, K)
  # return an array (for each atom kind(element))
  # of arrays (for each vector in K) of fourier component
  # Dirac delta are put on the atoms locations.

  def getFourier(self, K):

  ################################################################################
  # OP_cella.Transform(self,Az1, Ax, Az2   ,DPOS )
  # Rotates by the three Eulerian angles Az1, Ax, Az2 around
  # the x and z axis through the origin and shifts the origin by DPOS

  def Transform(self,Az1, Ax, Az2   ,DPOS ):


  ################################################################################
  # OP_cella.TransformByMatrix(self, rot ,DPOS )
  # Rotates by the rot matrix and shifts the origin by DPOS

  def TransformByMatrix(self, rot ,DPOS ):


  ############################################################
  # OP_cella.computeDistances(self, maxdist)
  # It builds up a Big multiple dictionary, namely
  #
  # self.distances[Aa][Bb][kA][kB][(DX,DY,DZ)]
  #
  # where Aa and kA are the atom name ( for example "Si",..)
  #  and the position in the array of vectors in cell.PositionsList
  # starting from 0. Same thing for Bb and kB.
  # (DX,DY,DZ) are integer numbers specifying the cell containing (Bb,kB)
  # relatively to (Aa,kA) 

  def computeDistances(self, maxdist):


  ##################################################################################
  # OP_cella. FindTetragons(self, Latoms)
  # This is the key routine to find good candidates to symmetry group.
  # Latoms is a list of the kind [  (Aa,kA) ,(Bb,kB)....] 
  # ( i.e. couples formed by atom-name and position in the position list.
  # Latoms must be formed of four  atoms defining a non-degenerate tetraedron.
  # A check is permormed on the non-degeneracy.
  # The funtions finds all the possible equivalent tetraedrons (which have the same
  # set of distances, and the same atom kinds)
  # The function return the list of all these tetraedrons
 
  def FindTetragons(self, Latoms, CellsCoo=[(0,0,0),(0,0,0),(0,0,0),(0,0,0)]):


  ###############################################################
  # OP_cella.FindEquivalences(self, CellsList)
  # This function should receive a list of cells (CellList)
  # that are superpose as they are, atom by atom to self.
  # (program stops if this condition is not satisfied)
  # It sets  self.equivalences containing a list of lists containing set of equivalent atoms in the format [(Aa,kA),...],
  #          for each cell atom. It is exactly a multiplication table for the symmetry group
  #
  #          self.grouplist    containing the names given to the groups (like Cu_G1 )
  #          self.Groups       a list of groups. Each group contains the equivalent atoms in the format (Aa,kA)
  #          self.DGroups      self.DGroups[(Aa,kA)] gives the name (a name like Cu_G1 ) to which atom (Aa,kA) belongs

   
  def FindEquivalences(self, CellsList):


  ###################################################
  # OP_cella.printEquivalences(self)
  # prints in a more readeble format
  #     self.equivalences
  #     self.DGroups

  def printEquivalences(self):

  ################################################
  #  OP_cella.computeHistograms(self, DR=0.1)
  #  for all the couples of atom groups g1,g2, creates a multiple dictionary
  #  histo[g1][g2]
  #  giving a list of items in the format [ [ r1  ,r2  , Ninteractions)....
  #   where Ninteractions are the number of interactions between an atom of g1
  #   and one of g2 at a distance between r1 and r2, r1-r2 being the maximum interval smaller
  # than DR

  def computeHistograms(self, DR=0.1):


  ####################################
  # print self.histo
  #
  def  printHisto(self,n):
