Ejemplo n.º 1
0
    def elPolarization(self, berryPhase, calcValues, ELEC_BY_VOL_CONST):
        '''
        Calculate electronic component of polarization

        Input: berryPhase[direction 1, 2, 3][spin]

        Calculation:

        Pel_x = electron charge / unit volume (m) * \
          berry phase mean value/2pi * lattice_matrices (diagonal x);
        '''
        # [OLEG]: check which lattice vectors to use br1 or br2
        nspins = numpy.shape(berryPhase)[1]
        elP = numpy.zeros((nspins, 3))
        for spinIndex in range(0, nspins):
            for coordIndex in range(0,
                                    3):  # loop over 3 lattice vector direct.
                latVec = calcValues['Real primitive lat vectors in bohr'][
                    coordIndex]
                normLatVec = numpy.linalg.norm(latVec)  # length of lat. vector
                elP[spinIndex,coordIndex] = \
                    (berryPhase[coordIndex,spinIndex]/(2*numpy.pi)) * \
                    ELEC_BY_VOL_CONST * \
                    bohrToMeters(normLatVec)
            print("Electronic polarization (C/m2)     " +\
                "sp(%1i) " % (spinIndex+1), \
            "[% e, % e, % e]" % tuple(elP[spinIndex,:]))
        print("=" * 87)
        return elP
Ejemplo n.º 2
0
    def elPolarization(self, berryPhase, calcValues, ELEC_BY_VOL_CONST):
        '''
        Calculate electronic component of polarization

        Input: berryPhase[direction 1, 2, 3][spin]

        Calculation:

        Pel_x = electron charge / unit volume (m) * \
          berry phase mean value/2pi * lattice_matrices (diagonal x);
        '''
        latticeConstants = calcValues['Lattice Constants in bohr']
        latticeMatrix_x = calcValues['Lattice Matrix in bohr'][0]
        latticeMatrix_y = calcValues['Lattice Matrix in bohr'][1]
        latticeMatrix_z = calcValues['Lattice Matrix in bohr'][2]
        # return the absolute value of the vector sqrt(x^2 + y^2 + z^2)
        absVector = lambda vec: math.sqrt(sum([i**2 for i in vec]))
        # length of lattice vectors
        lattice_x = absVector(latticeMatrix_x)
        lattice_y = absVector(latticeMatrix_y)
        lattice_z = absVector(latticeMatrix_z)
        # Electronic Polarization [OLEG]: check which lattice constants to use
        nspins = numpy.shape(berryPhase)[1]
        elP = numpy.zeros((nspins, 3))
        for spinIndex in range(0, nspins):
            for coordIndex in range(0, 3):
                elP[spinIndex,coordIndex] = \
                    (berryPhase[coordIndex,spinIndex]/(2*numpy.pi)) * \
                    ELEC_BY_VOL_CONST * \
                    bohrToMeters(latticeConstants[coordIndex])
            print "Electronic polarization (C/m2)     " +\
                "sp(%1i) " % (spinIndex+1), \
            "[% e, % e, % e]" % tuple(elP[spinIndex,:])
        print "=" * 87
        return elP
Ejemplo n.º 3
0
    def elPolarization(self, berryPhase, calcValues, ELEC_BY_VOL_CONST):
        '''
        Calculate electronic component of polarization

        Input: berryPhase[direction 1, 2, 3][spin]

        Calculation:

        Pel_x = electron charge / unit volume (m) * \
          berry phase mean value/2pi * lattice_matrices (diagonal x);
        '''
        latticeConstants = calcValues['Lattice Constants in bohr']
        latticeMatrix_x = calcValues['Lattice Matrix in bohr'][0]
        latticeMatrix_y = calcValues['Lattice Matrix in bohr'][1]
        latticeMatrix_z = calcValues['Lattice Matrix in bohr'][2]
        # return the absolute value of the vector sqrt(x^2 + y^2 + z^2)
        absVector = lambda vec: math.sqrt(sum([i**2 for i in vec]))
        # length of lattice vectors
        lattice_x = absVector(latticeMatrix_x)
        lattice_y = absVector(latticeMatrix_y)
        lattice_z = absVector(latticeMatrix_z)
	      # Electronic Polarization [OLEG]: check which lattice constants to use
        nspins = numpy.shape(berryPhase)[1]
        elP = numpy.zeros((nspins,3))
        for spinIndex in range(0,nspins):
            for coordIndex in range(0,3):
                elP[spinIndex,coordIndex] = \
                    (berryPhase[coordIndex,spinIndex]/(2*numpy.pi)) * \
                    ELEC_BY_VOL_CONST * \
                    bohrToMeters(latticeConstants[coordIndex]);
            print "Electronic polarization (C/m2)     " +\
                "sp(%1i) " % (spinIndex+1), \
            "[% e, % e, % e]" % tuple(elP[spinIndex,:]);
        print "="*87
        return elP; # END elPolarization
Ejemplo n.º 4
0
    def determineIonPolarization(self, fnWrpMethod, args):
        '''
        INPUT: fnWrpMethod - function that determines the method for
                             wrapping the phase
               args - contains logical variables regarding the
                      calculation setup
                      args['so'] - spin-orbit coupling
                      args['sp'] - spin-polarized calculation
                      args['orb'] - additional orbital potential (LDA+U)

        Calculation:

        Pion_x = electron charge / unit volume (m) * lattice_x * (
        
          sum of (
            atom valence charge * position(x)
            )
          )

          where atom valence charge = ( core value - spin val 1 - spin val 2 )
        '''
        print "\n", "CALCULATION OF IONIC POLARIZATION"
        ionP = []
        calcValues = self.calculationValues()
        ELEC_BY_VOL_CONST = self.ELEC_BY_VOL_CONST
        latticeConstants = calcValues['Lattice Constants in bohr']
        atomListing = calcValues['Atom Listing']
        #produce a tuple pair which includes the valence electrons and
        #the coordinates for each element
        calcIonValues = []  # (coordinates(x,y,z), valence value)

        #TODO: include good exception handling for this stage
        #construct the calcIonValues for the calculation
        if args['sp'] and not args['so']:
            nspins = 2
        else:
            nspins = 1
        for atom in atomListing:
            for i in range(atom['MULT']):
                theElementName = atom['Element Name']
                if calcValues['Element Listing'].has_key(theElementName):
                    theElement = calcValues['Element Listing'][theElementName]
                    if nspins == 2:
                        theValence = []
                        for spin in [1, 2]:
                            theValence.append( \
                                atom['Znucl']/2 - theElement['Core Value']/2 \
                            )
                    else:
                        theValence = atom['Znucl'] - theElement['Core Value']
                    xCoordinate = atom['X-Coord'][i]
                    yCoordinate = atom['Y-Coord'][i]
                    zCoordinate = atom['Z-Coord'][i]

                    #produce tuple from coordinates
                    coordinates = (xCoordinate, yCoordinate, zCoordinate)
                    calcIonValues.append(
                        (theElementName, coordinates, theValence))
                else:
                    print DEFAULT_PREFIX + 'ERROR: Missing element in element list'
                    print DEFAULT_PREFIX + theElementName
                    print DEFAULT_PREFIX + calcValues['Element List']
                    print DEFAULT_PREFIX + 'Exiting....'
                    sys.exit(1)
        self._calcIonValues = calcIonValues

        #### CALCULATION ####
        xPolarIon, yPolarIon, zPolarIon = (0., 0., 0.)
        print "=" * 87
        print "Elem.|  Fractional coord.  |  spin | Zion |", \
            "   dir(1)   ", \
            "|   ", "dir(2)   ", "|   ", "dir(3)"
        print "-" * 87
        print " "*41, "+"+"-"*12, "Ionic phase (rad)", \
            "-"*12+"+"
        totIonPhase = numpy.zeros((nspins, 3))
        for element, iCoord, iValence in calcIonValues:
            spinIndex = -1
            if isinstance(iValence, collections.Iterable):
                pass
            else:
                iValence = [
                    iValence,
                ]
            for spinValence in iValence:
                spinIndex += 1
                ionPhase = numpy.zeros((nspins, 3))
                coordIndex = -1
                for fcoord in iCoord:
                    coordIndex += 1
                    # fractional coordinates used
                    psi = fcoord * spinValence * 2 * numpy.pi
                    ionPhase[spinIndex, coordIndex] = psi
                if spinIndex == 0:
                    print "%2s " % element, \
                        "(%6.4f, %6.4f, %6.4f) " % iCoord, \
                        "sp(%1i)" % (spinIndex+1), \
                        "%5.2f" % spinValence, \
                        "[% e, % e, % e]" % tuple(ionPhase[spinIndex,:])
                else:
                    print " "*29, \
                        "sp(%1i)" % (spinIndex+1), \
                        "%5.2f" % spinValence, \
                        "[% e, % e, % e]" % tuple(ionPhase[spinIndex,:])
                totIonPhase[:, :] += ionPhase
        print "-" * 87
        for spinIndex in range(0, nspins):
            print "Total ionic phase (rad)", " "*5, \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(totIonPhase[spinIndex,:])

        # warap phases
        totIonPhase = fnWrpMethod(totIonPhase)

        for spinIndex in range(0, nspins):
            print "Total ionic phase wrap. (rad)", \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(totIonPhase[spinIndex,:])

        #IONIC Polarization
        ionPol = numpy.zeros((nspins, 3))
        for spinIndex in range(0, nspins):
            for coordIndex in range(0, 3):
                psi = totIonPhase[spinIndex, coordIndex]
                a = latticeConstants[coordIndex]
                ionPol[spinIndex,coordIndex] = \
                    (psi/(2*numpy.pi)) * ELEC_BY_VOL_CONST * \
                    bohrToMeters(a)
            print "Ionic polarization (C/m2)    ", \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(ionPol[spinIndex,:])
        print "=" * 87

        return ionPol  # END determineIonPolarization
Ejemplo n.º 5
0
    def __init__(self, **args):

        # spin polarization: yes/no
        spCalc = args['sp']

        ############################
        ######### PARSING ##########
        ############################

        ###Rest of the Files###
        #parse all the things!
        #### *.struct file parser
        parser_struct_handle = open(args['file_struct'], 'r').readlines()
        parser_struct_handle = b_PyParse.MainStructParser(parser_struct_handle)
        parser_struct_handle.parse()

        #### *.scf file parser
        parser_scf_handle = open(args['file_scf'], 'r').readlines()
        parser_scf_handle = b_PyParse.MainSCFParser(parser_scf_handle)
        parser_scf_handle.parse()

        #### *.outputd parser
        parser_outputd_handle = open(args['file_outputd'], 'r').readlines()
        parser_outputd_handle = b_PyParse.MainOutputDParser(
            parser_outputd_handle)
        parser_outputd_handle.parse()

        #### *.outputst parser
        parser_outputst_handle = open(args['file_outputst'], 'r').readlines()
        parser_outputst_handle = b_PyParse.MainOutputstParser(
            parser_outputst_handle)
        parser_outputst_handle.parse()

        #####################################
        ############ END Parsing ############
        #####################################

        #############################
        ###### Getting Values #######
        #############################
        self._calculationValues = orderedDict()

        #### *.struct handle
        # - determine name of atoms
        # - determine MULT for each atom
        self._calculationValues['Atom Listing'] = \
            parser_struct_handle['Atom Listing']

        #### *.scf handle
        # - Cell Volume
        self._calculationValues['Cell Volume in bohr^3'] = \
            parser_scf_handle['Cell Volume']
        self._calculationValues['Cell Volume in m^3'] = \
            bohrToMeters(self._calculationValues['Cell Volume in bohr^3'],3)

        #### *.outputd handle
        # - BR2_DIR matrix (v_x, v_y, v_z)
        # - number of atoms in cell
        # - Lattice Constants (x,y,z)
        laticematrix = parser_outputd_handle['BR2_DIR Matrix']
        latticematrixa1 = laticematrix[0]
        self._calculationValues['Lattice Matrix a1 in bohr'] = \
             latticematrixa1
        latticematrixa2 = laticematrix[1]
        self._calculationValues['Lattice Matrix a2 in bohr'] = \
             latticematrixa2
        latticematrixa3 = laticematrix[2]
        self._calculationValues['Lattice Matrix a3 in bohr'] = \
             latticematrixa3
        self._calculationValues['Lattice Matrix in bohr'] = \
            parser_outputd_handle['BR2_DIR Matrix']
        self._calculationValues['Lattice Matrix in m'] = \
            [[ bohrToMeters(i) for i in j ] for j in \
            self._calculationValues['Lattice Matrix in bohr']]
        self._calculationValues['Number of Atoms in Unit Cell'] = \
            parser_outputd_handle['Number of Atoms in Unit Cell']
        self._calculationValues['Lattice Constants in bohr'] = \
            parser_outputd_handle['Lattice Constants']
        self._calculationValues['Lattice Constants in m'] = \
            [ bohrToMeters(i) for i in \
            self._calculationValues['Lattice Constants in bohr']]

        #### *.outputst handle
        # for each element:
        # - Core Value
        # - Spin Value 1
        # - Spin Value 2
        self._calculationValues['Element Listing'] = \
            parser_outputst_handle['Element List']

        ####

        ########################
        # get electronic phase #
        ########################
        # get raw list [k-points, phase]
        phaseDirSpinPathRaw = args['phases']
        # wrap phases in the range [-pi ... +pi]
        phaseDirSpinPathWrp11 = self.wrpPhase(phaseDirSpinPathRaw, \
            self.wrp11)
        # print nice
        print "\n","Initial Berry phases and their", \
            "wrapped values in the range [-pi ... +pi]"
        print "=" * 87
        print " "*30, "| init k-point", "| phase raw (rad)", \
            "| phase wrap. (rad)"
        icoord = -1
        for coord in phaseDirSpinPathRaw:
            icoord += 1
            print "-" * 87
            print "direction(%u)" % int(icoord + 1)
            ispin = -1
            for spin in coord:
                ispin += 1
                print " " * 12, "spin(%u)" % int(ispin + 1)
                ipath = -1
                for path in spin:
                    ipath += 1
                    # perform wraping using the method privided in input
                    kpt = phaseDirSpinPathRaw[icoord][ispin][ipath][0]
                    ph = phaseDirSpinPathRaw[icoord][ispin][ipath][1]
                    phwrp = phaseDirSpinPathWrp11[icoord][ispin][ipath][1]
                    print " "*20, "path(%4d)       %4d        % e        % e" \
                        % (ipath+1, kpt, ph, phwrp)
        print "=" * 87
        print "\n", "CALCULATION OF ELECTRONIC POLARIZATION"
        print "=" * 87
        print "Value", " "*25, "|  spin  ", "|   ", "dir(1)   ", \
            "|   ", "dir(2)   ", "|   ", "dir(3)"
        print "-" * 87
        # find path-average phase
        phaseDirSpinWrp11 = self.pathAvrgPhase(phaseDirSpinPathWrp11)
        # wrap the average phase again as it can go out of bounds [-pi..+pi]
        phaseDirSpinWrp11 = self.wrp11(phaseDirSpinWrp11)
        nspins = numpy.shape(phaseDirSpinWrp11)[1]
        for spinIndex in range(0, nspins):
            print "Berry phase (rad) [-pi ... +pi]    sp(%1i)" \
                % (spinIndex+1), \
                " [% e, % e, % e]" % tuple(phaseDirSpinWrp11[:,spinIndex])
        if not spCalc and not args[
                'so']:  # in case of non-SP or non-SO calculation...
            phaseDirSpinWrp11 = 2 * phaseDirSpinWrp11  # account for the spin degeneracy
            nspins = numpy.shape(phaseDirSpinWrp11)[1]
            if nspins != 1:  # double check
                print "Inconsistency detected in the number of spins"
                print "Is it spin-polarized calculation? spCalc =", spCalc
                print "Number of spins in the electronic phase array", \
                    nspins
                print "Expected 1 spin"
                print "Decision is taken to EXIT"
                sys.exit(2)
            print "Berry phase (rad)                  up+dn  "+ \
                "[% e, % e, % e]" % tuple(phaseDirSpinWrp11)
            # wrap phases again [-pi ... +pi]
            phaseDirSpinWrp11 = self.wrp11(phaseDirSpinWrp11)
            print "Berry phase (rad) [-pi ... +pi] " +\
                "   up+dn  [% e, % e, % e]" \
                % tuple(phaseDirSpinWrp11)
        #electron charge / cell volume
        self.ELEC_BY_VOL_CONST = ELECTRON_CHARGE / \
            bohrToMeters(self._calculationValues['Cell Volume in bohr^3'], \
            dimension = 3.)
        # electronic polarization (C/m2)
        elP = self.elPolarization(phaseDirSpinWrp11,self._calculationValues, \
            self.ELEC_BY_VOL_CONST)
        # ionic polarization (C/m2)
        ionP = self.determineIonPolarization(self.wrp11, args)
        # Total polarization (C/m2) will be returned
        # when calling mainCalculation()
        self._totalPolarizationVal = self.totalPolarization(elP, ionP)
Ejemplo n.º 6
0
    def determineIonPolarization(self, fnWrpMethod, args):
        '''
        INPUT: fnWrpMethod - function that determines the method for
                             wrapping the phase
               args - contains logical variables regarding the
                      calculation setup
                      args['so'] - spin-orbit coupling
                      args['sp'] - spin-polarized calculation
                      args['orb'] - additional orbital potential (LDA+U)

        Calculation:

        Pion_x = electron charge / unit volume (m) * lattice_x * (
        
          sum of (
            atom valence charge * position(x)
            )
          )

          where atom valence charge = ( core value - spin val 1 - spin val 2 )
        '''
        print("\n\nCALCULATION OF IONIC POLARIZATION",\
            "(conventional lattice coordinates)")
        ionP = []
        calcValues = self.calculationValues()
        ELEC_BY_VOL_CONST = self.ELEC_BY_VOL_CONST
        latticeConstants = calcValues['Lattice Constants in bohr']
        atomListing = calcValues['Atom Listing']
        #produce a tuple pair which includes the valence electrons and
        #the coordinates for each element
        calcIonValues = []  # (coordinates(x,y,z), valence value)

        #TODO: include good exception handling for this stage
        #construct the calcIonValues for the calculation
        if args['sp'] and not args['so']:
            nspins = 2
        else:
            nspins = 1
        iatom = -1  # atom index
        Zcore = self.calcVal['Atom core charges']  # non-equiv. atoms
        for atom in atomListing:  # loop over non-equivalent atoms
            iatom = iatom + 1
            theElementName = atom['Element Name']
            for i in range(atom['MULT']):
                if nspins == 2:
                    theValence = []
                    for spin in [1, 2]:
                        theValence.append( \
                            atom['Znucl']/2 - Zcore[iatom]/2 \
                        )
                else:
                    theValence = atom['Znucl'] - Zcore[iatom]
                xCoordinate = atom['X-Coord'][i]
                yCoordinate = atom['Y-Coord'][i]
                zCoordinate = atom['Z-Coord'][i]
                #produce tuple from coordinates
                coordinates = (xCoordinate, yCoordinate, zCoordinate)
                calcIonValues.append((theElementName, coordinates, theValence))
        self._calcIonValues = calcIonValues

        #### CALCULATION ####
        xPolarIon, yPolarIon, zPolarIon = (0., 0., 0.)
        print("=" * 87)
        print("Elem.|  Fractional coord.  |  spin | Zion |", \
            "   dir(1)   ", \
            "|   ", "dir(2)   ", "|   ", "dir(3)")
        print("-" * 87)
        print(" "*41, "+"+"-"*12, "Ionic phase (rad)", \
            "-"*12+"+")
        totIonPhase = numpy.zeros((nspins, 3))
        for element, iCoord, iValence in calcIonValues:
            spinIndex = -1
            if isinstance(iValence, collections.Iterable):
                pass
            else:
                iValence = [
                    iValence,
                ]
            for spinValence in iValence:
                spinIndex += 1
                ionPhase = numpy.zeros((nspins, 3))
                coordIndex = -1
                for fcoord in iCoord:
                    coordIndex += 1
                    # fractional coordinates used
                    psi = fcoord * spinValence * 2 * numpy.pi
                    ionPhase[spinIndex, coordIndex] = psi
                if spinIndex == 0:
                    print("%2s " % element, \
                        "(%6.4f, %6.4f, %6.4f) " % iCoord, \
                        "sp(%1i)" % (spinIndex+1), \
                        "%5.2f" % spinValence, \
                        "[% e, % e, % e]" % tuple(ionPhase[spinIndex,:]))
                else:
                    print(" "*29, \
                        "sp(%1i)" % (spinIndex+1), \
                        "%5.2f" % spinValence, \
                        "[% e, % e, % e]" % tuple(ionPhase[spinIndex,:]))
                totIonPhase[:, :] += ionPhase
        print("-" * 87)
        for spinIndex in range(0, nspins):
            print("Total ionic phase (rad)", " "*5, \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(totIonPhase[spinIndex,:]))

        # warap phases
        totIonPhase = fnWrpMethod(totIonPhase)

        for spinIndex in range(0, nspins):
            print("Total ionic phase wrap. (rad)", \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(totIonPhase[spinIndex,:]))

        #IONIC Polarization
        ionPol = numpy.zeros((nspins, 3))
        for spinIndex in range(0, nspins):
            for coordIndex in range(0,
                                    3):  # loop over 3 lattice vector direct.
                psi = totIonPhase[spinIndex, coordIndex]
                # WIEN2k always uses conventional latt. vec. for ionic positions
                latVec = calcValues['Real conventional lat vectors in bohr'][
                    coordIndex]
                normLatVec = numpy.linalg.norm(latVec)  # length of lat. vector
                ionPol[spinIndex,coordIndex] = \
                    (psi/(2*numpy.pi)) * ELEC_BY_VOL_CONST * \
                    bohrToMeters(normLatVec)
            print("Ionic polarization (C/m2)    ", \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(ionPol[spinIndex,:]))
        print("=" * 87)

        return ionPol  # END determineIonPolarization
Ejemplo n.º 7
0
    def __init__(self, **args):

        # spin polarization: yes/no
        spCalc = args['sp']

        ############################
        ######### PARSING ##########
        ############################

        ###Rest of the Files###
        #parse all the things!
        #### *.struct file parser
        parser_struct_handle = open(args['file_struct'], 'r').readlines()
        parser_struct_handle = b_PyParse.MainStructParser(parser_struct_handle)
        parser_struct_handle.parse()

        #### *.inc parser
        parser_inc_handle = open(args['file_inc'], 'r').readlines()
        parser_inc_handle = b_PyParse.MainIncParser(parser_inc_handle)
        parser_inc_handle.parse()

        #####################################
        ############ END Parsing ############
        #####################################

        #############################
        ###### Getting Values #######
        #############################
        self.calcVal = orderedDict()

        #### *.struct handle
        # - name of atoms
        # - MULT for each atom
        # - coordinates
        # - nuclear charge
        self.calcVal['Atom Listing'] = \
            parser_struct_handle['Atom Listing']
        # - lattice type (P,F,B,CXY,CYZ,CXZ,R,H)
        self.calcVal['lattice type'] = \
            parser_struct_handle['lattice type']
        # - lattice orthogonal (T/F)
        self.calcVal['lattice ortho'] = \
            parser_struct_handle['lattice ortho']
        # - Cell Volume
        self.calcVal['Cell Volume in bohr^3'] = \
            parser_struct_handle['cell volume']
        # - Lattice Constants (a,b,c)
        self.calcVal['Lattice Constants in bohr'] = \
            parser_struct_handle['lattice constants']
        # - lattice vectors BR1_DIR matrix (v_x, v_y, v_z)
        self.calcVal['Real conventional lat vectors in bohr'] = \
            parser_struct_handle['real space conventional lattice vectors']
        # - lattice vectors BR2_DIR matrix (v_x, v_y, v_z)
        self.calcVal['Real primitive lat vectors in bohr'] = \
            parser_struct_handle['real space primitive lattice vectors']

        ### *.inc handle
        # - core charge for each non-eqivalent atom
        self.calcVal['Atom core charges'] = \
            parser_inc_handle['core charges']

        # check consistency of case.struct and case.inc files
        if len(self.calcVal['Atom core charges']) != \
            len(self.calcVal['Atom Listing']):
            print("Number of non-equivalent atoms in case.struct:", \
                len(self.calcVal['Atom Listing']))
            print("Number of non-equivalent atoms in case.inc:", \
                len(self.calcVal['Atom core charges']))
            raise Exception("Inconsistent number of non-equivalent atoms")

        # list of pi-wrapping functions that will be applied to wrap the phase
        wrpFnList = [self.wrp02, self.wrp11]
        for wrpFn in wrpFnList:  # iterate over various wrapping functions
            if wrpFn == self.wrp11:
                print("\n\n~~~~~~~~~~~~~~~~~~~~ " +\
                    "phases are wrapped in the range [-pi .. +pi]" +\
                    " ~~~~~~~~~~~~~~~~~~~~~~")
            elif wrpFn == self.wrp02:
                print("\n\n~~~~~~~~~~~~~~~~~~~~ " +\
                    "phases are wrapped in the range [0 .. +2pi] " +\
                    " ~~~~~~~~~~~~~~~~~~~~~")
            ########################
            # get electronic phase #
            ########################
            # get raw list [k-points, phase]
            phaseDirSpinPathRaw = args['phases']
            # wrap phases in the range [-pi ... +pi]
            phaseDirSpinPathWrp = self.wrpPhase(phaseDirSpinPathRaw, \
                wrpFn)
            # print nice
            print("\n","Initial Berry phases and their", \
                "wrapped values")
            print("=" * 87)
            print(" "*30, "| init k-point", "| phase raw (rad)", \
                "| phase wrap. (rad)")
            icoord = -1
            for coord in phaseDirSpinPathRaw:
                icoord += 1
                print("-" * 87)
                print("direction(%u)" % int(icoord + 1))
                ispin = -1
                for spin in coord:
                    ispin += 1
                    print(" " * 12, "spin(%u)" % int(ispin + 1))
                    ipath = -1
                    for path in spin:
                        ipath += 1
                        # perform wraping using the method privided in input
                        kpt = phaseDirSpinPathRaw[icoord][ispin][ipath][0]
                        ph = phaseDirSpinPathRaw[icoord][ispin][ipath][1]
                        phwrp = phaseDirSpinPathWrp[icoord][ispin][ipath][1]
                        print(" "*20, "path(%4d)       %4d        % e        % e" \
                            % (ipath+1, kpt, ph, phwrp))
            print("=" * 87)
            print("\n\nCALCULATION OF ELECTRONIC POLARIZATION",\
                "(primitive lattice coordinates)")
            print("=" * 87)
            print("Value", " "*25, "|  spin  ", "|   ", "dir(1)   ", \
                "|   ", "dir(2)   ", "|   ", "dir(3)")
            print("-" * 87)
            # find path-average phase
            phaseDirSpinWrp = self.pathAvrgPhase(phaseDirSpinPathWrp)
            # wrap the average phase again as it can go out of bounds [-pi..+pi]
            phaseDirSpinWrp = wrpFn(phaseDirSpinWrp)
            nspins = numpy.shape(phaseDirSpinWrp)[1]
            for spinIndex in range(0, nspins):
                print("Berry phase wrapped (rad)          sp(%1i)" \
                    % (spinIndex+1), \
                    " [% e, % e, % e]" % tuple(phaseDirSpinWrp[:,spinIndex]))
            if not spCalc and not args[
                    'so']:  # in case of non-SP or non-SO calculation...
                phaseDirSpinWrp = 2 * phaseDirSpinWrp  # account for the spin degeneracy
                nspins = numpy.shape(phaseDirSpinWrp)[1]
                if nspins != 1:  # double check
                    print("Inconsistency detected in the number of spins")
                    print("Is it spin-polarized calculation? spCalc =", spCalc)
                    print("Number of spins in the electronic phase array", \
                        nspins)
                    print("Expected 1 spin")
                    print("Decision is taken to EXIT")
                    sys.exit(2)
                print("Berry phase (rad)                  up+dn  "+ \
                    "[% e, % e, % e]" % tuple(phaseDirSpinWrp))
                # wrap phases again [-pi ... +pi]
                phaseDirSpinWrp = wrpFn(phaseDirSpinWrp)
                print("Berry phase wrapped (rad)" +\
                    "          up+dn  [% e, % e, % e]" \
                    % tuple(phaseDirSpinWrp))
            #electron charge / cell volume
            self.ELEC_BY_VOL_CONST = ELECTRON_CHARGE / \
                bohrToMeters(self.calcVal['Cell Volume in bohr^3'], \
                dimension = 3.)
            # electronic polarization (C/m2)
            elP = self.elPolarization(phaseDirSpinWrp,self.calcVal, \
                self.ELEC_BY_VOL_CONST)
            # convert elP from primitive basis to Cart. coordinates
            # WIEN2k always uses primitive latt. vec. in constructing Brillouin zone
            print("\nThe electronic polarization vector is presented in",\
                "this coord. system:")
            latVec = numpy.zeros((3, 3))
            for i in range(3):  # gather lattice vectors into a (3x3) array
                latVec[i, :] = self.calcVal[
                    'Real primitive lat vectors in bohr'][i]
                print(" "*4, "dir(%1i) =" % (i+1), \
                    "[% e, % e, % e] bohr" % tuple(latVec[i,:]))
            print("and will be transformed into Cartesian coordinates.")
            for i in range(elP.shape[0]):  # loop over spin channels
                elP[i, :] = vec2cart(elP[i, :], latVec)  # prim -> Cartesian

            #############################
            # ionic polarization (C/m2) #
            #############################
            ionP = self.determineIonPolarization(wrpFn, args)
            # convert ionP from conventional to Cart. coordinates
            # WIEN2k always uses conventional latt. vec. for ionic positions
            print("\nThe ionic positions and associated polarization vector is",\
                "presented in this coord. system:")
            latVec = numpy.zeros((3, 3))
            for i in range(3):  # gather lattice vectors into a (3x3) array
                latVec[i, :] = self.calcVal[
                    'Real conventional lat vectors in bohr'][i]
                print(" "*4, "dir(%1i) =" % (i+1), \
                    "[% e, % e, % e] bohr" % tuple(latVec[i,:]))
            for i in range(ionP.shape[0]):  # loop over spin channels
                ionP[i, :] = vec2cart(ionP[i, :],
                                      latVec)  # conventional -> Cartesian

            #############################
            # total polarization (C/m2) #
            #############################
            # Total polarization (C/m2) will be returned
            # when calling mainCalculation()
            self._totalPolarizationVal = self.totalPolarization(elP, ionP)
            # Prepare transform polarization from lattice vectors to Cartesian
            # coordinates (totP -> totPcart
            latVec = numpy.zeros((3, 3))
        # END iterate over various wrapping functions
        print('''
Notes:
(1) When lattice vectors are _not_ aligned with Cartesian coordinates, an
    additional transformation is required to present the polarization vector
    in Cartesian coordinates. This can be important when calculating Born 
    effective charges
           Z*_i,j = (Omega/e) * dP_i/dr_j,
    where i, j are Cartesian components, Omega is the cell volume (see output
    above), and e is the elementary charge. The total polarization vector is
    presented in Cartesian coordinates and should be used to determine dP_i.
    It is, however, up to the user to transform the atom displacement vector
    components dr_j into Cartesian coordinates. The change in fractional
    coordinated should be converted into dr_j using lattice vectors dir(1,2,3)
    used in calculation of the ionic polarization (see above). An 
    Octave/Matlab sctipt can be found in
    https://github.com/spichardo/BerryPI/wiki/Tutorial-3:-Non-orthogonal-lattice-vectors
(2) Results are presented for two pi-wrapping options [-pi .. +pi] and 
    [0 .. +2pi] separated by ~~~~~~. It is designed to assist in situations 
    when a sudden change in the Berry phase (and associated polarization) 
    occurs due to a pi-wrapping artefact (see discussion pertaining Fig. 2 in 
    Ref. [1]). It is up to the user to select the most relevant option. This 
    decision should be made based on comparing results for _two_ different 
    structures. The goal is to ensure a smooth change in the phase in response 
    to a small perturbation.''')
Ejemplo n.º 8
0
    def determineIonPolarization(self, fnWrpMethod, args):
        '''
        INPUT: fnWrpMethod - function that determines the method for
                             wrapping the phase
               args - contains logical variables regarding the
                      calculation setup
                      args['so'] - spin-orbit coupling
                      args['sp'] - spin-polarized calculation
                      args['orb'] - additional orbital potential (LDA+U)

        Calculation:

        Pion_x = electron charge / unit volume (m) * lattice_x * (
        
          sum of (
            atom valence charge * position(x)
            )
          )

          where atom valence charge = ( core value - spin val 1 - spin val 2 )
        '''
        print "\n", "CALCULATION OF IONIC POLARIZATION"
        ionP = []
        calcValues = self.calculationValues()
        ELEC_BY_VOL_CONST = self.ELEC_BY_VOL_CONST
        latticeConstants = calcValues['Lattice Constants in bohr']
        atomListing = calcValues['Atom Listing']
        #produce a tuple pair which includes the valence electrons and
        #the coordinates for each element
        calcIonValues = [] # (coordinates(x,y,z), valence value)
        
        #TODO: include good exception handling for this stage
        #construct the calcIonValues for the calculation
        if args['sp'] and not args['so']:
            nspins = 2
        else:
            nspins = 1
        for atom in atomListing:
            for i in range(atom['MULT']):
                theElementName = atom['Element Name']
                if calcValues['Element Listing'].has_key(theElementName):
                    theElement = calcValues['Element Listing'][theElementName]
                    if nspins == 2:
                        theValence = []
                        for spin in [1, 2]:
                            theValence.append( \
                                atom['Znucl']/2 - theElement['Core Value']/2 \
                            );
                    else:
                        theValence = atom['Znucl'] - theElement['Core Value'];
                    xCoordinate = atom['X-Coord'][i]
                    yCoordinate = atom['Y-Coord'][i]
                    zCoordinate = atom['Z-Coord'][i] 

                    #produce tuple from coordinates
                    coordinates = (xCoordinate, yCoordinate, zCoordinate)
                    calcIonValues.append((theElementName,coordinates, theValence))
                else:
                    print DEFAULT_PREFIX + 'ERROR: Missing element in element list'
                    print DEFAULT_PREFIX + theElementName
                    print DEFAULT_PREFIX + calcValues['Element List']
                    print DEFAULT_PREFIX + 'Exiting....'
                    sys.exit(1)
        self._calcIonValues = calcIonValues

        #### CALCULATION ####
        xPolarIon, yPolarIon, zPolarIon = (0., 0., 0.)
        print "="*87
        print "Elem.|  Fractional coord.  |  spin | Zion |", \
            "   dir(1)   ", \
            "|   ", "dir(2)   ", "|   ", "dir(3)"
        print "-"*87
        print " "*41, "+"+"-"*12, "Ionic phase (rad)", \
            "-"*12+"+"
        totIonPhase = numpy.zeros((nspins,3))
        for element, iCoord, iValence in calcIonValues:
            spinIndex = -1
            if isinstance(iValence, collections.Iterable):
                pass
            else:
                iValence = [iValence, ]
            for spinValence in iValence:
                spinIndex += 1
                ionPhase = numpy.zeros((nspins,3))
                coordIndex = -1
                for fcoord in iCoord:
                    coordIndex += 1
                    # fractional coordinates used
                    psi = fcoord * spinValence * 2*numpy.pi
                    ionPhase[ spinIndex , coordIndex ] = psi
                if spinIndex == 0:
                    print "%2s " % element, \
                        "(%6.4f, %6.4f, %6.4f) " % iCoord, \
                        "sp(%1i)" % (spinIndex+1), \
                        "%5.2f" % spinValence, \
                        "[% e, % e, % e]" % tuple(ionPhase[spinIndex,:]);
                else:
                    print " "*29, \
                        "sp(%1i)" % (spinIndex+1), \
                        "%5.2f" % spinValence, \
                        "[% e, % e, % e]" % tuple(ionPhase[spinIndex,:]);
                totIonPhase[:,:] += ionPhase
        print "-"*87
        for spinIndex in range(0,nspins):
           	print "Total ionic phase (rad)", " "*5, \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(totIonPhase[spinIndex,:]);

        # warap phases
        totIonPhase = fnWrpMethod( totIonPhase );

        for spinIndex in range(0,nspins):
           	print "Total ionic phase wrap. (rad)", \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(totIonPhase[spinIndex,:]);

        #IONIC Polarization
        ionPol = numpy.zeros((nspins,3))
        for spinIndex in range(0,nspins):
            for coordIndex in range(0,3):
                psi = totIonPhase[spinIndex,coordIndex]
                a = latticeConstants[coordIndex]
                ionPol[spinIndex,coordIndex] = \
                    (psi/(2*numpy.pi)) * ELEC_BY_VOL_CONST * \
                    bohrToMeters(a);
            print "Ionic polarization (C/m2)    ", \
                "sp(%1i)" % (spinIndex+1), " "*5, \
                "[% e, % e, % e]" % tuple(ionPol[spinIndex,:]);
        print "="*87

        return ionPol # END determineIonPolarization
Ejemplo n.º 9
0
    def __init__(self, **args):

        # spin polarization: yes/no
        spCalc = args['sp']

        ############################
        ######### PARSING ##########
        ############################

        ###Rest of the Files###
        #parse all the things!
        #### *.struct file parser
        parser_struct_handle = open(args['file_struct'], 'r').readlines()
        parser_struct_handle = b_PyParse.MainStructParser(parser_struct_handle)
        parser_struct_handle.parse()


        #### *.scf file parser
        parser_scf_handle = open(args['file_scf'], 'r').readlines()
        parser_scf_handle = b_PyParse.MainSCFParser(parser_scf_handle)
        parser_scf_handle.parse()


        #### *.outputd parser
        parser_outputd_handle = open(args['file_outputd'], 'r').readlines()
        parser_outputd_handle = b_PyParse.MainOutputDParser(parser_outputd_handle)
        parser_outputd_handle.parse()

        
        #### *.outputst parser
        parser_outputst_handle = open(args['file_outputst'], 'r').readlines()
        parser_outputst_handle = b_PyParse.MainOutputstParser(parser_outputst_handle)
        parser_outputst_handle.parse()


        #####################################
        ############ END Parsing ############
        #####################################


        #############################
        ###### Getting Values #######
        #############################
        self._calculationValues = orderedDict();
        
        #### *.struct handle
        # - determine name of atoms
        # - determine MULT for each atom
        self._calculationValues['Atom Listing'] = \
            parser_struct_handle['Atom Listing'];
        
        #### *.scf handle
        # - Cell Volume
        self._calculationValues['Cell Volume in bohr^3'] = \
            parser_scf_handle['Cell Volume'];
        self._calculationValues['Cell Volume in m^3'] = \
            bohrToMeters(self._calculationValues['Cell Volume in bohr^3'],3);

        #### *.outputd handle
        # - BR2_DIR matrix (v_x, v_y, v_z)
        # - number of atoms in cell
        # - Lattice Constants (x,y,z)
      	laticematrix=parser_outputd_handle['BR2_DIR Matrix']
      	latticematrixa1=laticematrix[0]
      	self._calculationValues['Lattice Matrix a1 in bohr'] = \
            latticematrixa1;
      	latticematrixa2=laticematrix[1]
      	self._calculationValues['Lattice Matrix a2 in bohr'] = \
            latticematrixa2;
      	latticematrixa3=laticematrix[2]
      	self._calculationValues['Lattice Matrix a3 in bohr'] = \
            latticematrixa3;
        self._calculationValues['Lattice Matrix in bohr'] = \
            parser_outputd_handle['BR2_DIR Matrix'];
        self._calculationValues['Lattice Matrix in m'] = \
            [[ bohrToMeters(i) for i in j ] for j in \
            self._calculationValues['Lattice Matrix in bohr']];
        self._calculationValues['Number of Atoms in Unit Cell'] = \
            parser_outputd_handle['Number of Atoms in Unit Cell'];
        self._calculationValues['Lattice Constants in bohr'] = \
            parser_outputd_handle['Lattice Constants'];
        self._calculationValues['Lattice Constants in m'] = \
            [ bohrToMeters(i) for i in \
            self._calculationValues['Lattice Constants in bohr']];

        #### *.outputst handle
        # for each element:
        # - Core Value
        # - Spin Value 1
        # - Spin Value 2
        self._calculationValues['Element Listing'] = \
            parser_outputst_handle['Element List'];

        ####
        
        ########################
        # get electronic phase #
        ########################
        # get raw list [k-points, phase]
        phaseDirSpinPathRaw = args['phases']
        # wrap phases in the range [-pi ... +pi]
        phaseDirSpinPathWrp11 = self.wrpPhase(phaseDirSpinPathRaw, \
            self.wrp11);
        # print nice
        print "\n","Initial Berry phases and their", \
            "wrapped values in the range [-pi ... +pi]";
        print "="*87
        print " "*30, "| init k-point", "| phase raw (rad)", \
            "| phase wrap. (rad)"
        icoord = -1
        for coord in phaseDirSpinPathRaw:
            icoord += 1
            print "-"*87
            print "direction(%u)" % int(icoord + 1)
            ispin = -1
            for spin in coord:
                ispin += 1
                print " "*12, "spin(%u)" % int(ispin + 1)
                ipath = -1
                for path in spin:
                    ipath += 1
                    # perform wraping using the method privided in input
                    kpt = phaseDirSpinPathRaw[icoord][ispin][ipath][0]
                    ph = phaseDirSpinPathRaw[icoord][ispin][ipath][1]
                    phwrp = phaseDirSpinPathWrp11[icoord][ispin][ipath][1]
                    print " "*20, "path(%4d)       %4d        % e        % e" \
                        % (ipath+1, kpt, ph, phwrp)
        print "="*87
        print "\n","CALCULATION OF ELECTRONIC POLARIZATION"
        print "="*87
        print "Value", " "*25, "|  spin  ", "|   ", "dir(1)   ", \
            "|   ", "dir(2)   ", "|   ", "dir(3)"
        print "-"*87
        # find path-average phase
        phaseDirSpinWrp11 = self.pathAvrgPhase(phaseDirSpinPathWrp11);
        # wrap the average phase again as it can go out of bounds [-pi..+pi]
        phaseDirSpinWrp11 = self.wrp11(phaseDirSpinWrp11);
        nspins = numpy.shape(phaseDirSpinWrp11)[1]
        for spinIndex in range(0,nspins):
            print "Berry phase (rad) [-pi ... +pi]    sp(%1i)" \
                % (spinIndex+1), \
                " [% e, % e, % e]" % tuple(phaseDirSpinWrp11[:,spinIndex]);                
        if not spCalc and not args['so']: # in case of non-SP or non-SO calculation...
            phaseDirSpinWrp11 = 2*phaseDirSpinWrp11 # account for the spin degeneracy
            nspins = numpy.shape(phaseDirSpinWrp11)[1]
            if nspins != 1: # double check
                print "Inconsistency detected in the number of spins"
                print "Is it spin-polarized calculation? spCalc =", spCalc
                print "Number of spins in the electronic phase array", \
                    nspins;
                print "Expected 1 spin"
                print "Decision is taken to EXIT"
                sys.exit(2)
            print "Berry phase (rad)                  up+dn  "+ \
                "[% e, % e, % e]" % tuple(phaseDirSpinWrp11);
            # wrap phases again [-pi ... +pi]
            phaseDirSpinWrp11 = self.wrp11(phaseDirSpinWrp11)
            print "Berry phase (rad) [-pi ... +pi] " +\
                "   up+dn  [% e, % e, % e]" \
                % tuple(phaseDirSpinWrp11);
        #electron charge / cell volume
        self.ELEC_BY_VOL_CONST = ELECTRON_CHARGE / \
            bohrToMeters(self._calculationValues['Cell Volume in bohr^3'], \
            dimension = 3.);
        # electronic polarization (C/m2)
        elP = self.elPolarization(phaseDirSpinWrp11,self._calculationValues, \
            self.ELEC_BY_VOL_CONST);
        # ionic polarization (C/m2)
        ionP = self.determineIonPolarization(self.wrp11,args)
        # Total polarization (C/m2) will be returned
        # when calling mainCalculation()
        self._totalPolarizationVal = self.totalPolarization(elP, ionP)
Ejemplo n.º 10
0
    def __init__(self, **args):

        # spin polarization: yes/no
        spCalc = args['sp']

        ############################
        ######### PARSING ##########
        ############################

        ###Rest of the Files###
        #parse all the things!
        #### *.struct file parser
        parser_struct_handle = open(args['file_struct'], 'r').readlines()
        parser_struct_handle = b_PyParse.MainStructParser(parser_struct_handle)
        parser_struct_handle.parse()

        #### *.inc parser
        parser_inc_handle = open(args['file_inc'], 'r').readlines()
        parser_inc_handle = b_PyParse.MainIncParser(parser_inc_handle)
        parser_inc_handle.parse()

        #####################################
        ############ END Parsing ############
        #####################################

        #############################
        ###### Getting Values #######
        #############################
        self._calculationValues = orderedDict()

        #### *.struct handle
        # - name of atoms
        # - MULT for each atom
        # - coordinates
        # - nuclear charge
        self._calculationValues['Atom Listing'] = \
            parser_struct_handle['Atom Listing']
        # - Cell Volume
        self._calculationValues['Cell Volume in bohr^3'] = \
            parser_struct_handle['cell volume']
        # - Lattice Constants (a,b,c)
        self._calculationValues['Lattice Constants in bohr'] = \
            parser_struct_handle['lattice constants']
        # - lattice vectors BR2_DIR matrix (v_x, v_y, v_z)
        self._calculationValues['Lattice Matrix in bohr'] = \
            parser_struct_handle['real space lattice vectors']

        ### *.inc handle
        # - core charge for each non-eqivalent atom
        self._calculationValues['Atom core charges'] = \
            parser_inc_handle['core charges']

        # check consistency of case.struct and case.inc files
        if len(self._calculationValues['Atom core charges']) != \
            len(self._calculationValues['Atom Listing']):
            print("Number of non-equivalent atoms in case.struct:", \
                len(self._calculationValues['Atom Listing']))
            print("Number of non-equivalent atoms in case.inc:", \
                len(self._calculationValues['Atom core charges']))
            raise Exception("Inconsistent number of non-equivalent atoms")

        ########################
        # get electronic phase #
        ########################
        # get raw list [k-points, phase]
        phaseDirSpinPathRaw = args['phases']
        # wrap phases in the range [-pi ... +pi]
        phaseDirSpinPathWrp11 = self.wrpPhase(phaseDirSpinPathRaw, \
            self.wrp11)
        # print nice
        print("\n","Initial Berry phases and their", \
            "wrapped values in the range [-pi ... +pi]")
        print("=" * 87)
        print(" "*30, "| init k-point", "| phase raw (rad)", \
            "| phase wrap. (rad)")
        icoord = -1
        for coord in phaseDirSpinPathRaw:
            icoord += 1
            print("-" * 87)
            print("direction(%u)" % int(icoord + 1))
            ispin = -1
            for spin in coord:
                ispin += 1
                print(" " * 12, "spin(%u)" % int(ispin + 1))
                ipath = -1
                for path in spin:
                    ipath += 1
                    # perform wraping using the method privided in input
                    kpt = phaseDirSpinPathRaw[icoord][ispin][ipath][0]
                    ph = phaseDirSpinPathRaw[icoord][ispin][ipath][1]
                    phwrp = phaseDirSpinPathWrp11[icoord][ispin][ipath][1]
                    print(" "*20, "path(%4d)       %4d        % e        % e" \
                        % (ipath+1, kpt, ph, phwrp))
        print("=" * 87)
        print("\n", "CALCULATION OF ELECTRONIC POLARIZATION")
        print("=" * 87)
        print("Value", " "*25, "|  spin  ", "|   ", "dir(1)   ", \
            "|   ", "dir(2)   ", "|   ", "dir(3)")
        print("-" * 87)
        # find path-average phase
        phaseDirSpinWrp11 = self.pathAvrgPhase(phaseDirSpinPathWrp11)
        # wrap the average phase again as it can go out of bounds [-pi..+pi]
        phaseDirSpinWrp11 = self.wrp11(phaseDirSpinWrp11)
        nspins = numpy.shape(phaseDirSpinWrp11)[1]
        for spinIndex in range(0, nspins):
            print("Berry phase (rad) [-pi ... +pi]    sp(%1i)" \
                % (spinIndex+1), \
                " [% e, % e, % e]" % tuple(phaseDirSpinWrp11[:,spinIndex]))
        if not spCalc and not args[
                'so']:  # in case of non-SP or non-SO calculation...
            phaseDirSpinWrp11 = 2 * phaseDirSpinWrp11  # account for the spin degeneracy
            nspins = numpy.shape(phaseDirSpinWrp11)[1]
            if nspins != 1:  # double check
                print("Inconsistency detected in the number of spins")
                print("Is it spin-polarized calculation? spCalc =", spCalc)
                print("Number of spins in the electronic phase array", \
                    nspins)
                print("Expected 1 spin")
                print("Decision is taken to EXIT")
                sys.exit(2)
            print("Berry phase (rad)                  up+dn  "+ \
                "[% e, % e, % e]" % tuple(phaseDirSpinWrp11))
            # wrap phases again [-pi ... +pi]
            phaseDirSpinWrp11 = self.wrp11(phaseDirSpinWrp11)
            print("Berry phase (rad) [-pi ... +pi] " +\
                "   up+dn  [% e, % e, % e]" \
                % tuple(phaseDirSpinWrp11))
        #electron charge / cell volume
        self.ELEC_BY_VOL_CONST = ELECTRON_CHARGE / \
            bohrToMeters(self._calculationValues['Cell Volume in bohr^3'], \
            dimension = 3.)
        # electronic polarization (C/m2)
        elP = self.elPolarization(phaseDirSpinWrp11,self._calculationValues, \
            self.ELEC_BY_VOL_CONST)
        # ionic polarization (C/m2)
        ionP = self.determineIonPolarization(self.wrp11, args)
        # Total polarization (C/m2) will be returned
        # when calling mainCalculation()
        self._totalPolarizationVal = self.totalPolarization(elP, ionP)