#!/usr/bin/env python

#-------------------------------------------------------------------------------
#
#   matter.py
#   library of operations on dictionary mat
#   written by G. Samsonidze (October 2008)
#
#-------------------------------------------------------------------------------

import math
from common import eps9, inf9, bohr, format_index2mat, format_espresso2mat, format_mat2espresso, format_siesta2mat, factor_siesta2mat, format_mat2siesta, format_tbpw2mat, format_mat2tbpw, atomsize, bondradius, bondtolerance, minimumbondingdistance, strictvalence, vertex, edge, face, periodic_table, index_by_number, index_by_symbol
from matrix import vector_dot_matrix, matrix_dot_vector, matrix_dot_matrix, determinant_matrix, invert_matrix

def main(argv = None):
   if argv is None:
      argv = sys.argv
   argc = len(argv)
   self = "matter.py"
   if argv[0][-len(self):] != self:
      sys.exit("\n   Rename script to %s\n" % self)
   print("\n   Module %s contains the following names:\n" % self)
   print("   mat_create     - create dictionary mat")
   print("   mat_check      - check dictionary mat")
   print("   mat_species    - get list of species from dictionary mat")
   print("   mat_format     - change format of dictionary mat")
   print("   mat_lattice    - set lattive parameters for dictionary mat")
   print("   mat_remove     - remove atom from dictionary mat")
   print("   mat_merge      - merge two dictionaries mat")
   print("   mat_replicate  - replicate dictionary mat into supercell")
   print("   mat_translate  - translate dictionary mat")
   print("   mat_rotate     - rotate dictionary mat")
   print("   mat_read       - read dictionary mat from file mat")
   print("   mat_write      - write dictionary mat to file mat")
   print("   paratec_read   - read dictionary mat from PARATEC input file")
   print("   paratec_write  - write dictionary mat to PARATEC input file")
   print("   vasp_read      - read dictionary mat from VASP POSCAR file")
   print("   vasp_write     - write dictionary mat to VASP POSCAR file")
   print("   espresso_read  - read dictionary mat from QE input file")
   print("   espresso_write - write dictionary mat to QE input file")
   print("   siesta_read    - read dictionary mat from SIESTA input file")
   print("   siesta_write   - write dictionary mat to SIESTA input file")
   print("   tbpw_read      - read dictionary mat from TBPW input file")
   print("   tbpw_write     - write dictionary mat to TBPW input file")
   print("   xyz_read       - read dictionary mat from XYZ file")
   print("   xyz_write      - write dictionary mat to XYZ file")
   print("   xsf_read       - read dictionary mat from XCrysDen XSF file")
   print("   xsf_write      - write dictionary mat to XCrysDen XSF file")
   print("   wien_write     - write dictionary mat to WIEN2k XYZ file")
   print("   povray_write   - write dictionary mat to POV-Ray file\n")
   return 0

def mat_create():
   mat = {}
   mat['nm'] = ''
   mat['ns'] = 0
   mat['na'] = 0
   mat['fc'] = format_index2mat[0]
   mat['lc'] = 0.0
   mat['fo'] = format_index2mat[0]
   mat['lo'] = [0.0, 0.0, 0.0]
   mat['fv'] = format_index2mat[0]
   mat['lv'] = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
   mat['fp'] = format_index2mat[0]
   mat['as'] = []
   mat['ap'] = []
   return mat

def mat_check(mat):
   ierr = 0
   if 'nm' in mat and 'ns' in mat and 'na' in mat and 'fc' in mat and 'lc' in mat and 'fo' in mat and 'lo' in mat and 'fv' in mat and 'lv' in mat and 'fp' in mat and 'as' in mat and 'ap' in mat:
      if type(mat['nm']) is not str:
         ierr = 1
      if type(mat['ns']) is not int:
         ierr = 1
      if type(mat['na']) is not int:
         ierr = 1
      if mat['fc'] != format_index2mat[0] and mat['fc'] != format_index2mat[1]:
         ierr = 1
      if type(mat['lc']) is not float:
         ierr = 1
      if mat['fo'] != format_index2mat[0] and mat['fo'] != format_index2mat[1] and mat['fo'] != format_index2mat[2] and mat['fo'] != format_index2mat[3]:
         ierr = 1
      if len(mat['lo']) != 3:
         ierr = 1
      for j in range(3):
         if type(mat['lo'][j]) is not float:
            ierr = 1
      if mat['fv'] != format_index2mat[0] and mat['fv'] != format_index2mat[1] and mat['fv'] != format_index2mat[2]:
         ierr = 1
      if len(mat['lv']) != 3:
         ierr = 1
      for i in range(3):
         if len(mat['lv'][i]) != 3:
            ierr = 1
      for i in range(3):
         for j in range(3):
            if type(mat['lv'][i][j]) is not float:
               ierr = 1
      if mat['fp'] != format_index2mat[0] and mat['fp'] != format_index2mat[1] and mat['fp'] != format_index2mat[2] and mat['fp'] != format_index2mat[3]:
         ierr = 1
      if len(mat['as']) != mat['na']:
         ierr = 1
      for i in range(mat['na']):
         if type(mat['as'][i]) is not int:
            ierr = 1
      if len(mat_species(mat['na'], mat['as'])) != mat['ns']:
         ierr = 1
      if len(mat['ap']) != mat['na']:
         ierr = 1
      for i in range(mat['na']):
         if len(mat['ap'][i]) != 3:
            ierr = 1
      for i in range(mat['na']):
         for j in range(3):
            if type(mat['ap'][i][j]) is not float:
               ierr = 1
   else:
      ierr = 1
   return ierr

def mat_species(mat_na, mat_as):
   cs = []
   for i in range(mat_na):
      if mat_as[i] not in cs:
         cs.append(mat_as[i])
   return cs

def mat_format(mat, fc, fo, fv, fp):
   mat['fc'], mat['lc'] = mat_fc_lc(mat['fc'], mat['lc'], fc)
   mat['fv'], mat['lv'] = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], fv)
   mat['fo'], mat['lo'] = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], fo)
   mat['fp'], mat['ap'] = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], fp)
   return mat

def mat_lattice(mat, axes, distance, format):
   if format != format_index2mat[3]:
      if mat['fo'] == format_index2mat[3]:
         mat['fo'], mat['lo'] = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], mat['fv'])
      if mat['fp'] == format_index2mat[3]:
         mat['fp'], mat['ap'] = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], mat['fv'])
      fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
      if fr == format:
         fo = fr
         lo = []
         for j in range(3):
            lo.append(rmin[j] - distance / 2)
         fo, lo = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], fo, lo, mat['fo'])
         mat['fo'] = fo
         mat['lo'] = lo
         fv = fr
         lv = []
         for i in range(3):
            lv.append([])
            for j in range(3):
               if j == i:
                  lv[i].append(rmax[j] - rmin[j] + distance)
               else:
                  lv[i].append(0.0)
         fv, lv = mat_fv_lv(mat['fc'], mat['lc'], fv, lv, mat['fv'])
         if axes[0] != 0 and axes[1] != 0 and axes[2] != 0:
            mat['fv'] = fv
            mat['lv'] = lv
         elif fv == mat['fv']:
            for i in range(3):
               if axes[i] != 0:
                  for j in range(3):
                     mat['lv'][i][j] = lv[i][j]
   return mat

def mat_remove(mat, index):
   if index >= 0 and index < mat['na']:
      mat['na'] -= 1
      del mat['as'][index]
      del mat['ap'][index]
      mat['ns'] = len(mat_species(mat['na'], mat['as']))
   return mat

def mat_merge(matc, mats):
   mat = {}
   if matc['fc'] == format_index2mat[0] and mats['fc'] == format_index2mat[0] and matc['fo'] == format_index2mat[0] and mats['fo'] == format_index2mat[0] and matc['fv'] == format_index2mat[0] and mats['fv'] == format_index2mat[0] and matc['fp'] == format_index2mat[0] and mats['fp'] == format_index2mat[0]:
      format = format_index2mat[0]
   if matc['fc'] == format_index2mat[1] and mats['fc'] == format_index2mat[1] and matc['fo'] == format_index2mat[1] and mats['fo'] == format_index2mat[1] and matc['fv'] == format_index2mat[1] and mats['fv'] == format_index2mat[1] and matc['fp'] == format_index2mat[1] and mats['fp'] == format_index2mat[1]:
      format = format_index2mat[1]
   else:
      format = format_index2mat[0]
   fcc, lcc = mat_fc_lc(matc['fc'], matc['lc'], format)
   fcs, lcs = mat_fc_lc(mats['fc'], mats['lc'], format)
   fvc, lvc = mat_fv_lv(matc['fc'], matc['lc'], matc['fv'], matc['lv'], format)
   fvs, lvs = mat_fv_lv(mats['fc'], mats['lc'], mats['fv'], mats['lv'], format)
   foc, loc = mat_fo_lo(matc['fc'], matc['lc'], matc['fv'], matc['lv'], matc['fo'], matc['lo'], format)
   fos, los = mat_fo_lo(mats['fc'], mats['lc'], mats['fv'], mats['lv'], mats['fo'], mats['lo'], format)
   fpc, apc = mat_fp_ap(matc['na'], matc['fc'], matc['lc'], matc['fv'], matc['lv'], matc['fp'], matc['ap'], format)
   fps, aps = mat_fp_ap(mats['na'], mats['fc'], mats['lc'], mats['fv'], mats['lv'], mats['fp'], mats['ap'], format)
   if fcc == format and fcs == format and fvc == format and fvs == format and foc == format and fos == format and fpc == format and fps == format:
      mat['nm'] = '%s %s' % (matc['nm'], mats['nm'])
      mat['na'] = matc['na'] + mats['na']
      mat['fc'] = matc['fc']
      mat['lc'] = matc['lc']
      mat['fo'] = format
      mat['lo'] = loc
      mat['fv'] = format
      mat['lv'] = []
      for i in range(3):
         mat['lv'].append([])
         for j in range(3):
            vc = lvc[i][j]
            vs = lvs[i][j] + los[j] - loc[j]
            if abs(vc) > abs(vs):
               lv = vc
            else:
               lv = vs
            mat['lv'][i].append(lv)
      mat['fp'] = format
      mat['as'] = []
      mat['ap'] = []
      for i in range(matc['na']):
         mat['as'].append(matc['as'][i])
         mat['ap'].append(apc[i])
      for i in range(mats['na']):
         mat['as'].append(mats['as'][i])
         mat['ap'].append(aps[i])
      mat['ns'] = len(mat_species(mat['na'], mat['as']))
   fcc = matc['fc']
   fvc = matc['fv']
   foc = matc['fo']
   fpc = matc['fp']
   mat['fc'], mat['lc'] = mat_fc_lc(mat['fc'], mat['lc'], fcc)
   mat['fv'], mat['lv'] = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], fvc)
   mat['fo'], mat['lo'] = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], foc)
   mat['fp'], mat['ap'] = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], fpc)
   return mat

def mat_replicate(mat, so, sv, format):
   smin = []
   smax = []
   si = []
   imax = 1000
   if format == format_index2mat[3]:
      format = mat['fv']
      so = vector_dot_matrix(so, mat['lv'])
      sv = matrix_dot_matrix(sv, mat['lv'])
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format)
   fo, lo = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], format)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fo == format and fv == format and fp == format:
      sn, sw = normal_make(sv)
      ln, lw = normal_make(lv)
      scenter = []
      for j in range(3):
         scenter.append(so[j])
      for i in range(3):
         for j in range(3):
            scenter[j] += sv[i][j] / 2
      scorner = []
      for i in range(8):
         scorner.append([])
         for j in range(3):
            scorner[i].append(scenter[j])
            for k in range(3):
               scorner[i][j] += sv[k][j] * (vertex[i][k] - 0.5)
      for i in range(3):
         smin.append(imax)
         smax.append(-imax)
         for j in range(8):
            p = 0.0
            for k in range(3):
               p += scorner[j][k] * ln[i][k]
            p /= lw[i]
            k = int(p)
            if p < 0.0:
               k -= 1
            else:
               k += 1
            if k < smin[i]:
               smin[i] = k
            if k > smax[i]:
               smax[i] = k
      amin = []
      amax = []
      for i in range(3):
         amin.append(imax)
         amax.append(-imax)
         for j in range(mat['na']):
            p = 0.0
            for k in range(3):
               p += ap[j][k] * ln[i][k]
            p /= lw[i]
            k = int(p)
            if p < 0.0:
               k -= 1
            else:
               k += 1
            if k < amin[i]:
               amin[i] = k
            if k > amax[i]:
               amax[i] = k
      j = 0
      for i in range(3):
         if abs(amin[i]) > j:
            j = abs(amin[i])
         if abs(amax[i]) > j:
            j = abs(amax[i])
      for i in range(3):
         smin[i] -= j
         smax[i] += j
      pscenter = []
      for i in range(3):
         pscenter.append(0.0)
         for j in range(3):
            pscenter[i] += scenter[j] * sn[i][j]
      psmin = []
      psmax = []
      for i in range(3):
         psmin.append(pscenter[i] - 0.5 * sw[i] - eps9)
         psmax.append(pscenter[i] + 0.5 * sw[i] - eps9)
      sna = 0
      sas = []
      sap = []
      for i in range(smin[0], smax[0] + 1):
         for j in range(smin[1], smax[1] + 1):
            for k in range(smin[2], smax[2] + 1):
               for l in range(mat['na']):
                  sa = []
                  for m in range(3):
                     sa.append(lv[0][m] * i + lv[1][m] * j + lv[2][m] * k + ap[l][m])
                  pa = []
                  for m in range(3):
                     pa.append(0.0)
                     for n in range(3):
                        pa[m] += sa[n] * sn[m][n]
                  flag = 1
                  for m in range(3):
                     if pa[m] < psmin[m] or pa[m] > psmax[m]:
                        flag = 0
                  if flag != 0:
                     sna += 1
                     sas.append(mat['as'][l])
                     sap.append(sa)
                     si.append([l, i, j, k])
      mat['na'] = sna
      mat['ns'] = len(mat_species(sna, sas))
      mat['fo'] = format
      mat['lo'] = so
      mat['fv'] = format
      mat['lv'] = sv
      mat['fp'] = format
      mat['as'] = sas
      mat['ap'] = sap
   return smin, smax, si, mat

def mat_translate(mat, translation, format):
   fo, lo = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], format)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fo == format and fp == format:
      for j in range(3):
         lo[j] += translation[j]
      for i in range(mat['na']):
         for j in range(3):
            ap[i][j] += translation[j]
      mat['fo'], mat['lo'] = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], fo, lo, mat['fo'])
      mat['fp'], mat['ap'] = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], fp, ap, mat['fp'])
   return mat

def mat_rotate(mat, rotation):
   if mat['fo'] == format_index2mat[3] or mat['fp'] == format_index2mat[3]:
      format = format_index2mat[0]
   else:
      format = mat['fp']
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format)
   fo, lo = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], format)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fo == format and fv == format and fp == format:
      lo = matrix_dot_vector(rotation, lo)
      for i in range(3):
         lv[i] = matrix_dot_vector(rotation, lv[i])
      for i in range(mat['na']):
         ap[i] = matrix_dot_vector(rotation, ap[i])
      mat['fv'], mat['lv'] = mat_fv_lv(mat['fc'], mat['lc'], fv, lv, mat['fv'])
      mat['fo'], mat['lo'] = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], fo, lo, mat['fo'])
      mat['fp'], mat['ap'] = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], fp, ap, mat['fp'])
   return mat

def mat_fc_lc(mat_fc, mat_lc, fc):
   if fc == format_index2mat[0] and mat_fc == format_index2mat[1]:
      lc = mat_lc / bohr
   elif fc == format_index2mat[1] and mat_fc == format_index2mat[0]:
      lc = mat_lc * bohr
   else:
      fc = mat_fc
      lc = mat_lc
   return fc, lc

def mat_fv_lv(mat_fc, mat_lc, mat_fv, mat_lv, fv):
   flag = 1
   if fv == format_index2mat[0] and mat_fv == format_index2mat[1]:
      factor = 1.0 / bohr
   elif fv == format_index2mat[1] and mat_fv == format_index2mat[0]:
      factor = bohr
   elif (fv == format_index2mat[0] or fv == format_index2mat[1]) and mat_fv == format_index2mat[2]:
      fc, lc = mat_fc_lc(mat_fc, mat_lc, fv)
      factor = lc
   elif fv == format_index2mat[2] and (mat_fv == format_index2mat[0] or mat_fv == format_index2mat[1]):
      fc, lc = mat_fc_lc(mat_fc, mat_lc, mat_fv)
      if abs(lc) > eps9:
         factor = 1.0 / lc
      else:
         flag = 0
   else:
      flag = 0
   if flag == 0:
      fv = mat_fv
      factor = 1.0
   lv = []
   for i in range(3):
      lv.append([])
      for j in range(3):
         lv[i].append(mat_lv[i][j] * factor)
   return fv, lv

def mat_fo_lo(mat_fc, mat_lc, mat_fv, mat_lv, mat_fo, mat_lo, fo):
   flag = 1
   if fo == format_index2mat[0] and mat_fo == format_index2mat[1]:
      factor = 1.0 / bohr
   elif fo == format_index2mat[1] and mat_fo == format_index2mat[0]:
      factor = bohr
   elif (fo == format_index2mat[0] or fo == format_index2mat[1]) and mat_fo == format_index2mat[2]:
      fc, lc = mat_fc_lc(mat_fc, mat_lc, fo)
      factor = lc
   elif fo == format_index2mat[2] and (mat_fo == format_index2mat[0] or mat_fo == format_index2mat[1]):
      fc, lc = mat_fc_lc(mat_fc, mat_lc, mat_fo)
      if abs(lc) > eps9:
         factor = 1.0 / lc
      else:
         flag = 0
   elif (fo == format_index2mat[0] or fo == format_index2mat[1] or fo == format_index2mat[2]) and mat_fo == format_index2mat[3]:
      fv, lv = mat_fv_lv(mat_fc, mat_lc, mat_fv, mat_lv, fo)
      if fv == fo:
         matrix = lv
         flag = 2
      else:
         flag = 0
   elif fo == format_index2mat[3] and (mat_fo == format_index2mat[0] or mat_fo == format_index2mat[1] or mat_fo == format_index2mat[2]):
      fv, lv = mat_fv_lv(mat_fc, mat_lc, mat_fv, mat_lv, mat_fo)
      if fv == mat_fo:
         ierr, matrix = invert_matrix(lv)
         if ierr == 0:
            flag = 2
         else:
            flag = 0
      else:
         flag = 0
   else:
      flag = 0
   if flag == 0:
      fo = mat_fo
      factor = 1.0
   if flag != 2:
      lo = []
      for j in range(3):
         lo.append(mat_lo[j] * factor)
   else:
      lo = vector_dot_matrix(mat_lo, matrix)
   return fo, lo

def mat_fp_ap(mat_na, mat_fc, mat_lc, mat_fv, mat_lv, mat_fp, mat_ap, fp):
   flag = 1
   if fp == format_index2mat[0] and mat_fp == format_index2mat[1]:
      factor = 1.0 / bohr
   elif fp == format_index2mat[1] and mat_fp == format_index2mat[0]:
      factor = bohr
   elif (fp == format_index2mat[0] or fp == format_index2mat[1]) and mat_fp == format_index2mat[2]:
      fc, lc = mat_fc_lc(mat_fc, mat_lc, fp)
      factor = lc
   elif fp == format_index2mat[2] and (mat_fp == format_index2mat[0] or mat_fp == format_index2mat[1]):
      fc, lc = mat_fc_lc(mat_fc, mat_lc, mat_fp)
      if abs(lc) > eps9:
         factor = 1.0 / lc
      else:
         flag = 0
   elif (fp == format_index2mat[0] or fp == format_index2mat[1] or fp == format_index2mat[2]) and mat_fp == format_index2mat[3]:
      fv, lv = mat_fv_lv(mat_fc, mat_lc, mat_fv, mat_lv, fp)
      if fv == fp:
         matrix = lv
         flag = 2
      else:
         flag = 0
   elif fp == format_index2mat[3] and (mat_fp == format_index2mat[0] or mat_fp == format_index2mat[1] or mat_fp == format_index2mat[2]):
      fv, lv = mat_fv_lv(mat_fc, mat_lc, mat_fv, mat_lv, mat_fp)
      if fv == mat_fp:
         ierr, matrix = invert_matrix(lv)
         if ierr == 0:
            flag = 2
         else:
            flag = 0
      else:
         flag = 0
   else:
      flag = 0
   if flag == 0:
      fp = mat_fp
      factor = 1.0
   ap = []
   if flag != 2:
      for i in range(mat_na):
         ap.append([])
         for j in range(3):
            ap[i].append(mat_ap[i][j] * factor)
   else:
      for i in range(mat_na):
         ap.append(vector_dot_matrix(mat_ap[i], matrix))
   return fp, ap

def mat_range(mat_na, mat_fc, mat_lc, mat_fv, mat_lv, mat_fp, mat_ap, fr):
   fp, ap = mat_fp_ap(mat_na, mat_fc, mat_lc, mat_fv, mat_lv, mat_fp, mat_ap, fr)
   if fp != fr:
      fr = fp
   if mat_na > 0:
      rmin = [inf9, inf9, inf9]
      rmax = [-inf9, -inf9, -inf9]
      for j in range(3):
         for i in range(mat_na):
            if ap[i][j] < rmin[j]:
               rmin[j] = ap[i][j]
            if ap[i][j] > rmax[j]:
               rmax[j] = ap[i][j]
   else:
      rmin = [0.0, 0.0, 0.0]
      rmax = [0.0, 0.0, 0.0]
   return fr, rmin, rmax

def normal_make(vector):
   normal = []
   weight = []
   normal.append([])
   normal[0].append(vector[1][1] * vector[2][2] - vector[1][2] * vector[2][1])
   normal[0].append(vector[1][2] * vector[2][0] - vector[1][0] * vector[2][2])
   normal[0].append(vector[1][0] * vector[2][1] - vector[1][1] * vector[2][0])
   normal.append([])
   normal[1].append(vector[2][1] * vector[0][2] - vector[2][2] * vector[0][1])
   normal[1].append(vector[2][2] * vector[0][0] - vector[2][0] * vector[0][2])
   normal[1].append(vector[2][0] * vector[0][1] - vector[2][1] * vector[0][0])
   normal.append([])
   normal[2].append(vector[0][1] * vector[1][2] - vector[0][2] * vector[1][1])
   normal[2].append(vector[0][2] * vector[1][0] - vector[0][0] * vector[1][2])
   normal[2].append(vector[0][0] * vector[1][1] - vector[0][1] * vector[1][0])
   for i in range(3):
      weight.append(0.0)
      for j in range(3):
         weight[i] += math.pow(normal[i][j], 2)
      weight[i] = math.sqrt(weight[i])
   for i in range(3):
      if abs(weight[i]) < eps9:
         weight[i] = 1.0
   for i in range(3):
      for j in range(3):
         normal[i][j] /= weight[i]
   for i in range(3):
      weight[i] = 0.0
      for j in range(3):
         weight[i] += vector[i][j] * normal[i][j]
   for i in range(3):
      for j in range(3):
         normal[i][j] *= weight[i]
   for i in range(3):
      weight[i] = 0.0
      for j in range(3):
         weight[i] += math.pow(normal[i][j], 2)
   for i in range(3):
      if abs(weight[i]) < eps9:
         weight[i] = 1.0
   return normal, weight

def mat_read(file):
   ierr = 0
   mat = mat_create()
   mat['fc'] = format_index2mat[0]
   mat['lc'] = 1.0
   mat['fo'] = format_index2mat[0]
   mat['fv'] = format_index2mat[0]
   mat['fp'] = format_index2mat[0]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      i = 1
      ic = 0
      io = 0
      iv = 0
      ip = 0
      for s in r:
         t = s.split()
         if len(t) > 0:
            if t[0].lower() == 'name_of_matter':
               for j in range(1, len(t)):
                  if j > 1:
                     mat['nm'] += ' '
                  mat['nm'] += t[j]
            elif t[0].lower() == 'number_of_species':
               mat['ns'] = int(t[1])
            elif t[0].lower() == 'number_of_atoms':
               mat['na'] = int(t[1])
            elif t[0].lower() == 'lattice_constant':
               mat['fc'] = t[1].lower()
               ic = i
            elif t[0].lower() == 'lattice_origin':
               mat['fo'] = t[1].lower()
               io = i
            elif t[0].lower() == 'lattice_vectors':
               mat['fv'] = t[1].lower()
               iv = i
            elif t[0].lower() == 'atomic_species_and_atomic_positions':
               mat['fp'] = t[1].lower()
               ip = i
         i += 1
      if ic > 0:
         s = r[ic]
         t = s.split()
         mat['lc'] = float(t[0])
      if io > 0:
         s = r[io]
         t = s.split()
         for j in range(3):
            mat['lo'][j] = float(t[j])
      if iv > 0:
         for i in range(3):
            s = r[iv + i]
            t = s.split()
            for j in range(3):
               mat['lv'][i][j] = float(t[j])
      if ip > 0:
         for i in range(mat['na']):
            s = r[ip + i]
            t = s.split()
            mat['as'].append(int(t[0]))
            mat['ap'].append([])
            for j in range(3):
               mat['ap'][i].append(float(t[j + 1]))
   return ierr, mat

def mat_write(file, mat):
   ierr = 0
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('\n')
      s = 'name_of_matter %s\n' % mat['nm']
      h.write(s)
      s = 'number_of_species %i\n' % mat['ns']
      h.write(s)
      s = 'number_of_atoms %i\n' % mat['na']
      h.write(s)
      h.write('\n')
      s = 'lattice_constant %s\n' % mat['fc']
      h.write(s)
      s = '     %13.9f\n' % mat['lc']
      h.write(s)
      h.write('\n')
      s = 'lattice_origin %s\n' % mat['fo']
      h.write(s)
      s = '    '
      for j in range(3):
         s += ' %13.9f' % mat['lo'][j]
      s += '\n'
      h.write(s)
      h.write('\n')
      s = 'lattice_vectors %s\n' % mat['fv']
      h.write(s)
      for i in range(3):
         s = '    '
         for j in range(3):
            s += ' %13.9f' % mat['lv'][i][j]
         s += '\n'
         h.write(s)
      h.write('\n')
      s = 'atomic_species_and_atomic_positions %s\n' % mat['fp']
      h.write(s)
      for i in range(mat['na']):
         s = ' %3i' % mat['as'][i]
         for j in range(3):
            s += ' %13.9f' % mat['ap'][i][j]
         s += '\n'
         h.write(s)
      h.write('\n')
      h.close()
   return ierr

def paratec_read(file):
   ierr = 0
   mat = mat_create()
   mat['nm'] = 'paratec'
   mat['fc'] = format_index2mat[0]
   mat['lc'] = 1.0
   mat['fv'] = format_index2mat[0]
   mat['fp'] = format_index2mat[3]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      i = 1
      iv = 0
      ip = 0
      flag = 0
      for s in r:
         t = s.split()
         if len(t) > 0:
            if t[0].lower() == 'volume':
               volume = float(t[1])
               flag = 1
            elif t[0].lower() == 'coordinates_absolute':
               mat['fp'] = format_index2mat[0]
            elif t[0].lower() == 'begin':
               if t[1].lower() == 'latticevecs':
                  iv = i
               elif t[1].lower() == 'coordinates':
                  ip = i
         i += 1
      if iv > 0:
         for i in range(3):
            s = r[iv + i]
            t = s.split()
            for j in range(3):
               mat['lv'][i][j] = float(t[j + 1])
      if ip > 0:
         i = 0
         na = 0
         ns = 0
         number = 0
         while 1:
            s = r[ip + i]         
            t = s.split()
            if t[0].lower() == 'newtype':
               index = index_by_symbol(t[1])
               number = periodic_table[index]['number']
               ns += 1
            elif t[0].lower() == 'coord':
               mat['as'].append(number)
               mat['ap'].append([])
               for j in range(3):
                  mat['ap'][na].append(float(t[j + 1]))
               na += 1
            else:
               break
            i += 1
         mat['na'] = na
         mat['ns'] = ns
      if flag != 0:
         ierr, det = determinant_matrix(mat['lv'])
         if abs(det) > eps9:
            mat['fc'] = format_index2mat[0]
            mat['lc'] = math.pow(volume / det, 1.0 / 3.0)
            mat['fv'] = format_index2mat[2]
         else:
            ierr = 1
   format = mat['fv']
   mat['fo'] = format
   fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fr == format:
      for j in range(3):
         mat['lo'][j] = (rmin[j] + rmax[j]) / 2
         for i in range(3):
            mat['lo'][j] -= mat['lv'][i][j] / 2
   return ierr, mat

def paratec_write(file, mat):
   ierr = 0
   nsafety = 5
   eigspacefrac = 0.5
   cs = mat_species(mat['na'], mat['as'])
   nelec = 0
   for i in range(mat['na']):
      nelec += periodic_table[index_by_number(mat['as'][i])]['nvelec']
   nbnd = nelec / 2
   if nelec % 2 != 0:
      nbnd += 1
   ratio = nbnd / eigspacefrac
   nbnd = int(ratio)
   if nbnd < ratio - eps9:
      nbnd += 1
   nbndfft = nbnd + nsafety - 1
   if mat['fv'] == format_index2mat[1]:
      fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format_index2mat[0])
      if fv != format_index2mat[0]:
         ierr = 1
   else:
      fv = mat['fv']
      lv = mat['lv']
   if fv == format_index2mat[2]:
      fc, lc = mat_fc_lc(mat['fc'], mat['lc'], format_index2mat[0])
      if fc == format_index2mat[0]:
         ierr, det = determinant_matrix(lv)
         volume = det * math.pow(lc, 3)
      else:
         ierr = 1
   if mat['fp'] == format_index2mat[1] or mat['fp'] == format_index2mat[2]:
      fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format_index2mat[0])
      if fp != format_index2mat[0]:
         ierr = 1
   else:
      fp = mat['fp']
      ap = mat['ap']
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('\n')
      h.write('begin pw_jobs\n')
      h.write('pw_job scf\n')
      h.write('end pw_jobs\n')
      h.write('\n')
      h.write('begin latticevecs\n')
      for i in range(3):
         s = 'coord'
         for j in range(3):
            s += ' %13.9f' % lv[i][j]
         s += '\n'
         h.write(s)
      if fv == format_index2mat[2]:
         s = 'volume %.9f\n' % volume
         h.write(s)
      h.write('end latticevecs\n')
      h.write('\n')
      if fp == format_index2mat[0]:
         h.write('coordinates_absolute\n')
      h.write('begin coordinates\n')
      for i in range(mat['ns']):
         index = index_by_number(cs[i])
         symbol = periodic_table[index]['symbol']
         s = 'newtype %s\n' % symbol
         h.write(s)
         for j in range(mat['na']):
            if mat['as'][j] == cs[i]:
               s = 'coord'
               for k in range(3):
                  s += ' %13.9f' % ap[j][k]
               s += '\n'
               h.write(s)
      h.write('end coordinates\n')
      h.write('\n')
      h.write('pp_format 3\n')
      h.write('begin pseudopotential\n')
      for i in range(mat['ns']):
         number = periodic_table[index_by_number(cs[i])]['number']
         nvelec = periodic_table[index_by_number(cs[i])]['nvelec']
         period = periodic_table[index_by_number(cs[i])]['period']
         group = periodic_table[index_by_number(cs[i])]['group']
         #
         # find occupations of s,p,d,f shells
         #
         if period < 2 or group < 3:
            occupation = [nvelec, 0, 0, 0]
         elif period < 8 and group > 12:
            occupation = [2, nvelec - 2, 0, 0]
         elif period < 8:
            occupation = [2, 0, nvelec - 2, 0]
         else:
            occupation = [2, 0, 0, nvelec - 2]
         #
         # exceptions are hard-coded below
         #
         if number == 57:
            occupation = [2, 0, 1, 0]
         if number == 58:
            occupation = [2, 0, 1, 1]
         if number == 89:
            occupation = [2, 0, 1, 0]
         if number == 90:
            occupation = [2, 0, 2, 0]
         if number == 91:
            occupation = [2, 0, 1, 2]
         if number == 92:
            occupation = [2, 0, 1, 3]
         #
         # set local channel
         #
         if occupation[3] != 0:
            lloc = 3
         elif occupation[2] != 0:
            lloc = 2
         elif occupation[1] != 0:
            lloc = 1
         else:
            lloc = 0
         #
         # write pseudopotential information
         #
         s = 'pp_data %i %i.0 %i.0 %i.0 %i.0\n' % (tuple([lloc + 1]) + tuple(occupation))
         h.write(s)
      h.write('end pseudopotential\n')
      h.write('\n')
      h.write('exchange_correlation ceperley_alder\n')
      h.write('number_of_spins 1\n')
      h.write('diagonalization_method Grassmann_metal\n')
      h.write('energy_cutoff 60.0\n')
      h.write('submatrix_energy_cutoff 3.0\n')
      h.write('accuracy_diag 1.0e-10\n')
      h.write('diagsafety 2.0\n')
      h.write('number_kpoints 0\n')
      h.write('k_grid 1 1 1\n')
      h.write('k_grid_shift 0.0 0.0 0.0\n')
      s = 'number_bands %i\n' % nbnd
      h.write(s)
      s = 'number_bands_fft %i\n' % nbndfft
      h.write(s)
      s = 'eigspacefrac %.1f\n' % eigspacefrac
      h.write(s)
      h.write('occupy_levels normal\n')
      h.write('smearing_energy 0.001\n')
      h.write('\n')
      h.write('mix_method pulay_kerker\n')
      h.write('energy_convergence_criterion 1.0e-10\n')
      h.write('max_iter_scfloop 50\n')
      h.write('screening_type previous\n')
      h.write('\n')
      h.close()
   return ierr

def vasp_read(file):
   ierr = 0
   mat = mat_create()
   mat['fc'] = format_index2mat[1]
   mat['fv'] = format_index2mat[2]
   mat['fp'] = format_index2mat[3]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      #
      # TEMP ASE FIX BEGIN
      #
      #s = r[0]
      #t = s.split()
      #mat['nm'] = t[0]
      #
      mat['nm'] = 'vasp'
      #
      # TEMP ASE FIX END
      #
      s = r[1]
      t = s.split()
      mat['lc'] = float(t[0])
      for i in range(3):
         s = r[2 + i]
         t = s.split()
         for j in range(3):
            mat['lv'][i][j] = float(t[j])
      if mat['lc'] < 0.0:
         volume = -mat['lc']
         ierr, det = determinant_matrix(mat['lv'])
         if abs(det) > eps9:
            mat['lc'] = math.pow(volume / det, 1.0 / 3.0)
      s = r[5]
      species = s.split()
      s = r[6]
      t = s.split()
      mat['ns'] = len(t)
      for i in range(mat['ns']):
         k = int(t[i])
         index = index_by_symbol(species[i])
         number = periodic_table[index]['number']
         for j in range(k):
            mat['as'].append(number)
         mat['na'] += k
      if r[7][0].lower() == 's':
         k = 1
      else:
         k = 0
      if r[7 + k][0].lower() == 'c' or r[7 + k][0].lower() == 'k':
         mat['fp'] = format_index2mat[2]
      for i in range(mat['na']):
         s = r[8 + k + i]
         t = s.split()
         mat['ap'].append([])
         for j in range(3):
            mat['ap'][i].append(float(t[j]))
   format = mat['fv']
   mat['fo'] = format
   fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fr == format:
      for j in range(3):
         mat['lo'][j] = (rmin[j] + rmax[j]) / 2
         for i in range(3):
            mat['lo'][j] -= mat['lv'][i][j] / 2
   return ierr, mat

def vasp_write(file, mat):
   ierr = 0
   cs = mat_species(mat['na'], mat['as'])
   if mat['fc'] != format_index2mat[1]:
      fc, lc = mat_fc_lc(mat['fc'], mat['lc'], format_index2mat[1])
      if fc != format_index2mat[1]:
         ierr = 1
   else:
      fc = mat['fc']
      lc = mat['lc']
   if mat['fv'] != format_index2mat[2]:
      fv, lv = mat_fv_lv(fc, lc, mat['fv'], mat['lv'], format_index2mat[2])
      if fv != format_index2mat[2]:
         ierr = 1
   else:
      fv = mat['fv']
      lv = mat['lv']
   if mat['fp'] == format_index2mat[0] or mat['fp'] == format_index2mat[1]:
      fp, ap = mat_fp_ap(mat['na'], fc, lc, fv, lv, mat['fp'], mat['ap'], format_index2mat[3])
      if fp != format_index2mat[3]:
         ierr = 1
   else:
      fp = mat['fp']
      ap = mat['ap']
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      #
      # TEMP ASE FIX BEGIN
      #
      # replace the name of the system with the list of atomic species
      # for compatibility with the Atomic Simulation Environment (ASE)
      #
      #s = mat['nm'] + '\n'
      #
      s = ''
      for i in range(mat['ns']):
         index = index_by_number(cs[i])
         symbol = periodic_table[index]['symbol']
         s += ' %s' % symbol
      s += '\n'
      #
      # TEMP ASE FIX END
      #
      h.write(s)
      s = ' %13.9f\n' % lc
      h.write(s)
      for i in range(3):
         s = ''
         for j in range(3):
            s += ' %13.9f' % lv[i][j]
         s += '\n'
         h.write(s)
      s = ''
      for i in range(mat['ns']):
         index = index_by_number(cs[i])
         symbol = periodic_table[index]['symbol']
         s += ' %s' % symbol
      s += '\n'
      h.write(s)
      s = ''
      for i in range(mat['ns']):
         number = 0
         for j in range(mat['na']):
            if mat['as'][j] == cs[i]:
               number += 1
         s += ' %i' % number
      s += '\n'
      h.write(s)
      if fp == format_index2mat[2]:
         s = 'Cartesian\n'
      else:
         s = 'Direct\n'
      h.write(s)
      for i in range(mat['ns']):
         for j in range(mat['na']):
            if mat['as'][j] == cs[i]:
               s = ''
               for k in range(3):
                  s += ' %13.9f' % ap[j][k]
               s += '\n'
               h.write(s)
      h.close()
   return ierr

def espresso_read(file):
   ierr = 0
   mat = mat_create()
   mat['fc'] = format_index2mat[0]
   mat['lc'] = 1.0
   mat['fv'] = format_index2mat[0]
   mat['fp'] = format_index2mat[0]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      u = h.readlines()
      h.close()
      r = []
      for v in u:
         if len(v.replace(' ', '').replace('\t', '').replace('\n', '')) > 0:
            w = v.split(',')
            for x in w:
               r.append(x)
      crystallographic_constants = 0
      i = 1
      iv = 0
      ip = 0
      for s in r:
         t = s.replace('=', ' = ').replace('\'', '').replace('\"', '').replace('{', '').replace('}', '').replace('(', '').replace(')', '').split()
         if len(t) > 0:
            if t[0].lower() == 'prefix':
               for j in range(2, len(t)):
                  if j > 2:
                     mat['nm'] += ' '
                  mat['nm'] += t[j]
            elif t[0].lower() == 'ibrav':
               ibrav = int(t[2])
            elif t[0].lower() == 'celldm1':
               crystallographic_constants = 1
               mat['fc'] = format_index2mat[0]
               celldm1 = float(t[2])
               mat['lc'] = celldm1
               mat['fv'] = format_index2mat[2]
               mat['fp'] = format_index2mat[2]
            elif t[0].lower() == 'celldm2':
               celldm2 = float(t[2])
            elif t[0].lower() == 'celldm3':
               celldm3 = float(t[2])
            elif t[0].lower() == 'celldm4':
               celldm4 = float(t[2])
            elif t[0].lower() == 'celldm5':
               celldm5 = float(t[2])
            elif t[0].lower() == 'celldm6':
               celldm6 = float(t[2])
            elif t[0].lower() == 'a':
               crystallographic_constants = 2
               mat['fc'] = format_index2mat[1]
               a = float(t[2])
               mat['lc'] = a
               mat['fv'] = format_index2mat[2]
               mat['fp'] = format_index2mat[2]
            elif t[0].lower() == 'b':
               # to avoid confusion with boron
               if t[1] == '=':
                  b = float(t[2])
            elif t[0].lower() == 'c':
               # to avoid confusion with carbon
               if t[1] == '=':
                  c = float(t[2])
            elif t[0].lower() == 'cos_ab':
               cos_gamma = float(t[2])
            elif t[0].lower() == 'cos_ac':
               cos_beta = float(t[2])
            elif t[0].lower() == 'cos_bc':
               cos_alpha = float(t[2])
            elif t[0].lower() == 'ntyp':
               mat['ns'] = int(t[2])
            elif t[0].lower() == 'nat':
               mat['na'] = int(t[2])
            elif t[0].lower() == 'cell_parameters':
               if len(t) > 1:
                  fv = t[1].lower()
                  if fv == format_mat2espresso[format_index2mat[0]]:
                     mat['fc'] = format_index2mat[0]
                     mat['lc'] = 1.0
                     mat['fv'] = format_index2mat[2]
                  elif fv == format_mat2espresso[format_index2mat[1]]:
                     mat['fc'] = format_index2mat[1]
                     mat['lc'] = 1.0
                     mat['fv'] = format_index2mat[2]
               iv = i
            elif t[0].lower() == 'atomic_positions':
               if len(t) > 1:
                  fp = t[1].lower()
                  if fp in format_espresso2mat:
                     mat['fp'] = format_espresso2mat[fp]
                  else:
                     mat['fp'] = 'latconst'
               else:
                  mat['fp'] = 'latconst'
               ip = i
         i += 1
      if iv > 0:
         for i in range(3):
            s = r[iv + i]
            t = s.split()
            for j in range(3):
               mat['lv'][i][j] = float(t[j])
      if ip > 0:
         for i in range(mat['na']):
            s = r[ip + i]
            t = s.split()
            mat['as'].append(periodic_table[index_by_symbol(t[0])]['number'])
            mat['ap'].append([])
            for j in range(3):
               mat['ap'][i].append(float(t[j + 1]))
      if ibrav == 1:
         mat['lv'] = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
      elif ibrav == 2:
         mat['lv'] = [[-0.5, 0.0, 0.5], [0.0, 0.5, 0.5], [-0.5, 0.5, 0.0]]
      elif ibrav == 3:
         mat['lv'] = [[0.5, 0.5, 0.5], [-0.5, 0.5, 0.5], [-0.5, -0.5, 0.5]]
      elif ibrav == 4:
         if crystallographic_constants == 2:
            celldm3 = c / a
         mat['lv'] = [[1.0, 0.0, 0.0], [-0.5, math.sqrt(3.0) / 2.0, 0.0], [0.0, 0.0, celldm3]]
      elif ibrav == 5:
         if crystallographic_constants == 1:
            cos_alpha = celldm4
         tx = math.sqrt((1.0 - cos_alpha) / 2.0)
         ty = math.sqrt((1.0 - cos_alpha) / 6.0)
         tz = math.sqrt((1.0 + 2.0 * cos_alpha) / 3.0)
         mat['lv'] = [[tx, -ty, tz], [0.0, 2.0 * ty, tz], [-tx, -ty, tz]]
      elif ibrav == -5:
         if crystallographic_constants == 1:
            cos_alpha = celldm4
         tx = math.sqrt((1.0 - cos_alpha) / 2.0)
         ty = math.sqrt((1.0 - cos_alpha) / 6.0)
         tz = math.sqrt((1.0 + 2.0 * cos_alpha) / 3.0)
         u = tz - 2.0 * math.sqrt(2.0) * ty
         v = tz + math.sqrt(2.0) * ty
         mat['lv'] = [[u / math.sqrt(3.0), v / math.sqrt(3.0), v / math.sqrt(3.0)], [v / math.sqrt(3.0), u / math.sqrt(3.0), v / math.sqrt(3.0)], [v / math.sqrt(3.0), v / math.sqrt(3.0), u / math.sqrt(3.0)]]
      elif ibrav == 6:
         if crystallographic_constants == 2:
            celldm3 = c / a
         mat['lv'] = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, celldm3]]
      elif ibrav == 7:
         if crystallographic_constants == 2:
            celldm3 = c / a
         mat['lv'] = [[0.5, -0.5, celldm3 / 2.0], [0.5, 0.5, celldm3 / 2.0], [-0.5, -0.5, celldm3 / 2.0]]
      elif ibrav == 8:
         if crystallographic_constants == 2:
            celldm2 = b / a
            celldm3 = c / a
         mat['lv'] = [[1.0, 0.0, 0.0], [0.0, celldm2, 0.0], [0.0, 0.0, celldm3]]
      elif ibrav == 9:
         if crystallographic_constants == 2:
            celldm2 = b / a
            celldm3 = c / a
         mat['lv'] = [[0.5, celldm2 / 2.0, 0.0], [-0.5, celldm2 / 2.0, 0.0], [0.0, 0.0, celldm3]]
      elif ibrav == 10:
         if crystallographic_constants == 2:
            celldm2 = b / a
            celldm3 = c / a
         mat['lv'] = [[0.5, 0.0, celldm3 / 2.0], [0.5, celldm2 / 2.0, 0.0], [0.0, celldm2 / 2.0, celldm3 / 2.0]]
      elif ibrav == 11:
         if crystallographic_constants == 2:
            celldm2 = b / a
            celldm3 = c / a
         mat['lv'] = [[0.5, celldm2 / 2.0, celldm3 / 2.0], [-0.5, celldm2 / 2.0, celldm3 / 2.0], [-0.5, -celldm2 / 2.0, celldm3 / 2.0]]
      elif ibrav == 12:
         if crystallographic_constants == 1:
            cos_gamma = celldm4
         else:
            celldm2 = b / a
            celldm3 = c / a
         sin_gamma = math.sqrt(1.0 - math.pow(cos_gamma, 2))
         mat['lv'] = [[1.0, 0.0, 0.0], [celldm2 * cos_gamma, celldm2 * sin_gamma, 0.0], [0.0, 0.0, celldm3]]
      elif ibrav == -12:
         if crystallographic_constants == 1:
            cos_beta = celldm5
         else:
            celldm2 = b / a
            celldm3 = c / a
         sin_beta = math.sqrt(1.0 - math.pow(cos_beta, 2))
         mat['lv'] = [[1.0, 0.0, 0.0], [0.0, celldm2, 0.0], [sin_beta, 0.0, celldm3 * cos_beta]]
      elif ibrav == 13:
         if crystallographic_constants == 1:
            cos_gamma = celldm4
         else:
            celldm2 = b / a
            celldm3 = c / a
         sin_gamma = math.sqrt(1.0 - math.pow(cos_gamma, 2))
         mat['lv'] = [[0.5, 0.0, -celldm3 / 2.0], [celldm2 * cos_gamma, celldm2 * sin_gamma, 0.0], [0.5, 0.0, celldm3 / 2.0]]
      elif ibrav == 14:
         if crystallographic_constants == 1:
            cos_alpha = celldm4
            cos_beta = celldm5
            cos_gamma = celldm6
         else:
            celldm2 = b / a
            celldm3 = c / a
         sin_gamma = math.sqrt(1.0 - math.pow(cos_gamma, 2))
         mat['lv'] = [[1.0, 0.0, 0.0], [celldm2 * cos_gamma, celldm2 * sin_gamma, 0.0], [celldm3 * cos_beta, celldm3 * (cos_alpha - cos_beta * cos_gamma) / sin_gamma, celldm3 * math.sqrt(1.0 + 2.0 * cos_alpha * cos_beta * cos_gamma - math.pow(cos_alpha, 2) - math.pow(cos_beta, 2) - math.pow(cos_gamma, 2)) / sin_gamma]]
   format = mat['fv']
   mat['fo'] = format
   fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fr == format:
      for j in range(3):
         mat['lo'][j] = (rmin[j] + rmax[j]) / 2
         for i in range(3):
            mat['lo'][j] -= mat['lv'][i][j] / 2
   return ierr, mat

def espresso_write(file, mat):
   ierr = 0
   cs = mat_species(mat['na'], mat['as'])
   nelec = 0
   for i in range(mat['na']):
      nelec += periodic_table[index_by_number(mat['as'][i])]['nvelec']
   nbnd = nelec / 2
   if nelec % 2 != 0:
      nbnd += 1
   if mat['fv'] == format_index2mat[2] or mat['fp'] == format_index2mat[2]:
      celldm = 1
   else:
      celldm = 0
   if mat['fp'] in format_mat2espresso:
      fp = format_mat2espresso[mat['fp']]
   else:
      ierr = 1
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('&CONTROL\n')
      s = '   prefix = \'%s\'\n' % mat['nm']
      h.write(s)
      h.write('   calculation = \'scf\'\n')
      h.write('   verbosity = \'high\'\n')
      h.write('   wf_collect = .false.\n')
      h.write('   tstress = .true.\n')
      h.write('   tprnfor = .true.\n')
      h.write('   outdir = \'.\'\n')
      h.write('   wfcdir = \'.\'\n')
      h.write('   pseudo_dir = \'.\'\n')
      h.write('/\n')
      h.write('&SYSTEM\n')
      h.write('   ibrav = 0\n')
      if celldm != 0:
         if mat['fc'] == format_index2mat[0]:
            s = '   celldm(1) = %.9f\n' % mat['lc']
         else:
            s = '   a = %.9f\n' % mat['lc']
         h.write(s)
      s = '   nat = %i\n' % mat['na']
      h.write(s)
      s = '   ntyp = %i\n' % mat['ns']
      h.write(s)
      s = '   nbnd = %i\n' % nbnd
      h.write(s)
      h.write('   ecutwfc = 60.0\n')
      h.write('/\n')
      h.write('&ELECTRONS\n')
      h.write('   electron_maxstep = 100\n')
      h.write('   conv_thr = 1.0d-10\n')
      h.write('   mixing_mode = \'plain\'\n')
      h.write('   mixing_beta = 0.7\n')
      h.write('   mixing_ndim = 8\n')
      h.write('   diagonalization = \'david\'\n')
      h.write('   diago_david_ndim = 4\n')
      h.write('   diago_full_acc = .true.\n')
      h.write('/\n')
      s = 'CELL_PARAMETERS'
      if mat['fv'] == format_index2mat[0]:
          s += ' bohr'
      elif mat['fv'] == format_index2mat[1]:
          s += ' angstrom'
      else:
          s += ' alat'
      s += '\n'
      h.write(s)
      for i in range(3):
         s = '    '
         for j in range(3):
            s += ' %13.9f' % mat['lv'][i][j]
         s += '\n'
         h.write(s)
      h.write('ATOMIC_SPECIES\n')
      for i in range(mat['ns']):
         index = index_by_number(cs[i])
         s = '  %2s %7.3f  %s%s\n' % (periodic_table[index]['symbol'], periodic_table[index]['mass'], periodic_table[index]['symbol'], '.UPF')
         h.write(s)
      s = 'ATOMIC_POSITIONS %s\n' % fp
      h.write(s)
      for i in range(mat['na']):
         s = '  %2s' % periodic_table[index_by_number(mat['as'][i])]['symbol']
         for j in range(3):
            s += ' %13.9f' % mat['ap'][i][j]
         s += '\n'
         h.write(s)
      h.write('K_POINTS gamma\n')
      h.close()
   return ierr

def siesta_read(file):
   ierr = 0
   mat = mat_create()
   mat['fc'] = format_index2mat[0]
   mat['lc'] = 0.0
   mat['fv'] = format_index2mat[2]
   mat['fp'] = format_index2mat[0]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      i = 1
      iv = 0
      il = 0
      ip = 0
      for s in r:
         t = s.split()
         if len(t) > 0:
            t[0] = t[0].replace('-', '').replace('_', '').replace('.', '')
            if t[0].lower() == 'systemlabel':
               for j in range(1, len(t)):
                  if j > 1:
                     mat['nm'] += ' '
                  mat['nm'] += t[j]
            elif t[0].lower() == 'numberofspecies':
               mat['ns'] = int(t[1])
            elif t[0].lower() == 'numberofatoms':
               mat['na'] = int(t[1])
            elif t[0].lower() == 'latticeconstant':
               mat['lc'] = float(t[1])
               fc = t[2].lower()
               if fc in format_siesta2mat:
                  mat['lc'] *= factor_siesta2mat[fc]
                  mat['fc'] = format_siesta2mat[fc]
               else:
                  ierr = 1
            elif t[0].lower() == 'atomiccoordinatesformat':
               fp = t[1].lower()
               if fp in format_siesta2mat:
                  mat['fp'] = format_siesta2mat[fp]
               else:
                  ierr = 1
            elif t[0].lower() == '%block':
               if t[1].lower() == 'latticevectors':
                  iv = i
               elif t[1].lower() == 'chemicalspecieslabel':
                  il = i
               elif t[1].lower() == 'atomiccoordinatesandatomicspecies':
                  ip = i
         i += 1
      if iv > 0:
         for i in range(3):
            s = r[iv + i]
            t = s.split()
            for j in range(3):
               mat['lv'][i][j] = float(t[j])
      if il > 0:
         index = []
         number = []
         for i in range(mat['ns']):
            s = r[il + i]
            t = s.split()
            index.append(int(t[0]))
            number.append(int(t[1]))
      if ip > 0:
         for i in range(mat['na']):
            s = r[ip + i]
            t = s.split()
            mat['ap'].append([])
            for j in range(3):
               mat['ap'][i].append(float(t[j]))
            mat['as'].append(number[index.index(int(t[3]))])
   format = mat['fv']
   mat['fo'] = format
   fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fr == format:
      for j in range(3):
         mat['lo'][j] = (rmin[j] + rmax[j]) / 2
         for i in range(3):
            mat['lo'][j] -= mat['lv'][i][j] / 2
   return ierr, mat

def siesta_write(file, mat):
   ierr = 0
   cs = mat_species(mat['na'], mat['as'])
   if mat['fc'] in format_mat2siesta:
      fc = format_mat2siesta[mat['fc']]
   else:
      ierr = 1
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format_index2mat[2])
   if fv != format_index2mat[2]:
      ierr = 1
   if mat['fp'] in format_mat2siesta:
      fp = format_mat2siesta[mat['fp']]
   else:
      ierr = 1
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('\n')
      s = 'SystemName      %s\n' % mat['nm']
      h.write(s)
      s = 'SystemLabel     %s\n' % mat['nm']
      h.write(s)
      s = 'NumberOfSpecies %i\n' % mat['ns']
      h.write(s)
      s = 'NumberOfAtoms   %i\n' % mat['na']
      h.write(s)
      h.write('\n')
      s = 'LatticeConstant %.9f %s\n' % (mat['lc'], fc)
      h.write(s)
      h.write('\n')
      s = 'AtomicCoordinatesFormat %s\n' % fp
      h.write(s)
      h.write('\n')
      h.write('%block LatticeVectors\n')
      for i in range(3):
         s = ''
         for j in range(3):
            s += ' %13.9f' % lv[i][j]
         s += '\n'
         h.write(s)
      h.write('%endblock LatticeVectors\n')
      h.write('\n')
      h.write('%block ChemicalSpeciesLabel\n')
      for i in range(mat['ns']):
         s = '%i %i %s\n' % (i + 1, cs[i], periodic_table[index_by_number(cs[i])]['symbol'])
         h.write(s)
      h.write('%endblock ChemicalSpeciesLabel\n')
      h.write('\n')
      h.write('%block AtomicCoordinatesAndAtomicSpecies\n')
      for i in range(mat['na']):
         s = ''
         for j in range(3):
            s += ' %13.9f' % mat['ap'][i][j]
         an = cs.index(mat['as'][i]) + 1
         s += '  %i' % an
         s += '\n'
         h.write(s)
      h.write('%endblock AtomicCoordinatesAndAtomicSpecies\n')
      h.write('\n')
      h.write('UserBasis T\n')
      h.write('\n')
      h.write('SolutionMethod diagon\n')
      h.write('\n')
      h.write('MD.TypeOfRun CG\n')
      h.write('MD.VariableCell F\n')
      h.write('MD.NumCGsteps 0\n')
      h.write('\n')
      h.write('%block kgrid_Monkhorst_Pack\n')
      h.write('1 0 0 +0.0\n')
      h.write('0 1 0 +0.0\n')
      h.write('0 0 1 +0.0\n')
      h.write('%endblock kgrid_Monkhorst_Pack\n')
      h.write('\n')
      h.close()
   return ierr

def tbpw_read(file):
   ierr = 0
   mat = mat_create()
   mat['nm'] = 'tbpw'
   mat['fc'] = format_index2mat[0]
   mat['lc'] = 0.0
   mat['fv'] = format_index2mat[2]
   mat['fp'] = format_index2mat[3]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      i = 1
      iv = 0
      il = 0
      ip = 0
      for s in r:
         t = s.split()
         if len(t) > 0:
            if t[0].lower() == 'numberofspecies':
               mat['ns'] = int(t[1])
            elif t[0].lower() == 'numberofatoms':
               mat['na'] = int(t[1])
            elif t[0].lower() == 'latticeconstant':
               mat['lc'] = float(t[1])
            elif t[0].lower() == 'latticeconstantformat':
               fc = t[1].lower()
               if fc in format_tbpw2mat:
                  mat['fc'] = format_tbpw2mat[fc]
               else:
                  ierr = 1
            elif t[0].lower() == 'atomiccoordinatesformat':
               fp = t[1].lower()
               if fp in format_tbpw2mat:
                  mat['fp'] = format_tbpw2mat[fp]
               else:
                  ierr = 1
            if t[0].lower() == 'latticevectors':
               iv = i
            elif t[0].lower() == 'chemicalspecieslabel':
               il = i
            elif t[0].lower() == 'atomiccoordinatesandatomicspecies':
               ip = i
         i += 1
      if iv > 0:
         for i in range(3):
            s = r[iv + i]
            t = s.split()
            for j in range(3):
               mat['lv'][i][j] = float(t[j])
      if il > 0:
         index = []
         number = []
         for i in range(mat['ns']):
            s = r[il + i]
            t = s.split()
            index.append(int(t[0]))
            number.append(int(t[1]))
      if ip > 0:
         for i in range(mat['na']):
            s = r[ip + i]
            t = s.split()
            mat['ap'].append([])
            for j in range(3):
               mat['ap'][i].append(float(t[j]))
            mat['as'].append(number[index.index(int(t[3]))])
   format = mat['fv']
   mat['fo'] = format
   fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fr == format:
      for j in range(3):
         mat['lo'][j] = (rmin[j] + rmax[j]) / 2
         for i in range(3):
            mat['lo'][j] -= mat['lv'][i][j] / 2
   return ierr, mat

def tbpw_write(file, mat):
   ierr = 0
   cs = mat_species(mat['na'], mat['as'])
   nelec = 0
   for i in range(mat['na']):
      nelec += periodic_table[index_by_number(mat['as'][i])]['nvelec']
   nbnd = nelec / 2
   if mat['fc'] in format_mat2tbpw:
      fc = format_mat2tbpw[mat['fc']]
   else:
      ierr = 1
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format_index2mat[2])
   if fv != format_index2mat[2]:
      ierr = 1
   if mat['fp'] in format_mat2tbpw:
      if mat['fp'] == format_index2mat[0] or mat['fp'] == format_index2mat[1]:
         fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format_index2mat[2])
         if fp != format_index2mat[2]:
            ierr = 1
      else:
         fp = mat['fp']
         ap = mat['ap']
      fp = format_mat2tbpw[fp]
   else:
      ierr = 1
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('\n')
      h.write('DiagonalizationSwitch 0\n')
      h.write('#AbsoluteTolerance -1.0d0\n')
      h.write('\n')
      h.write('#InputEnergiesInEV\n')
      h.write('EnergyCutoff 11.0\n')
      h.write('\n')
      h.write('NumberOfDimensions 3\n')
      s = 'LatticeConstantFormat %s\n' % fc
      h.write(s)
      s = 'LatticeConstant %.9f\n' % mat['lc']
      h.write(s)
      h.write('LatticeVectors\n')
      for i in range(3):
         s = ''
         for j in range(3):
            s += ' %13.9f' % lv[i][j]
         s += '\n'
         h.write(s)
      h.write('\n')
      s = 'NumberOfAtoms %i\n' % mat['na']
      h.write(s)
      s = 'NumberOfSpecies %i\n' % mat['ns']
      h.write(s)
      h.write('ChemicalSpeciesLabel\n')
      for i in range(mat['ns']):
         s = '%i %i %s\n' % (i + 1, cs[i], periodic_table[index_by_number(cs[i])]['symbol'])
         h.write(s)
      s = 'AtomicCoordinatesFormat %s\n' % fp
      h.write(s)
      h.write('AtomicCoordinatesAndAtomicSpecies\n')
      for i in range(mat['na']):
         s = ''
         for j in range(3):
            s += ' %13.9f' % ap[i][j]
         an = cs.index(mat['as'][i]) + 1
         s += '  %i' % an
         s += '\n'
         h.write(s)
      h.write('\n')
      s = 'NumberOfBands %i\n' % (2 * nbnd)
      h.write(s)
      s = 'NumberOfOccupiedBands %i\n' % nbnd
      h.write(s)
      h.write('\n')
      h.write('KPointsScale reciprocallatticevectors\n')
      h.write('KPointsList 1\n')
      h.write('0.000000000  0.000000000  0.000000000  1.0\n')
      h.write('\n')
      h.close()
   return ierr

def xyz_read(file):
   ierr = 0
   mat = mat_create()
   mat['nm'] = 'xyz'
   mat['fc'] = format_index2mat[1]
   mat['lc'] = 1.0
   mat['fv'] = format_index2mat[1]
   mat['fp'] = format_index2mat[1]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      s = r[0]
      t = s.split()
      mat['na'] = int(t[0])
      s = r[1]
      t = s.split()
      mat['nm'] = ''
      for j in range(len(t)):
         if j > 0:
            mat['nm'] += ' '
         mat['nm'] += t[j]
      for i in range(mat['na']):
         s = r[i + 2]
         t = s.split()
         mat['as'].append(periodic_table[index_by_symbol(t[0])]['number'])
         mat['ap'].append([])
         for j in range(3):
            mat['ap'][i].append(float(t[j + 1]))
   mat['ns'] = len(mat_species(mat['na'], mat['as']))
   format = mat['fv']
   mat['fo'] = format
   axes = [1, 1, 1]
   distance = 10.0
   mat = mat_lattice(mat, axes, distance, format)
   return ierr, mat

def xyz_write(file, mat):
   ierr = 0
   format = format_index2mat[1]
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fp != format:
      ierr = 1
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      s = '%i\n' % mat['na']
      h.write(s)
      s = '%s\n' % mat['nm']
      h.write(s)
      for i in range(mat['na']):
         s = '  %2s' % periodic_table[index_by_number(mat['as'][i])]['symbol']
         for j in range(3):
            s += ' %13.9f' % ap[i][j]
         s += '\n'
         h.write(s)
      h.close()
   return ierr

def xsf_read(file):
   ierr = 0
   mat = mat_create()
   mat['nm'] = 'xsf'
   mat['fc'] = format_index2mat[1]
   mat['lc'] = 1.0
   mat['fv'] = format_index2mat[1]
   mat['fp'] = format_index2mat[1]
   try:
      h = open(file, 'r')
   except:
      ierr = 1
   if ierr == 0:
      r = h.readlines()
      h.close()
      i = 1
      iv = 0
      ip = 0
      for s in r:
         t = s.split()
         if len(t) > 0:
            if t[0].lower() == 'primvec':
               iv = i
            elif t[0].lower() == 'primcoord':
               ip = i
         i += 1
      if iv > 0:
         for i in range(3):
            s = r[iv + i]
            t = s.split()
            for j in range(3):
               mat['lv'][i][j] = float(t[j])
      if ip > 0:
         s = r[ip]
         t = s.split()
         mat['na'] = int(t[0])
         for i in range(mat['na']):
            s = r[ip + i + 1]
            t = s.split()
            if t[0].isdigit():
               mat['as'].append(int(t[0]))
            else:
               index = index_by_symbol(t[0])
               number = periodic_table[index]['number']
               mat['as'].append(number)
            mat['ap'].append([])
            for j in range(3):
               mat['ap'][i].append(float(t[j + 1]))
   mat['ns'] = len(mat_species(mat['na'], mat['as']))
   format = mat['fv']
   mat['fo'] = format
   fr, rmin, rmax = mat_range(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fr == format:
      for j in range(3):
         mat['lo'][j] = (rmin[j] + rmax[j]) / 2
         for i in range(3):
            mat['lo'][j] -= mat['lv'][i][j] / 2
   return ierr, mat

def xsf_write(file, mat):
   ierr = 0
   format = format_index2mat[1]
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fv != format or fp != format:
      ierr = 1
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('CRYSTAL\n')
      h.write('PRIMVEC\n')
      for i in range(3):
         s = ''
         for j in range(3):
            s += ' %11.6f' % lv[i][j]
         s += '\n'
         h.write(s)
      h.write('CONVVEC\n')
      for i in range(3):
         s = ''
         for j in range(3):
            s += ' %11.6f' % lv[i][j]
         s += '\n'
         h.write(s)
      h.write('PRIMCOORD\n')
      s = ' %4i %i\n' % (mat['na'], 1)
      h.write(s)
      for i in range(mat['na']):
         s = ' %4i' % mat['as'][i]
         for j in range(3):
            s += ' %11.6f' % ap[i][j]
         for j in range(3):
            s += ' %11.6f' % 0.0
         s += '\n'
         h.write(s)
      h.close()
   return ierr

def wien_write(file, mat):
   ierr = 0
   formatv = format_index2mat[2]
   if mat['fp'] != format_index2mat[3]:
      formatp = format_index2mat[2]
   else:
      formatp = format_index2mat[3]
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], formatv)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], formatp)
   if fv != formatv or fp != formatp:
      ierr = 1
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      if mat['fc'] == format_index2mat[0]:
         s = 'BOHR'
      else:
         s = 'ANG'
      if fp == format_index2mat[2]:
         s += ' C L\n'
      else:
         s += ' F L\n'
      h.write(s)
      s = '     %13.9f\n' % mat['lc']
      h.write(s)
      for i in range(3):
         s = '    '
         for j in range(3):
            s += ' %13.9f' % lv[i][j]
         s += '\n'
         h.write(s)
      for i in range(mat['na']):
         s = '  %2s' % periodic_table[index_by_number(mat['as'][i])]['symbol']
         for j in range(3):
            s += ' %13.9f' % ap[i][j]
         s += '\n'
         h.write(s)
      h.close()
   return ierr

def povray_bonds_st(mat):
   ierr = 0
   bonds = []
   format = format_index2mat[1]
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fv == format and fp == format:
      for i1 in range(mat['na']):
         bonds.append([])
         n1 = index_by_number(mat['as'][i1])
         v1 = periodic_table[n1]['valence']
         r1 = periodic_table[n1]['rcov']
         i = 0
         for i2 in range(mat['na']):
            n2 = index_by_number(mat['as'][i2])
            v2 = periodic_table[n2]['valence']
            r2 = periodic_table[n2]['rcov']
            for j1 in range(-1, 2):
               for j2 in range(-1, 2):
                  for j3 in range(-1, 2):
                     if (j3 != 0 or j2 != 0 or j1 != 0 or i2 != i1) and n2 != 0 and n1 != 0:
                        p = []
                        for j in range(3):
                           p.append(lv[2][j] * j3 + lv[1][j] * j2 + lv[0][j] * j1 + ap[i2][j] - ap[i1][j])
                        r = 0.0
                        for j in range(3):
                           r += math.pow(p[j], 2)
                        r = math.sqrt(r)
                        if r < minimumbondingdistance:
                           ierr = 1
                        if r < r1 + r2 + bondtolerance:
                           if strictvalence == 1 and i >= v1:
                              ierr = 1
                           bonds[i1].append([])
                           for j in range(3):
                              bonds[i1][i].append(ap[i1][j] + p[j] * r1 / (r1 + r2))
                           i += 1
   else:
      ierr = 1
   return ierr, bonds

def povray_bonds_ut(mat, umat, smin, smax, si):
   ierr = 0
   bonds = []
   format = format_index2mat[1]
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   ufv, ulv = mat_fv_lv(umat['fc'], umat['lc'], umat['fv'], umat['lv'], format)
   ufp, uap = mat_fp_ap(umat['na'], umat['fc'], umat['lc'], umat['fv'], umat['lv'], umat['fp'], umat['ap'], format)
   if fp == format and ufv == format and ufp == format:
      for i1 in range(mat['na']):
         bonds.append([])
         n1 = index_by_number(mat['as'][i1])
         v1 = periodic_table[n1]['valence']
         r1 = periodic_table[n1]['rcov']
         i = 0
         for i2 in range(umat['na']):
            n2 = index_by_number(umat['as'][i2])
            v2 = periodic_table[n2]['valence']
            r2 = periodic_table[n2]['rcov']
            for j1 in range(smin[0] - 1, smax[0] + 2):
               for j2 in range(smin[1] - 1, smax[1] + 2):
                  for j3 in range(smin[2] - 1, smax[2] + 2):
                     if (j3 != si[i1][3] or j2 != si[i1][2] or j1 != si[i1][1] or i2 != si[i1][0]) and n2 != 0 and n1 != 0:
                        p = []
                        for j in range(3):
                           p.append(ulv[2][j] * j3 + ulv[1][j] * j2 + ulv[0][j] * j1 + uap[i2][j] - ap[i1][j])
                        r = 0.0
                        for j in range(3):
                           r += math.pow(p[j], 2)
                        r = math.sqrt(r)
                        if r < minimumbondingdistance:
                           ierr = 1
                        if r < r1 + r2 + bondtolerance:
                           if strictvalence == 1 and i >= v1:
                              ierr = 1
                           bonds[i1].append([])
                           for j in range(3):
                              bonds[i1][i].append(ap[i1][j] + p[j] * r1 / (r1 + r2))
                           i += 1
   else:
      ierr = 1
   return ierr, bonds

def povray_write(file, mat, box, basis, bonds):
   cameralocation = [-0.1, -0.5, 0.9]
   cameralookat = [0.0, 0.0, 0.0]
   camerafactor = 3.0
   ierr = 0
   format = format_index2mat[1]
   fv, lv = mat_fv_lv(mat['fc'], mat['lc'], mat['fv'], mat['lv'], format)
   fo, lo = mat_fo_lo(mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fo'], mat['lo'], format)
   fp, ap = mat_fp_ap(mat['na'], mat['fc'], mat['lc'], mat['fv'], mat['lv'], mat['fp'], mat['ap'], format)
   if fo != format or fv != format or fp != format:
      ierr = 1
   lvcenter = []
   for j in range(3):
      lvcenter.append(lo[j])
   for i in range(3):
      for j in range(3):
         lvcenter[j] += lv[i][j] / 2
   if box != 0:
      lvcorner = []
      for i in range(8):
         lvcorner.append([])
         for j in range(3):
            lvcorner[i].append(lvcenter[j])
            for k in range(3):
               lvcorner[i][j] += lv[k][j] * (vertex[i][k] - 0.5)
   lvlength = []
   for i in range(3):
      lvlength.append(0.0)
      for j in range(3):
         lvlength[i] += math.pow(lv[i][j], 2)
      lvlength[i] = math.sqrt(lvlength[i])
   lvscale = 0.0
   for i in range(3):
      lvscale += lvlength[i]
   lvscale /= 3
   cameradistance = 0.0
   for i in range(3):
      cameradistance += math.pow(cameralocation[i] - cameralookat[i], 2)
   cameradistance = math.sqrt(cameradistance)
   camerascale = camerafactor * lvscale / cameradistance
   cameralocationlv = []
   for j in range(3):
      cameralocationlv.append(lvcenter[j] / camerascale + cameralocation[j])
   cameralookatlv = []
   for j in range(3):
      cameralookatlv.append(lvcenter[j] / camerascale + cameralookat[j])
   cs = mat_species(mat['na'], mat['as'])
   symbol = []
   ratom = []
   rbond = []
   color = []
   for i in range(mat['ns']):
      index = index_by_number(cs[i])
      symbol.append(periodic_table[index]['symbol'].lower())
      ratom.append(atomsize * periodic_table[index]['rvdw'])
      rbond.append(bondradius)
      color.append(periodic_table[index]['color'])
   atomicsymbol = []
   for i in range(mat['na']):
      index = index_by_number(mat['as'][i])
      atomicsymbol.append(periodic_table[index]['symbol'].lower())
   try:
      h = open(file, 'w')
   except:
      ierr = 1
   if ierr == 0:
      h.write('\n')
      s = '// name of matter: %s\n' % mat['nm']
      h.write(s)
      h.write('\n')
      s = '#declare camera_location = <%.2f, %.2f, %.2f>;\n' % tuple(cameralocationlv)
      h.write(s)
      s = '#declare camera_look_at = <%.2f, %.2f, %.2f>;\n' % tuple(cameralookatlv)
      h.write(s)
      s = '#declare camera_scale = %.2f;\n' % camerascale
      h.write(s)
      h.write('#declare light_location = camera_location - camera_look_at;\n')
      h.write('#declare light_scale = 1e6;\n')
      h.write('#declare color_light = rgb <2.00, 2.00, 2.00>;\n')
      h.write('#declare color_background = rgb <0.00, 0.00, 0.00>;\n')
      if box != 0:
         h.write('#declare radius_frame = 0.01;\n')
         h.write('#declare color_frame = rgb <0.75, 0.75, 0.75>;\n')
         h.write('#declare color_box = rgbf <1.00, 1.00, 1.00, 0.75>;\n')
      if basis != 0:
         axislength = lvscale / 3
         axisradius = axislength / 50
         s = '#declare length_axis = %.2f;\n' % axislength
         h.write(s)
         s = '#declare radius_axis = %.2f;\n' % axisradius
         h.write(s)
         h.write('#declare color_axis_x = rgb <1.00, 0.00, 0.00>;\n')
         h.write('#declare color_axis_y = rgb <0.00, 1.00, 0.00>;\n')
         h.write('#declare color_axis_z = rgb <0.00, 0.00, 1.00>;\n')
         h.write('#declare length_arrow = 0.2 * length_axis;\n')
         h.write('#declare radius_arrow = 2.0 * radius_axis;\n')
         h.write('#declare color_arrow_x = color_axis_x;\n')
         h.write('#declare color_arrow_y = color_axis_y;\n')
         h.write('#declare color_arrow_z = color_axis_z;\n')
      for i in range(mat['ns']):
         s = '#declare radius_atom_%s = %.2f;\n' % (symbol[i], ratom[i])
         h.write(s)
         if cs[i] != 0:
            s = '#declare radius_bond_%s = %.2f;\n' % (symbol[i], rbond[i])
            h.write(s)
         s = '#declare color_atom_%s = rgb <%.2f, %.2f, %.2f>;\n' % (tuple([symbol[i]]) + tuple(color[i]))
         h.write(s)
         if cs[i] != 0:
            s = '#declare color_bond_%s = rgb <%.2f, %.2f, %.2f>;\n' % (tuple([symbol[i]]) + tuple(color[i]))
            h.write(s)
      h.write('\n')
      h.write('camera { location camera_location sky <0.00, 0.00, 1.00> up <0.00, 0.00, 1.00> right <-1.33, 0.00, 0.00> direction <0.00, -1.00, 0.00> look_at camera_look_at scale camera_scale }\n')
      h.write('light_source { light_location color color_light shadowless scale light_scale }\n')
      h.write('background { color color_background }\n')
      h.write('\n')
      if box != 0:
         h.write('union {\n')
         for i in range(8):
            s = 'sphere { <%.9f, %.9f, %.9f>, radius_frame }\n' % tuple(lvcorner[i])
            h.write(s)
         for i in range(12):
            s = 'cylinder { <%.9f, %.9f, %.9f>, <%.9f, %.9f, %.9f>, radius_frame }\n' % (tuple(lvcorner[edge[i][0]]) + tuple(lvcorner[edge[i][1]]))
            h.write(s)
         h.write('texture { pigment { color color_frame } }\n')
         h.write('}\n')
         h.write('\n')
         h.write('union {\n')
         for i in range(12):
            s = 'triangle { <%.9f, %.9f, %.9f>, <%.9f, %.9f, %.9f>, <%.9f, %.9f, %.9f> }\n' % (tuple(lvcorner[face[i][0]]) + tuple(lvcorner[face[i][1]]) + tuple(lvcorner[face[i][2]]))
            h.write(s)
         h.write('texture { pigment { color color_box } }\n')
         h.write('}\n')
         h.write('\n')
      if basis != 0:
         h.write('union {\n')
         h.write('cylinder { <0.00, 0.00, 0.00>, <length_axis, 0.00, 0.00>, radius_axis texture { pigment { color color_axis_x } } }\n')
         h.write('cylinder { <0.00, 0.00, 0.00>, <0.00, length_axis, 0.00>, radius_axis texture { pigment { color color_axis_y } } }\n')
         h.write('cylinder { <0.00, 0.00, 0.00>, <0.00, 0.00, length_axis>, radius_axis texture { pigment { color color_axis_z } } }\n')
         h.write('cone { <length_axis, 0.00, 0.00>, radius_arrow <length_axis + length_arrow, 0.00, 0.00>, 0.00 texture { pigment { color color_arrow_x } } }\n')
         h.write('cone { <0.00, length_axis, 0.00>, radius_arrow <0.00, length_axis + length_arrow, 0.00>, 0.00 texture { pigment { color color_arrow_y } } }\n')
         h.write('cone { <0.00, 0.00, length_axis>, radius_arrow <0.00, 0.00, length_axis + length_arrow>, 0.00 texture { pigment { color color_arrow_z } } }\n')
         h.write('}\n')
         h.write('\n')
      h.write('union {\n')
      for i in range(mat['na']):
         s = 'sphere { <%.9f, %.9f, %.9f>, radius_atom_%s texture { pigment { color color_atom_%s } } }\n' % (tuple(ap[i]) + tuple([atomicsymbol[i]]) + tuple([atomicsymbol[i]]))
         h.write(s)
      h.write('}\n')
      h.write('\n')
      h.write('union {\n')
      for i in range(mat['na']):
         for j in range(len(bonds[i])):
            s = 'cylinder { <%.9f, %.9f, %.9f>, <%.9f, %.9f, %.9f>, radius_bond_%s texture { pigment { color color_bond_%s } } }\n' % (tuple(ap[i]) + tuple(bonds[i][j]) + tuple([atomicsymbol[i]]) + tuple([atomicsymbol[i]]))
            h.write(s)
      h.write('}\n')
      h.write('\n')
      h.close()
   return ierr

if __name__ == "__main__":
   import sys
   sys.exit(main())

