Source code for ase2sprkkr.asr.stiffness

"""Stiffness tensor."""
from asr.core import command, option, ASRResult, prepare_result
import typing


[docs] def webpanel(result, row, key_descriptions): import numpy as np def matrixtable(M, digits=2, unit='', skiprow=0, skipcolumn=0): table = M.tolist() shape = M.shape for i in range(skiprow, shape[0]): for j in range(skipcolumn, shape[1]): value = table[i][j] table[i][j] = '{:.{}f}{}'.format(value, digits, unit) return table stiffnessdata = row.data['results-asr.stiffness.json'] c_ij = stiffnessdata['stiffness_tensor'] eigs = stiffnessdata['eigenvalues'] nd = np.sum(row.pbc) if nd == 2: c_ij = np.zeros((4, 4)) c_ij[1:, 1:] = stiffnessdata['stiffness_tensor'] rows = matrixtable(c_ij, unit='', skiprow=1, skipcolumn=1) rows[0] = ['C<sub>ij</sub> (N/m)', 'xx', 'yy', 'xy'] rows[1][0] = 'xx' rows[2][0] = 'yy' rows[3][0] = 'xy' eigrows = ([['<b>Stiffness tensor eigenvalues<b>', '']] + [[f'Eigenvalue {ie}', f'{eig.real:.2f} N/m'] for ie, eig in enumerate(sorted(eigs, key=lambda x: x.real))]) elif nd == 3: c_ij = np.zeros((7, 7)) c_ij[1:, 1:] = stiffnessdata['stiffness_tensor'] rows = matrixtable(c_ij, unit='', skiprow=1, skipcolumn=1) rows[0] = ['C<sub>ij</sub> (10^9 N/m^2)', 'xx', 'yy', 'zz', 'yz', 'xz', 'xy'] rows[1][0] = 'xx' rows[2][0] = 'yy' rows[3][0] = 'zz' rows[4][0] = 'yz' rows[5][0] = 'xz' rows[6][0] = 'xy' eigrows = ([['<b>Stiffness tensor eigenvalues<b>', '']] + [[f'Eigenvalue {ie}', f'{eig.real:.2f} * 10^9 N/m^2'] for ie, eig in enumerate(sorted(eigs, key=lambda x: x.real))]) else: rows = [] eig = complex(eigs[0]) eigrows = ([['<b>Stiffness tensor eigenvalues<b>', '']] + [[f'Eigenvalue', f'{eig.real:.2f} * 10^(-10) N']]) for ir, tmprow in enumerate(rows): for ic, item in enumerate(tmprow): if ir == 0 or ic == 0: rows[ir][ic] = '<b>' + rows[ir][ic] + '</b>' ctable = dict( type='table', rows=rows) eigtable = dict( type='table', rows=eigrows) panel = {'title': 'Stiffness tensor', 'columns': [[ctable], [eigtable]], 'sort': 2} dynstab = row.dynamic_stability_stiffness high = 'Min. Stiffness eig. > 0' low = 'Min. Stiffness eig. < 0' row = ['Dynamical (stiffness)', {'value': dynstab.upper(), 'description': f"LOW: {low}\nHIGH: {high}"}] summary = {'title': 'Summary', 'columns': [[{'type': 'table', 'header': ['Stability', 'Category'], 'rows': [row], }]], 'sort': 3} return [panel, summary]
[docs] @prepare_result class Result(ASRResult): c_11: float c_12: float c_13: float c_14: float c_15: float c_16: float c_21: float c_22: float c_23: float c_24: float c_25: float c_26: float c_31: float c_32: float c_33: float c_34: float c_35: float c_36: float c_41: float c_42: float c_43: float c_44: float c_45: float c_46: float c_51: float c_52: float c_53: float c_54: float c_55: float c_56: float c_61: float c_62: float c_63: float c_64: float c_65: float c_66: float __links__: typing.List[str] stiffness_tensor: typing.List[typing.List[float]] eigenvalues: typing.List[complex] dynamic_stability_stiffness: str speed_of_sound_x: float speed_of_sound_y: float key_descriptions = { "c_11": "Stiffness tensor 11-component.", "c_12": "Stiffness tensor 12-component.", "c_13": "Stiffness tensor 13-component.", "c_14": "Stiffness tensor 14-component.", "c_15": "Stiffness tensor 15-component.", "c_16": "Stiffness tensor 16-component.", "c_21": "Stiffness tensor 21-component.", "c_22": "Stiffness tensor 22-component.", "c_23": "Stiffness tensor 23-component.", "c_24": "Stiffness tensor 24-component.", "c_25": "Stiffness tensor 25-component.", "c_26": "Stiffness tensor 26-component.", "c_31": "Stiffness tensor 31-component.", "c_32": "Stiffness tensor 32-component.", "c_33": "Stiffness tensor 33-component.", "c_34": "Stiffness tensor 34-component.", "c_35": "Stiffness tensor 35-component.", "c_36": "Stiffness tensor 36-component.", "c_41": "Stiffness tensor 41-component.", "c_42": "Stiffness tensor 42-component.", "c_43": "Stiffness tensor 43-component.", "c_44": "Stiffness tensor 44-component.", "c_45": "Stiffness tensor 45-component.", "c_46": "Stiffness tensor 46-component.", "c_51": "Stiffness tensor 51-component.", "c_52": "Stiffness tensor 52-component.", "c_53": "Stiffness tensor 53-component.", "c_54": "Stiffness tensor 54-component.", "c_55": "Stiffness tensor 55-component.", "c_56": "Stiffness tensor 56-component.", "c_61": "Stiffness tensor 61-component.", "c_62": "Stiffness tensor 62-component.", "c_63": "Stiffness tensor 63-component.", "c_64": "Stiffness tensor 64-component.", "c_65": "Stiffness tensor 65-component.", "c_66": "Stiffness tensor 66-component.", "eigenvalues": "Stiffness tensor eigenvalues.", "speed_of_sound_x": "Speed of sound (x) [m/s]", "speed_of_sound_y": "Speed of sound (y) [m/s]", "stiffness_tensor": "Stiffness tensor [`N/m^{dim-1}`]", "dynamic_stability_stiffness": "Stiffness dynamic stability (low/high)", "__links__": "UIDs to strained folders." } formats = {"ase_webpanel": webpanel}
@command(module='asr.stiffness', returns=Result) @option('--strain-percent', help='Magnitude of applied strain.', type=float) def main(strain_percent: float = 1.0) -> Result: """Calculate stiffness tensor.""" from asr.setup.strains import main as setupstrains from asr.setup.strains import get_relevant_strains, get_strained_folder_name from asr.relax import main as relax from ase.io import read from ase.units import J from asr.core import read_json, chdir from asr.database.material_fingerprint import main as computemf import numpy as np if not setupstrains.done: setupstrains(strain_percent=strain_percent) atoms = read('structure.json') ij = get_relevant_strains(atoms.pbc) ij_to_voigt = [[0, 5, 4], [5, 1, 3], [4, 3, 2]] links = {} stiffness = np.zeros((6, 6), float) for i, j in ij: dstress = np.zeros((6,), float) for sign in [-1, 1]: folder = get_strained_folder_name(sign * strain_percent, i, j) with chdir(folder): if not relax.done: relax() if not computemf.done: computemf() mf = read_json(folder / ('results-asr.database.' 'material_fingerprint.json')) links[str(folder)] = mf['uid'] structurefile = folder / 'structure.json' structure = read(str(structurefile)) # The structure already has the stress if it was # calculated stress = structure.get_stress(voigt=True) dstress += stress * sign stiffness[:, ij_to_voigt[i][j]] = dstress / (strain_percent * 0.02) stiffness = np.array(stiffness, float) # We work with Mandel notation which is conventional and convenient stiffness[3:, :] *= 2**0.5 stiffness[:, 3:] *= 2**0.5 # Convert the stiffness tensor from [eV/Ang^3] -> [J/m^3]=[N/m^2] stiffness *= 10**30 / J # Now do some post processing data = {} nd = np.sum(atoms.pbc) speed_of_sound_x = None speed_of_sound_y = None if nd == 2: cell = atoms.get_cell() # We have to normalize with the supercell size z = cell[2, 2] stiffness = stiffness[[0, 1, 5], :][:, [0, 1, 5]] * z * 1e-10 from ase.units import kg from ase.units import m as meter area = atoms.get_volume() / cell[2, 2] mass = sum(atoms.get_masses()) area_density = (mass / kg) / (area / meter**2) # speed of sound in m/s speed_of_sound_x = np.sqrt(stiffness[0, 0] / area_density) speed_of_sound_y = np.sqrt(stiffness[1, 1] / area_density) elif nd == 1: cell = atoms.get_cell() area = atoms.get_volume() / cell[2, 2] stiffness = stiffness[[2], :][:, [2]] * area * 1e-20 # typical values for 1D are of the order of 10^(-10) N elif nd == 0: raise RuntimeError('Cannot compute stiffness tensor of 0D material.') data['speed_of_sound_x'] = speed_of_sound_x data['speed_of_sound_y'] = speed_of_sound_y for i in range(6): for j in range(6): data[f'c_{i + 1}{j + 1}'] = None stiffness_shape = stiffness.shape for i in range(stiffness_shape[0]): for j in range(stiffness_shape[1]): data[f'c_{i + 1}{j + 1}'] = stiffness[i, j] data['__links__'] = links data['stiffness_tensor'] = stiffness if nd == 1: eigs = stiffness else: eigs = np.linalg.eigvals(stiffness) data['eigenvalues'] = eigs dynamic_stability_stiffness = ['low', 'high'][int(eigs.min() > 0)] data['dynamic_stability_stiffness'] = dynamic_stability_stiffness return data if __name__ == '__main__': main.cli()