relax_box calculation style

Lucas M. Hale, lucas.hale@nist.gov, Materials Science and Engineering Division, NIST.

Introduction

The relax_box calculation style refines the lattice parameters of an orthogonal system (crystal structure) by relaxing the box dimensions towards a given pressure. In refining the lattice parameter values, the box dimensions are allowed to relax, but the relative positions of the atoms within the box are held fixed.

This calculations provides a quick tool for obtaining lattice parameters for ideal crystal structures.

Version notes

  • 2018-07-09: Notebook added.

  • 2019-07-30: Description updated and small changes due to iprPy version.

  • 2020-05-22: Version 0.10 update - potentials now loaded from database.

  • 2020-09-22: Setup and parameter definition streamlined.

Additional dependencies

Disclaimers

  • NIST disclaimers

  • With this method there is no guarantee that the resulting parameters are for a stable structure. Allowing internal relaxations may result in different values for some structures. Additionally, some transformation paths may be restricted from occurring due to symmetry, i.e. initially cubic structures may remain cubic instead of relaxing to a non-cubic structure.

Method and Theory

The math in this section uses Voigt notation, where indicies i,j correspond to 1=xx, 2=yy, 3=zz, 4=yz, 5=xz, and 6=xy, and x, y and z are orthogonal box vectors.

An initial system (and corresponding unit cell system) is supplied with box dimensions, \(a_i^0\), close to the equilibrium values. A LAMMPS simulation is performed that evaluates the system’s pressures, \(P_{i}\), for the initial system as given, and subjected to twelve different strain states corresponding to one of \(\epsilon_{i}\) being given a value of \(\frac{\Delta \epsilon}{2}\), where \(\Delta \epsilon\) is the strain range parameter. Using the \(P_{i}\) values obtained from the strained states, the \(C_{ij}\) matrix for the system is estimated as

\[C_{ij} \approx - \frac{P_i(\epsilon_j=\frac{\Delta \epsilon}{2}) - P_i(\epsilon_j=-\frac{\Delta \epsilon}{2})}{\Delta \epsilon}.\]

The negative out front comes from the fact that the system-wide stress state is \(\sigma_i = -P_i\). Using \(C_{ij}\), an attempt is made to compute the elastic compliance matrix as \(S_{ij} = C_{ij}^{-1}\). If successful, new box dimensions are estimated using \(S_{ij}\), \(a_i^0\), and \(P_i\) for the unstrained system

\[a_i = \frac{a_i^0}{1 - (\sum_{j=1}^3{S_{ij} P_j})}.\]

The system is updated using the new box dimensions. The process is repeated until either \(a_i\) converge less than a specified tolerance, \(a_i\) diverge from \(a_i^0\) greater than some limit, or convergence is not reached after 100 iterations. If the calculation is successful, the final \(a_i\) dimensions are reported.

Demonstration

1. Setup

1.1. Library imports

Import libraries needed by the calculation. The external libraries used are:

[1]:
# Standard library imports
from pathlib import Path
import os
import shutil
import datetime
from copy import deepcopy

# http://www.numpy.org/
import numpy as np

# https://github.com/usnistgov/DataModelDict
from DataModelDict import DataModelDict as DM

# https://github.com/usnistgov/atomman
import atomman as am
import atomman.lammps as lmp
import atomman.unitconvert as uc

# https://github.com/usnistgov/iprPy
import iprPy

print('Notebook last executed on', datetime.date.today(), 'using iprPy version', iprPy.__version__)
Notebook last executed on 2020-09-22 using iprPy version 0.10.2

1.2. Default calculation setup

[2]:
# Specify calculation style
calc_style = 'relax_box'

# If workingdir is already set, then do nothing (already in correct folder)
try:
    workingdir = workingdir

# Change to workingdir if not already there
except:
    workingdir = Path('calculationfiles', calc_style)
    if not workingdir.is_dir():
        workingdir.mkdir(parents=True)
    os.chdir(workingdir)

# Initialize connection to library
library = iprPy.Library(load=['lammps_potentials'])

2. Assign values for the calculation’s run parameters

2.1. Specify system-specific paths

  • lammps_command is the LAMMPS command to use (required).

  • mpi_command MPI command for running LAMMPS in parallel. A value of None will run simulations serially.

[3]:
lammps_command = 'lmp_serial'
mpi_command = None

2.2. Load interatomic potential

  • potential_name gives the name of the potential_LAMMPS reference record in the iprPy library to use for the calculation.

  • potential is an atomman.lammps.Potential object (required).

[4]:
potential_name = '1999--Mishin-Y--Ni--LAMMPS--ipr1'

# Retrieve potential and parameter file(s)
potential = library.get_lammps_potential(id=potential_name, getfiles=True)

2.3. Load initial unit cell system

  • ucell is an atomman.System representing a fundamental unit cell of the system (required). Here, this is generated using the load parameters and symbols.

[5]:
# Create ucell by loading prototype record
ucell = am.load('prototype', 'A1--Cu--fcc', symbols='Ni', a=3.5)

print(ucell)
avect =  [ 3.500,  0.000,  0.000]
bvect =  [ 0.000,  3.500,  0.000]
cvect =  [ 0.000,  0.000,  3.500]
origin = [ 0.000,  0.000,  0.000]
natoms = 4
natypes = 1
symbols = ('Ni',)
pbc = [ True  True  True]
per-atom properties = ['atype', 'pos']
     id   atype  pos[0]  pos[1]  pos[2]
      0       1   0.000   0.000   0.000
      1       1   0.000   1.750   1.750
      2       1   1.750   0.000   1.750
      3       1   1.750   1.750   0.000

2.4. Modify system

  • sizemults list of three integers specifying how many times the ucell vectors of \(a\), \(b\) and \(c\) are replicated in creating system.

  • system is an atomman.System to perform the scan on (required).

[6]:
sizemults = [3, 3, 3]

# Generate system by supersizing ucell
system = ucell.supersize(*sizemults)
print('# of atoms in system =', system.natoms)
# of atoms in system = 108

2.5. Specify calculation-specific run parameters

  • strainrange specifies the \(\Delta \epsilon\) strain range to use in estimating \(C_{ij}\).

  • pressure_xx gives the xx component of the pressure to equilibriate the system to.

  • pressure_yy gives the yy component of the pressure to equilibriate the system to.

  • pressure_zz gives the zz component of the pressure to equilibriate the system to.

  • convergence_tol is the relative tolerance to use in identifying if the lattice constants have converged.

  • divergence_scale is a factor for identifying if the lattice constants have diverged from the original guess. Divergence is identified if \(a > a^0 d\) or \(a < a^0 / d\), where d is divergence_scale.

[7]:
strainrange = 1e-7
pressure_xx = uc.set_in_units(0.0, 'GPa')
pressure_yy = uc.set_in_units(0.0, 'GPa')
pressure_zz = uc.set_in_units(0.0, 'GPa')
convergence_tol = 1e-11
divergence_scale = 3.

3. Define calculation function(s) and generate template LAMMPS script(s)

3.1. cij.template

[8]:
with open('cij.template', 'w') as f:
    f.write("""# LAMMPS input script that evaluates the Virial pressure of a system both as
# it was given, and with small strains applied.
# This can be used to estimate the 0 K elastic constants of the system.

box tilt large

<atomman_system_pair_info>

change_box all triclinic

# Specify strain range and number of points to examine in the range
variable delta equal <delta>
variable steps equal <steps>
variable deltax equal ${delta}/(${steps}-1)

# Specify variables of the initial configuration's dimensions
variable lx0 equal $(lx)
variable ly0 equal $(ly)
variable lz0 equal $(lz)

# Specify the thermo properties to calculate
variable peatom equal pe/atoms
thermo_style custom step lx ly lz yz xz xy pxx pyy pzz pyz pxz pxy v_peatom pe
thermo_modify format float %.13e

# Compute properties for the initial configuration
run 0

# Compute properties for normal x-direction strains
variable aratio equal 1-${delta}/2.+(v_a-1)*${deltax}
variable xmax equal v_aratio*${lx0}
label loopa
variable a loop ${steps}
change_box all x final 0 ${xmax} remap units box
run 0
next a
jump cij.in loopa
change_box all x final 0 ${lx0} remap units box

# Compute properties for normal y-direction strains
variable bratio equal 1-${delta}/2.+(v_b-1)*${deltax}
variable ymax equal v_bratio*${ly0}
label loopb
variable b loop ${steps}
change_box all y final 0 ${ymax} remap units box
run 0
next b
jump cij.in loopb
change_box all y final 0 ${ly0} remap units box

# Compute properties for normal z-direction strains
variable cratio equal 1-${delta}/2.+(v_c-1)*${deltax}
variable zmax equal v_cratio*${lz0}
label loopc
variable c loop ${steps}
change_box all z final 0 ${zmax} remap units box
run 0
next c
jump cij.in loopc
change_box all z final 0 ${lz0} remap units box

# Compute properties for yz shear strains
variable eyz equal (-${delta}/2.+(v_d-1)*${deltax})*${lz0}
label loopd
variable d loop ${steps}
change_box all yz final ${eyz} remap units box
run 0
next d
jump cij.in loopd
change_box all yz final 0 remap units box

# Compute properties for xz shear strains
variable exz equal (-${delta}/2.+(v_e-1)*${deltax})*${lz0}
label loope
variable e loop ${steps}
change_box all xz final ${exz} remap units box
run 0
next e
jump cij.in loope
change_box all xz final 0 remap units box

# Compute properties for xy shear strains
variable exy equal (-${delta}/2.+(v_f-1)*${deltax})*${ly0}
label loopf
variable f loop ${steps}
change_box all xy final ${exy} remap units box
run 0
next f
jump cij.in loopf
change_box all xy final 0 remap units box""")

3.2. relax_box()

[9]:
def relax_box(lammps_command, system, potential,
              mpi_command=None, strainrange=1e-6,
              p_xx=0.0, p_yy=0.0, p_zz=0.0, p_xy=0.0, p_xz=0.0, p_yz=0.0,
              tol=1e-10, diverge_scale=3.):
    """
    Quickly refines static orthorhombic system by evaluating the elastic
    constants and the virial pressure.

    Parameters
    ----------
    lammps_command :str
        Command for running LAMMPS.
    system : atomman.System
        The system to perform the calculation on.
    potential : atomman.lammps.Potential
        The LAMMPS implemented potential to use.
    mpi_command : str, optional
        The MPI command for running LAMMPS in parallel.  If not given, LAMMPS
        will run serially.
    strainrange : float, optional
        The small strain value to apply when calculating the elastic
        constants (default is 1e-6).
    p_xx : float, optional
        The value to relax the x tensile pressure component to (default is
        0.0).
    p_yy : float, optional
        The value to relax the y tensile pressure component to (default is
        0.0).
    p_zz : float, optional
        The value to relax the z tensile pressure component to (default is
        0.0).
    tol : float, optional
        The relative tolerance used to determine if the lattice constants have
        converged (default is 1e-10).
    diverge_scale : float, optional
        Factor to identify if the system's dimensions have diverged.  Divergence
        is identified if either any current box dimension is greater than the
        original dimension multiplied by diverge_scale, or if any current box
        dimension is less than the original dimension divided by diverge_scale.
        (Default is 3.0).

    Returns
    -------
    dict
        Dictionary of results consisting of keys:

        - **'a_lat'** (*float*) - The relaxed a lattice constant.
        - **'b_lat'** (*float*) - The relaxed b lattice constant.
        - **'c_lat'** (*float*) - The relaxed c lattice constant.
        - **'alpha_lat'** (*float*) - The alpha lattice angle.
        - **'beta_lat'** (*float*) - The beta lattice angle.
        - **'gamma_lat'** (*float*) - The gamma lattice angle.
        - **'E_coh'** (*float*) - The cohesive energy of the relaxed system.
        - **'stress'** (*numpy.array*) - The measured stress state of the
          relaxed system.
        - **'C_elastic'** (*atomman.ElasticConstants*) - The relaxed system's
          elastic constants.
        - **'system_relaxed'** (*atomman.System*) - The relaxed system.

    Raises
    ------
    RuntimeError
        If system diverges or no convergence reached after 100 cycles.
    """

    # Flag for if values have converged
    converged = False

    # Define current and old systems
    system_current = deepcopy(system)
    system_old = None

    system.dump('atom_dump', f='initial.dump')

    for cycle in range(100):

        # Run LAMMPS and evaluate results based on system_old
        results = calc_cij(lammps_command, system_current, potential,
                           mpi_command=mpi_command,
                           p_xx=p_xx, p_yy=p_yy, p_zz=p_zz,
                           strainrange=strainrange, cycle=cycle)
        system_new = results['system_new']

        # Compare new and current to test for convergence
        if np.allclose(system_new.box.vects,
                       system_current.box.vects,
                       rtol=tol, atol=0):
            converged = True
            break

        # Compare old and new to test for double-value convergence
        elif system_old is not None and np.allclose(system_new.box.vects,
                                                    system_old.box.vects,
                                                    rtol=tol, atol=0):
            # Update current to average of old and new
            system_current.box_set(a = (system_new.box.a+system_old.box.a) / 2.,
                                   b = (system_new.box.b+system_old.box.b) / 2.,
                                   c = (system_new.box.c+system_old.box.c) / 2.,
                                   scale=True)
            # Calculate Cij for the averaged system
            results = calc_cij(lammps_command, system_current, potential,
                               mpi_command=mpi_command,
                               p_xx=p_xx, p_yy=p_yy, p_zz=p_zz,
                               strainrange=strainrange, cycle=cycle+1)
            system_new = results['system_new']
            converged = True
            break

        # Test for divergence
        elif system_new.box.a < system.box.a / diverge_scale:
            raise RuntimeError('Divergence of box dimensions')
        elif system_new.box.a > system.box.a * diverge_scale:
            raise RuntimeError('Divergence of box dimensions')
        elif system_new.box.b < system.box.b / diverge_scale:
            raise RuntimeError('Divergence of box dimensions')
        elif system_new.box.b > system.box.b * diverge_scale:
            raise RuntimeError('Divergence of box dimensions')
        elif system_new.box.c < system.box.c / diverge_scale:
            raise RuntimeError('Divergence of box dimensions')
        elif system_new.box.c > system.box.c * diverge_scale:
            raise RuntimeError('Divergence of box dimensions')
        elif results['E_coh'] == 0.0:
            raise RuntimeError('Divergence: cohesive energy is 0')

        # If not converged or diverged, current -> old and new -> current
        else:
            system_old, system_current = system_current, system_new

    # Return values when converged
    if converged:
        system_new.dump('atom_dump', f='final.dump')

        # Build results_dict
        results_dict = {}
        results_dict['dumpfile_initial'] = 'initial.dump'
        results_dict['symbols_initial'] = system.symbols
        results_dict['dumpfile_final'] = 'final.dump'
        results_dict['symbols_final'] = system.symbols

        results_dict['lx'] = system_new.box.lx
        results_dict['ly'] = system_new.box.ly
        results_dict['lz'] = system_new.box.lz
        results_dict['xy'] = system_new.box.xy
        results_dict['xz'] = system_new.box.xz
        results_dict['yz'] = system_new.box.yz

        results_dict['E_coh'] = results['E_coh']
        results_dict['measured_pxx'] = results['measured_pxx']
        results_dict['measured_pyy'] = results['measured_pyy']
        results_dict['measured_pzz'] = results['measured_pzz']
        results_dict['measured_pxy'] = results['measured_pxy']
        results_dict['measured_pxz'] = results['measured_pxz']
        results_dict['measured_pyz'] = results['measured_pyz']

        return results_dict
    else:
        raise RuntimeError('Failed to converge after 100 cycles')

3.3. calc_cij()

[10]:
def calc_cij(lammps_command, system, potential,
             mpi_command=None, p_xx=0.0, p_yy=0.0, p_zz=0.0,
             strainrange=1e-6, cycle=0):
    """
    Runs cij.in LAMMPS script to evaluate Cij, and E_coh of the current system,
    and define a new system with updated box dimensions to test.

    Parameters
    ----------
    lammps_command :str
        Command for running LAMMPS.
    system : atomman.System
        The system to perform the calculation on.
    potential : atomman.lammps.Potential
        The LAMMPS implemented potential to use.
    mpi_command : str, optional
        The MPI command for running LAMMPS in parallel.  If not given, LAMMPS
        will run serially.
    strainrange : float, optional
        The small strain value to apply when calculating the elastic
        constants (default is 1e-6).
    p_xx : float, optional
        The value to relax the x tensile pressure component to (default is
        0.0).
    p_yy : float, optional
        The value to relax the y tensile pressure component to (default is
        0.0).
    p_zz : float, optional
        The value to relax the z tensile pressure component to (default is
        0.0).
    cycle : int, optional
        Indicates the iteration cycle of quick_a_Cij().  This is used to
        uniquely save the LAMMPS input and output files.

    Returns
    -------
    dict
        Dictionary of results consisting of keys:

        - **'E_coh'** (*float*) - The cohesive energy of the supplied system.
        - **'stress'** (*numpy.array*) - The measured stress state of the
          supplied system.
        - **'C_elastic'** (*atomman.ElasticConstants*) - The supplied system's
          elastic constants.
        - **'system_new'** (*atomman.System*) - System with updated box
          dimensions.

    Raises
    ------
    RuntimeError
        If any of the new box dimensions are less than zero.
    """
    # Build filedict if function was called from iprPy
    try:
        assert __name__ == pkg_name
        calc = iprPy.load_calculation(calculation_style)
        filedict = calc.filedict
    except:
        filedict = {}

    # Get lammps units
    lammps_units = lmp.style.unit(potential.units)

    # Define lammps variables
    lammps_variables = {}
    system_info = system.dump('atom_data', f='init.dat',
                              potential=potential,
                              return_pair_info=True)
    lammps_variables['atomman_system_pair_info'] = system_info

    lammps_variables['delta'] = strainrange
    lammps_variables['steps'] = 2

    # Write lammps input script
    template_file = 'cij.template'
    lammps_script = 'cij.in'
    template = iprPy.tools.read_calc_file(template_file, filedict)
    with open(lammps_script, 'w') as f:
        f.write(iprPy.tools.filltemplate(template, lammps_variables,
                                         '<', '>'))

    # Run lammps
    output = lmp.run(lammps_command, lammps_script, mpi_command=mpi_command,
                     return_style='model')
    shutil.move('log.lammps', 'cij-'+str(cycle)+'-log.lammps')

    # Extract LAMMPS thermo data. Each term ranges i=0-12 where i=0 is undeformed
    # The remaining values are for -/+ strain pairs in the six unique directions
    lx = uc.set_in_units(np.array(output.finds('Lx')), lammps_units['length'])
    ly = uc.set_in_units(np.array(output.finds('Ly')), lammps_units['length'])
    lz = uc.set_in_units(np.array(output.finds('Lz')), lammps_units['length'])
    xy = uc.set_in_units(np.array(output.finds('Xy')), lammps_units['length'])
    xz = uc.set_in_units(np.array(output.finds('Xz')), lammps_units['length'])
    yz = uc.set_in_units(np.array(output.finds('Yz')), lammps_units['length'])

    pxx = uc.set_in_units(np.array(output.finds('Pxx')), lammps_units['pressure'])
    pyy = uc.set_in_units(np.array(output.finds('Pyy')), lammps_units['pressure'])
    pzz = uc.set_in_units(np.array(output.finds('Pzz')), lammps_units['pressure'])
    pxy = uc.set_in_units(np.array(output.finds('Pxy')), lammps_units['pressure'])
    pxz = uc.set_in_units(np.array(output.finds('Pxz')), lammps_units['pressure'])
    pyz = uc.set_in_units(np.array(output.finds('Pyz')), lammps_units['pressure'])

    pe = uc.set_in_units(np.array(output.finds('PotEng')) / system.natoms,
                         lammps_units['energy'])

    # Set the six non-zero strain values
    strains = np.array([ (lx[2] -  lx[1])  / lx[0],
                         (ly[4] -  ly[3])  / ly[0],
                         (lz[6] -  lz[5])  / lz[0],
                         (yz[8] -  yz[7])  / lz[0],
                         (xz[10] - xz[9])  / lz[0],
                         (xy[12] - xy[11]) / ly[0] ])

    # Calculate cij using stress changes associated with each non-zero strain
    cij = np.empty((6,6))
    for i in range(6):
        delta_stress = np.array([ pxx[2*i+1]-pxx[2*i+2],
                                  pyy[2*i+1]-pyy[2*i+2],
                                  pzz[2*i+1]-pzz[2*i+2],
                                  pyz[2*i+1]-pyz[2*i+2],
                                  pxz[2*i+1]-pxz[2*i+2],
                                  pxy[2*i+1]-pxy[2*i+2] ])

        cij[i] = delta_stress / strains[i]

    for i in range(6):
        for j in range(i):
            cij[i,j] = cij[j,i] = (cij[i,j] + cij[j,i]) / 2

    C = am.ElasticConstants(Cij=cij)

    S = C.Sij

    # Extract the current stress state
    stress = -1 * np.array([[pxx[0], pxy[0], pxz[0]],
                            [pxy[0], pyy[0], pyz[0]],
                            [pxz[0], pyz[0], pzz[0]]])

    s_xx = stress[0,0] + p_xx
    s_yy = stress[1,1] + p_yy
    s_zz = stress[2,2] + p_zz

    new_a = system.box.a / (S[0,0]*s_xx + S[0,1]*s_yy + S[0,2]*s_zz + 1)
    new_b = system.box.b / (S[1,0]*s_xx + S[1,1]*s_yy + S[1,2]*s_zz + 1)
    new_c = system.box.c / (S[2,0]*s_xx + S[2,1]*s_yy + S[2,2]*s_zz + 1)

    if new_a <= 0 or new_b <= 0 or new_c <=0:
        raise RuntimeError('Divergence of box dimensions to <= 0')

    system_new = deepcopy(system)
    system_new.box_set(a=new_a, b=new_b, c=new_c, scale=True)

    results_dict = {}
    results_dict['E_coh'] = pe[0]
    results_dict['system_new'] = system_new
    results_dict['measured_pxx'] = pxx[0]
    results_dict['measured_pyy'] = pyy[0]
    results_dict['measured_pzz'] = pzz[0]
    results_dict['measured_pxy'] = pxy[0]
    results_dict['measured_pxz'] = pxz[0]
    results_dict['measured_pyz'] = pyz[0]
    return results_dict

4. Run calculation function(s)

[11]:
results_dict = relax_box(lammps_command, system, potential,
                           mpi_command = mpi_command,
                           p_xx = pressure_xx,
                           p_yy = pressure_yy,
                           p_zz = pressure_zz,
                           strainrange = strainrange,
                           tol=convergence_tol,
                           diverge_scale=divergence_scale)
[12]:
results_dict.keys()
[12]:
dict_keys(['dumpfile_initial', 'symbols_initial', 'dumpfile_final', 'symbols_final', 'lx', 'ly', 'lz', 'xy', 'xz', 'yz', 'E_coh', 'measured_pxx', 'measured_pyy', 'measured_pzz', 'measured_pxy', 'measured_pxz', 'measured_pyz'])

5. Report results

5.1. Define units for outputting values

  • length_unit is the unit of length to display values in.

  • energy_unit is the unit of energy to display values in.

  • pressure_unit is the unit of pressure to display values in.

[13]:
length_unit = 'angstrom'
energy_unit = 'eV'
pressure_unit = 'GPa'

5.2. Print Ecoh and lattice constants of relaxed ucell

[14]:
print('Ecoh =', uc.get_in_units(results_dict['E_coh'], energy_unit), energy_unit)

box = am.Box(lx=results_dict['lx'], ly=results_dict['ly'], lz=results_dict['lz'],
             xy=results_dict['xy'], xz=results_dict['xz'], yz=results_dict['yz'])

print('a =', uc.get_in_units(box.a / sizemults[0], length_unit), length_unit)
print('b =', uc.get_in_units(box.b / sizemults[1], length_unit), length_unit)
print('c =', uc.get_in_units(box.c / sizemults[2], length_unit), length_unit)
print('alpha =', box.alpha)
print('beta = ', box.beta)
print('gamma =', box.gamma)
Ecoh = -4.449999998349075 eV
a = 3.519999437540435 angstrom
b = 3.5199994375404366 angstrom
c = 3.519999437540417 angstrom
alpha = 90.0
beta =  90.0
gamma = 90.0

5.3. Check final system pressures

[15]:
print('Pxx =', uc.get_in_units(results_dict['measured_pxx'], pressure_unit), pressure_unit)
print('Pyy =', uc.get_in_units(results_dict['measured_pyy'], pressure_unit), pressure_unit)
print('Pzz =', uc.get_in_units(results_dict['measured_pzz'], pressure_unit), pressure_unit)
print('Pyz =', uc.get_in_units(results_dict['measured_pyz'], pressure_unit), pressure_unit)
print('Pxz =', uc.get_in_units(results_dict['measured_pxz'], pressure_unit), pressure_unit)
print('Pxy =', uc.get_in_units(results_dict['measured_pxy'], pressure_unit), pressure_unit)
Pxx = 3.0498088437975e-12 GPa
Pyy = 3.0488307763301005e-12 GPa
Pzz = 2.1086605910971996e-12 GPa
Pyz = -5.5323121222754e-16 GPa
Pxz = -3.6252693770542003e-16 GPa
Pxy = -1.3217127937177e-16 GPa

5.4. Show relaxed atomic configuration

[16]:
finalsystem = am.load('atom_dump', results_dict['dumpfile_final'],
                      symbols=results_dict['symbols_final'])
print(finalsystem)
avect =  [10.560,  0.000,  0.000]
bvect =  [ 0.000, 10.560,  0.000]
cvect =  [ 0.000,  0.000, 10.560]
origin = [ 0.000,  0.000,  0.000]
natoms = 108
natypes = 1
symbols = ('Ni',)
pbc = [ True  True  True]
per-atom properties = ['atype', 'pos', 'atom_id']
     id   atype  pos[0]  pos[1]  pos[2]
      0       1   0.000   0.000   0.000
      1       1   0.000   1.760   1.760
      2       1   1.760   0.000   1.760
      3       1   1.760   1.760   0.000
      4       1   3.520   0.000   0.000
      5       1   3.520   1.760   1.760
      6       1   5.280   0.000   1.760
      7       1   5.280   1.760   0.000
      8       1   7.040   0.000   0.000
      9       1   7.040   1.760   1.760
     10       1   8.800   0.000   1.760
     11       1   8.800   1.760   0.000
     12       1   0.000   3.520   0.000
     13       1   0.000   5.280   1.760
     14       1   1.760   3.520   1.760
     15       1   1.760   5.280   0.000
     16       1   3.520   3.520   0.000
     17       1   3.520   5.280   1.760
     18       1   5.280   3.520   1.760
     19       1   5.280   5.280   0.000
     20       1   7.040   3.520   0.000
     21       1   7.040   5.280   1.760
     22       1   8.800   3.520   1.760
     23       1   8.800   5.280   0.000
     24       1   0.000   7.040   0.000
     25       1   0.000   8.800   1.760
     26       1   1.760   7.040   1.760
     27       1   1.760   8.800   0.000
     28       1   3.520   7.040   0.000
     29       1   3.520   8.800   1.760
     30       1   5.280   7.040   1.760
     31       1   5.280   8.800   0.000
     32       1   7.040   7.040   0.000
     33       1   7.040   8.800   1.760
     34       1   8.800   7.040   1.760
     35       1   8.800   8.800   0.000
     36       1   0.000   0.000   3.520
     37       1   0.000   1.760   5.280
     38       1   1.760   0.000   5.280
     39       1   1.760   1.760   3.520
     40       1   3.520   0.000   3.520
     41       1   3.520   1.760   5.280
     42       1   5.280   0.000   5.280
     43       1   5.280   1.760   3.520
     44       1   7.040   0.000   3.520
     45       1   7.040   1.760   5.280
     46       1   8.800   0.000   5.280
     47       1   8.800   1.760   3.520
     48       1   0.000   3.520   3.520
     49       1   0.000   5.280   5.280
     50       1   1.760   3.520   5.280
     51       1   1.760   5.280   3.520
     52       1   3.520   3.520   3.520
     53       1   3.520   5.280   5.280
     54       1   5.280   3.520   5.280
     55       1   5.280   5.280   3.520
     56       1   7.040   3.520   3.520
     57       1   7.040   5.280   5.280
     58       1   8.800   3.520   5.280
     59       1   8.800   5.280   3.520
     60       1   0.000   7.040   3.520
     61       1   0.000   8.800   5.280
     62       1   1.760   7.040   5.280
     63       1   1.760   8.800   3.520
     64       1   3.520   7.040   3.520
     65       1   3.520   8.800   5.280
     66       1   5.280   7.040   5.280
     67       1   5.280   8.800   3.520
     68       1   7.040   7.040   3.520
     69       1   7.040   8.800   5.280
     70       1   8.800   7.040   5.280
     71       1   8.800   8.800   3.520
     72       1   0.000   0.000   7.040
     73       1   0.000   1.760   8.800
     74       1   1.760   0.000   8.800
     75       1   1.760   1.760   7.040
     76       1   3.520   0.000   7.040
     77       1   3.520   1.760   8.800
     78       1   5.280   0.000   8.800
     79       1   5.280   1.760   7.040
     80       1   7.040   0.000   7.040
     81       1   7.040   1.760   8.800
     82       1   8.800   0.000   8.800
     83       1   8.800   1.760   7.040
     84       1   0.000   3.520   7.040
     85       1   0.000   5.280   8.800
     86       1   1.760   3.520   8.800
     87       1   1.760   5.280   7.040
     88       1   3.520   3.520   7.040
     89       1   3.520   5.280   8.800
     90       1   5.280   3.520   8.800
     91       1   5.280   5.280   7.040
     92       1   7.040   3.520   7.040
     93       1   7.040   5.280   8.800
     94       1   8.800   3.520   8.800
     95       1   8.800   5.280   7.040
     96       1   0.000   7.040   7.040
     97       1   0.000   8.800   8.800
     98       1   1.760   7.040   8.800
     99       1   1.760   8.800   7.040
    100       1   3.520   7.040   7.040
    101       1   3.520   8.800   8.800
    102       1   5.280   7.040   8.800
    103       1   5.280   8.800   7.040
    104       1   7.040   7.040   7.040
    105       1   7.040   8.800   8.800
    106       1   8.800   7.040   8.800
    107       1   8.800   8.800   7.040