Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduplicate elastic #166

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions atomistics/shared/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,6 @@ class OutputEnergyVolumeCurve(
volume: callable


@dataclasses.dataclass
class OutputElastic(Output):
elastic_matrix: callable
elastic_matrix_inverse: callable
bulkmodul_voigt: callable
bulkmodul_reuss: callable
bulkmodul_hill: callable
shearmodul_voigt: callable
shearmodul_reuss: callable
shearmodul_hill: callable
youngsmodul_voigt: callable
youngsmodul_reuss: callable
youngsmodul_hill: callable
poissonsratio_voigt: callable
poissonsratio_reuss: callable
poissonsratio_hill: callable
AVR: callable
elastic_matrix_eigval: callable
Comment on lines -80 to -97
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While currently only the ElasticMatrix implements the calculation of the elastic moduli, @samwaseda developed the ElasticTensor class which can also calculate the elastic moduli. https://github.com/pyiron/pyiron_atomistics/blob/main/pyiron_atomistics/atomistics/master/elastic.py So I would prefer to have a reference interface for the elastic moduli defined in shared/output and a specific implementation in the workflows/elastic/workflow.py module.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to make it specific now anyhow, then introduce a shared parent if and when failing to do so would result in code duplication or a lack of clarity about the relationship between the two approaches.



@dataclasses.dataclass
class OutputPhonons(Output):
mesh_dict: callable
Expand Down
178 changes: 87 additions & 91 deletions atomistics/workflows/elastic/elastic_moduli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from functools import cached_property

import numpy as np

from atomistics.shared.output import Output


def get_bulkmodul_voigt(elastic_matrix):
def get_bulkmodul_voigt(elastic_matrix) -> float:
return (
elastic_matrix[0, 0]
+ elastic_matrix[1, 1]
Expand All @@ -10,27 +14,27 @@ def get_bulkmodul_voigt(elastic_matrix):
) / 9


def get_shearmodul_voigt(elastic_matrix):
def get_shearmodul_voigt(elastic_matrix) -> float:
return (
(elastic_matrix[0, 0] + elastic_matrix[1, 1] + elastic_matrix[2, 2])
- (elastic_matrix[0, 1] + elastic_matrix[0, 2] + elastic_matrix[1, 2])
+ 3 * (elastic_matrix[3, 3] + elastic_matrix[4, 4] + elastic_matrix[5, 5])
) / 15


def get_youngsmodul_voigt(bulkmodul_voigt, shearmodul_voigt):
def get_youngsmodul_voigt(bulkmodul_voigt, shearmodul_voigt) -> float:
return (9 * bulkmodul_voigt * shearmodul_voigt) / (
3 * bulkmodul_voigt + shearmodul_voigt
)


def get_poissonsratio_voigt(bulkmodul_voigt, shearmodul_voigt):
def get_poissonsratio_voigt(bulkmodul_voigt, shearmodul_voigt) -> float:
return (1.5 * bulkmodul_voigt - shearmodul_voigt) / (
3 * bulkmodul_voigt + shearmodul_voigt
)


def get_bulkmodul_reuss(elastic_matrix_inverse):
def get_bulkmodul_reuss(elastic_matrix_inverse) -> float:
return 1 / (
elastic_matrix_inverse[0, 0]
+ elastic_matrix_inverse[1, 1]
Expand All @@ -44,7 +48,7 @@ def get_bulkmodul_reuss(elastic_matrix_inverse):
)


def get_shearmodul_reuss(elastic_matrix_inverse):
def get_shearmodul_reuss(elastic_matrix_inverse) -> float:
return 15 / (
4
* (
Expand All @@ -67,164 +71,156 @@ def get_shearmodul_reuss(elastic_matrix_inverse):
)


def get_youngsmodul_reuss(bulkmodul_reuss, shearmodul_reuss):
def get_youngsmodul_reuss(bulkmodul_reuss, shearmodul_reuss) -> float:
return (9 * bulkmodul_reuss * shearmodul_reuss) / (
3 * bulkmodul_reuss + shearmodul_reuss
)


def get_poissonsratio_reuss(bulkmodul_reuss, shearmodul_reuss):
def get_poissonsratio_reuss(bulkmodul_reuss, shearmodul_reuss) -> float:
return (1.5 * bulkmodul_reuss - shearmodul_reuss) / (
3 * bulkmodul_reuss + shearmodul_reuss
)


def get_bulkmodul_hill(bulkmodul_voigt, bulkmodul_reuss):
def get_bulkmodul_hill(bulkmodul_voigt, bulkmodul_reuss) -> float:
return _hill_approximation(voigt=bulkmodul_voigt, reuss=bulkmodul_reuss)


def get_shearmodul_hill(shearmodul_voigt, shearmodul_reuss):
def get_shearmodul_hill(shearmodul_voigt, shearmodul_reuss) -> float:
return _hill_approximation(voigt=shearmodul_voigt, reuss=shearmodul_reuss)


def get_youngsmodul_hill(bulkmodul_hill, shearmodul_hill):
def get_youngsmodul_hill(bulkmodul_hill, shearmodul_hill) -> float:
return (9.0 * bulkmodul_hill * shearmodul_hill) / (
3.0 * bulkmodul_hill + shearmodul_hill
)


def get_poissonsratio_hill(bulkmodul_hill, shearmodul_hill):
def get_poissonsratio_hill(bulkmodul_hill, shearmodul_hill) -> float:
return (1.5 * bulkmodul_hill - shearmodul_hill) / (
3.0 * bulkmodul_hill + shearmodul_hill
)


def get_AVR(shearmodul_voigt, shearmodul_reuss):
def get_AVR(shearmodul_voigt, shearmodul_reuss) -> float:
return (
100.0
* (shearmodul_voigt - shearmodul_reuss)
/ (shearmodul_voigt + shearmodul_reuss)
)


def get_elastic_matrix_eigval(elastic_matrix):
def get_elastic_matrix_eigval(elastic_matrix) -> tuple[np.ndarray, np.ndarray]:
return np.linalg.eig(elastic_matrix)


def get_elastic_matrix_inverse(elastic_matrix):
def get_elastic_matrix_inverse(elastic_matrix) -> np.ndarray:
return np.linalg.inv(elastic_matrix)


def _hill_approximation(voigt, reuss):
return 0.50 * (voigt + reuss)


class ElasticProperties:
def __init__(self, elastic_matrix):
class OutputElastic(Output):
def __init__(self, elastic_matrix: np.ndarray):
self._elastic_matrix = elastic_matrix
self._elastic_matrix_inverse = None
self._bulkmodul_voigt = None
self._shearmodul_voigt = None
self._bulkmodul_reuss = None
self._shearmodul_reuss = None
self._bulkmodul_hill = None
self._shearmodul_hill = None

def get_elastic_matrix(self):

@property
def elastic_matrix(self):
return self._elastic_matrix

def get_elastic_matrix_inverse(self):
if self._elastic_matrix_inverse is None:
self._elastic_matrix_inverse = get_elastic_matrix_inverse(
elastic_matrix=self._elastic_matrix
)
return self._elastic_matrix_inverse
@cached_property
def elastic_matrix_inverse(self):
return get_elastic_matrix_inverse(elastic_matrix=self.elastic_matrix)

def get_bulkmodul_voigt(self):
if self._bulkmodul_voigt is None:
self._bulkmodul_voigt = get_bulkmodul_voigt(
elastic_matrix=self._elastic_matrix
)
return self._bulkmodul_voigt
@cached_property
def bulkmodul_voigt(self):
return get_bulkmodul_voigt(elastic_matrix=self.elastic_matrix)

def get_shearmodul_voigt(self):
if self._shearmodul_voigt is None:
self._shearmodul_voigt = get_shearmodul_voigt(
elastic_matrix=self._elastic_matrix
)
return self._shearmodul_voigt
@cached_property
def shearmodul_voigt(self):
return get_shearmodul_voigt(elastic_matrix=self.elastic_matrix)

def get_bulkmodul_reuss(self):
if self._bulkmodul_reuss is None:
self._bulkmodul_reuss = get_bulkmodul_reuss(
elastic_matrix_inverse=self.get_elastic_matrix_inverse()
)
return self._bulkmodul_reuss
@cached_property
def bulkmodul_reuss(self):
return get_bulkmodul_reuss(elastic_matrix_inverse=self.elastic_matrix_inverse)

def get_shearmodul_reuss(self):
if self._shearmodul_reuss is None:
self._shearmodul_reuss = get_shearmodul_reuss(
elastic_matrix_inverse=self.get_elastic_matrix_inverse()
)
return self._shearmodul_reuss
@cached_property
def shearmodul_reuss(self):
return get_shearmodul_reuss(elastic_matrix_inverse=self.elastic_matrix_inverse)

def get_bulkmodul_hill(self):
if self._bulkmodul_hill is None:
self._bulkmodul_hill = get_bulkmodul_hill(
bulkmodul_voigt=self.get_bulkmodul_voigt(),
bulkmodul_reuss=self.get_bulkmodul_reuss(),
@cached_property
def bulkmodul_hill(self):
return get_bulkmodul_hill(
bulkmodul_voigt=self.bulkmodul_voigt,
bulkmodul_reuss=self.bulkmodul_reuss,
)
return self._bulkmodul_hill

def get_shearmodul_hill(self):
if self._shearmodul_hill is None:
self._shearmodul_hill = get_shearmodul_hill(
shearmodul_voigt=self.get_shearmodul_voigt(),
shearmodul_reuss=self.get_shearmodul_reuss(),
@cached_property
def shearmodul_hill(self):
return get_shearmodul_hill(
shearmodul_voigt=self.shearmodul_voigt,
shearmodul_reuss=self.shearmodul_reuss,
)
return self._shearmodul_hill

def get_youngsmodul_voigt(self):
@cached_property
def youngsmodul_voigt(self):
return get_youngsmodul_voigt(
bulkmodul_voigt=self.get_bulkmodul_voigt(),
shearmodul_voigt=self.get_shearmodul_voigt(),
bulkmodul_voigt=self.bulkmodul_voigt,
shearmodul_voigt=self.shearmodul_voigt,
)

def get_poissonsratio_voigt(self):
@cached_property
def poissonsratio_voigt(self):
return get_poissonsratio_voigt(
bulkmodul_voigt=self.get_bulkmodul_voigt(),
shearmodul_voigt=self.get_shearmodul_voigt(),
bulkmodul_voigt=self.bulkmodul_voigt,
shearmodul_voigt=self.shearmodul_voigt,
)

def get_youngsmodul_reuss(self):
@cached_property
def youngsmodul_reuss(self):
return get_youngsmodul_reuss(
bulkmodul_reuss=self.get_bulkmodul_reuss(),
shearmodul_reuss=self.get_shearmodul_reuss(),
bulkmodul_reuss=self.bulkmodul_reuss,
shearmodul_reuss=self.shearmodul_reuss,
)

def get_poissonsratio_reuss(self):
@cached_property
def poissonsratio_reuss(self):
return get_poissonsratio_reuss(
bulkmodul_reuss=self.get_bulkmodul_reuss(),
shearmodul_reuss=self.get_shearmodul_reuss(),
bulkmodul_reuss=self.bulkmodul_reuss,
shearmodul_reuss=self.shearmodul_reuss,
)

def get_youngsmodul_hill(self):
@cached_property
def youngsmodul_hill(self):
return get_youngsmodul_hill(
bulkmodul_hill=self.get_bulkmodul_hill(),
shearmodul_hill=self.get_shearmodul_hill(),
bulkmodul_hill=self.bulkmodul_hill,
shearmodul_hill=self.shearmodul_hill,
)

def get_poissonratio_hill(self):
@cached_property
def poissonsratio_hill(self):
return get_poissonsratio_hill(
bulkmodul_hill=self.get_bulkmodul_hill(),
shearmodul_hill=self.get_shearmodul_hill(),
bulkmodul_hill=self.bulkmodul_hill,
shearmodul_hill=self.shearmodul_hill,
)

def get_AVR(self):
@cached_property
def AVR(self):
return get_AVR(
shearmodul_voigt=self.get_shearmodul_voigt(),
shearmodul_reuss=self.get_shearmodul_reuss(),
shearmodul_voigt=self.shearmodul_voigt,
shearmodul_reuss=self.shearmodul_reuss,
)

def get_elastic_matrix_eigval(self):
return get_elastic_matrix_eigval(elastic_matrix=self._elastic_matrix)
@cached_property
def elastic_matrix_eigval(self):
return get_elastic_matrix_eigval(elastic_matrix=self.elastic_matrix)

def get(self, *output: str) -> dict:
return {q: getattr(self, q) for q in output}

@classmethod
def fields(cls):
return tuple(q for q in dir(cls) if not (q[0] == "_" or q in ["get", "fields"]))
27 changes: 2 additions & 25 deletions atomistics/workflows/elastic/workflow.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
import numpy as np

from atomistics.shared.output import OutputElastic
from atomistics.workflows.interface import Workflow
from atomistics.workflows.elastic.elastic_moduli import ElasticProperties
from atomistics.workflows.elastic.elastic_moduli import OutputElastic
from atomistics.workflows.elastic.helper import (
generate_structures_helper,
analyse_structures_helper,
)


ElasticMatrixOutputElastic = OutputElastic(
elastic_matrix=ElasticProperties.get_elastic_matrix,
elastic_matrix_inverse=ElasticProperties.get_elastic_matrix_inverse,
bulkmodul_voigt=ElasticProperties.get_bulkmodul_voigt,
bulkmodul_reuss=ElasticProperties.get_bulkmodul_reuss,
bulkmodul_hill=ElasticProperties.get_bulkmodul_hill,
shearmodul_voigt=ElasticProperties.get_shearmodul_voigt,
shearmodul_reuss=ElasticProperties.get_shearmodul_reuss,
shearmodul_hill=ElasticProperties.get_shearmodul_hill,
youngsmodul_voigt=ElasticProperties.get_youngsmodul_voigt,
youngsmodul_reuss=ElasticProperties.get_youngsmodul_reuss,
youngsmodul_hill=ElasticProperties.get_youngsmodul_hill,
poissonsratio_voigt=ElasticProperties.get_poissonsratio_voigt,
poissonsratio_reuss=ElasticProperties.get_poissonsratio_reuss,
poissonsratio_hill=ElasticProperties.get_poissonratio_hill,
AVR=ElasticProperties.get_AVR,
elastic_matrix_eigval=ElasticProperties.get_elastic_matrix_eigval,
)


class ElasticMatrixWorkflow(Workflow):
def __init__(
self, structure, num_of_point=5, eps_range=0.005, sqrt_eta=True, fit_order=2
Expand Down Expand Up @@ -81,6 +60,4 @@ def analyse_structures(self, output_dict, output=OutputElastic.fields()):
self._data["strain_energy"] = strain_energy
self._data["e0"] = ene0
self._data["A2"] = A2
return ElasticMatrixOutputElastic.get(
ElasticProperties(elastic_matrix=elastic_matrix), *output
)
return OutputElastic(elastic_matrix).get(*output)
Loading