"""
.. module:: Configuratinos
    :synopsis: Framework for constructing charge, dipole configurations.
.. moduleauthor:: D. Wang <dwang5@zoho.com>
"""
import numpy as np
from supercell import Supercell
from netCDF4 import Dataset
import time
from cmath import exp
from math import atan
[docs]class Charge_config(Supercell):
    """
    Charge_config inherits from the 'Supercell' class.
    Args:
        n1,n2,n3 are the number of repeated unitcells along the three directions of the 'lattice'.
        lattice specifies the Bravais lattice of a **unit cell**.
    """
    def __init__(self, n1, n2, nz, lattice):
        Supercell.__init__(self, n1, n2, nz, lattice)
        self.alloy_calculated = False
        self.signs = np.zeros(self.nsites)
[docs]    def write_alloy_matrix(self, fn):
        """
        Write the out put to a 'netcdf' file named 'fn'.
        """
        if self.alloy_calculated == False:
            print("Need to generate the alloy first ...")
            exit()
        ccpm = Dataset(fn, "w", format="NETCDF4")
        ccpm.createDimension("ia", self.nsites)
        matrix = ccpm.createVariable('matrix', np.float64, ('ia'))
        ccpm.description = 'Alloy matrix'
        ccpm.history = 'Created at ' + time.ctime(time.time())
        matrix[:] = self.signs
        ccpm.close() 
[docs]    def generate_high_symmetry(self, p=1, k=(0, 0, 0)):
        """
        The distribution of charge is set according to this k value and the
        charge magnitude.
        :param p: represents the magnitude of charge.
        :param k: k = (kx,ky,kz): represents the high symmetry points in the reciprocal space.
        """
        pi = 4.0 * atan(1.0)
        for l in range(self.nsites):
            ixa = self.ixa[l]
            iya = self.iya[l]
            iza = self.iza[l]
            # This is a little redundant, but may be useful in the future.
            dum = exp(1j * pi * (k[0] * ixa + k[1] * iya + k[2] * iza))
            self.signs[l] = p * dum.real
        self.alloy_calculated = True  
[docs]class Dipole_config(Supercell):
    """
    Similar to 'Charge config'.
    """
    def __init__(self, n1, n2, nz, lattice):
        Supercell.__init__(self, n1, n2, nz, lattice)
        self.alloy_calculated = False
        self.signs = np.zeros((self.nsites, 3))
    def write_alloy_matrix(self, fn):
        if self.alloy_calculated == False:
            print("Need to generate the alloy first ...")
            exit()
        dipm = Dataset(fn, "w", format="NETCDF4")
        direction = dipm.createDimension("direction", 3)
        ia = dipm.createDimension("ia", self.nsites)
        directions = dipm.createVariable("direction", np.int32, ("direction"))
        ias = dipm.createVariable("ia", np.int32, ("ia"))
        # The actual 2-d varable.
        matrix = dipm.createVariable('matrix', np.float64, ('ia', 'direction'))
        dipm.description = 'Alloy matrix'
        dipm.history = 'Created at ' + time.ctime(time.time())
        matrix[:, :] = self.signs
        dipm.close()
[docs]    def generate_high_symmetry(self, p=(1, 1, 1), k_px=(0, 0, 0), k_py=(0, 0, 0), k_pz=(0, 0, 0)):
        """
        :param p: p=(px,py,pz) represents the magnitude of dpoles.
        :param k_px: k_px = (kx,ky,kz) represents a high symmetry points in the reciprocal space and specifies how the value of px on each site.
        :param k_py: Similar to k_px.
        :param k_pz: Similar to k_px.
        """
        pi = 4.0 * atan(1.0)
        px = p[0]
        py = p[1]
        pz = p[2]
        for l in range(self.nsites):
            ixa = self.ixa[l]
            iya = self.iya[l]
            iza = self.iza[l]
            # This is a little redundant, but may be useful in the future.
            dum = exp(1j * pi * (k_px[0] * ixa + k_px[1] * iya + k_px[2] * iza))
            self.signs[l, 0] = px * dum.real
            dum = exp(1j * pi * (k_py[0] * ixa + k_py[1] * iya + k_py[2] * iza))
            self.signs[l, 1] = py * dum.real
            dum = exp(1j * pi * (k_pz[0] * ixa + k_pz[1] * iya + k_pz[2] * iza))
            self.signs[l, 2] = pz * dum.real
        self.alloy_calculated = True