Skip to content

Commit

Permalink
Get FC import from CASTEP 25.1 working (#364)
Browse files Browse the repository at this point in the history
- CASTEP 25.1 adds extra fields to BORN and DIELECTRIC sections of
  castep_bin file; read (and discard) this information

- It can also create a BORN section without corresponding
  DIELECTRIC (by Berry Phase calculation). That throws off some Euphonic
  logic which assumes you would only ever have BORN and DIELECTRIC data
  at the same time.

- As FC behaviour isn't really defined when you only have one, let's
  discard it in that case.
  • Loading branch information
ajjackson authored Feb 10, 2025
1 parent 48f8d11 commit 0554c1f
Show file tree
Hide file tree
Showing 8 changed files with 1,130 additions and 11 deletions.
28 changes: 23 additions & 5 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
`Unreleased <https://github.com/pace-neutrons/Euphonic/compare/v1.4.0.post1...HEAD>`_
-------------------------------------------------------------------------------------

- The euphonic.spectra module has been broken up into a subpackage
with the single-spectrum classes defined in euphonic.spectra.base
and the collections in euphonic.spectra.collections. This is not a
breaking change: the public classes, functions and type annotations
remain importable from euphonic.spectra.
- Bug fixes

- CASTEP 25.1 allows Born effective charges to be calculated by
Berry Phase methods without a corresponding dielectric tensor. In
such cases, no long-range term can be subtracted from the Force
Constants (or reconstructed). Euphonic uses the presence of Born
effective charges to indicate such a subtraction; to prevent
ill-defined cases, ForceConstants now sets both Born charges and
dielectric tensor to None if only one was provided.

- Maintenance

- The euphonic.spectra module has been broken up into a subpackage
with the single-spectrum classes defined in euphonic.spectra.base
and the collections in euphonic.spectra.collections. This is not a
breaking change: the public classes, functions and type annotations
remain importable from euphonic.spectra.

- CASTEP 25.1 includes an extra field in .castep_bin files,
indicating whether Born effective charges were read from an
external file. For clarity and safety, this field is now
explicitly read by the Euphonic .castep_bin parser, but remains unused.


- Bug fixes

Expand Down
8 changes: 4 additions & 4 deletions euphonic/force_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,16 @@ def __init__(self, crystal: Crystal, force_constants: Quantity,
self.cell_origins = cell_origins
self.n_cells_in_sc = n_sc

if born is not None:
if born is not None and dielectric is not None:
self._born = born.to(ureg.e).magnitude
self.born_unit = str(born.units)
self._dielectric = dielectric.to(ureg(
'e**2/(bohr*hartree)')).magnitude
self.dielectric_unit = str(dielectric.units)
else:
self._born = born
self._born = None
self.born_unit = str(ureg.e)
self._dielectric = dielectric
self._dielectric = None
self.dielectric_unit = str(ureg((
'e**2/(bohr*hartree)')))

Expand Down Expand Up @@ -473,7 +473,7 @@ def _calculate_phonons_at_qpts(
[weights], [[np.ndarray, type(None)]], [(len(qpts),)], ['weights'])

# Set default splitting params
if self.born is None:
if self.born is None or self.dielectric is None:
dipole = False
if not dipole:
splitting = False
Expand Down
13 changes: 12 additions & 1 deletion euphonic/readers/castep.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,9 +491,19 @@ def read_interpolation_data(
elif header == b'BORN_CHGS':
born = np.reshape(
_read_entry(f, float_type), (n_atoms, 3, 3))

if castep_version > Version("25.1"):
# Extra field marks if born charges were read from BORN
_ = _read_entry(f)

elif header == b'DIELECTRIC':
entry = _read_entry(f, float_type)
dielectric = np.transpose(np.reshape(
_read_entry(f, float_type), (3, 3)))
entry, (3, 3)))

if castep_version > Version("25.1"):
# Extra field marks if dielectric tensor was read from BORN
_ = _read_entry(f)

data_dict: Dict[str, Any] = {}
cry_dict = data_dict['crystal'] = {}
Expand Down Expand Up @@ -528,6 +538,7 @@ def read_interpolation_data(
data_dict['dielectric'] = dielectric*ureg(
'e**2/(hartree*bohr)').to(dielectric_unit).magnitude
data_dict['dielectric_unit'] = dielectric_unit

except UnboundLocalError:
pass

Expand Down
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 0554c1f

Please sign in to comment.