Skip to content

structure

Class and routines for storing and working with crystal structures.

Structure

Source code in lib/phonopy_spectroscopy/structure.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
class Structure:
    def __init__(
        self,
        latt_vecs,
        at_pos,
        at_typ,
        at_m=None,
        conv_trans=None,
        cart_to_frac=False,
    ):
        """Create a new instance of the `Structure` class.

        Parameters
        ----------
        latt_vecs : array_like
            Lattice vectors (shape: `(3, 3)`).
        at_pos : array_like
            Atomic positions (shape: `(N, 3)`).
        at_typ : array_like
            Atom types (shape: `(N,)`).
        at_m : array_like, optional
            Atomic masses (optional, shape: `(N,)`).
        conv_trans : array_like, optional
            Specifies a transformation to the conventonal unit cell
            (default: identity matrix).
        cart_to_frac : bool, optional
            If `True`, convert `at_pos` from Cartesian to fractional
            coordinates (default: `False`).
        """

        latt_vecs = np_asarray_copy(latt_vecs, dtype=np.float64)

        if not np_check_shape(latt_vecs, (3, 3)):
            raise ValueError(
                "latt_vecs must be an array_like with shape (3, 3)."
            )

        at_pos = np_asarray_copy(at_pos, dtype=np.float64)
        at_typ = np.array([str(typ) for typ in at_typ], dtype=object)

        if len(at_pos) > 0 and not np_check_shape(at_pos, (None, 3)):
            raise ValueError("at_pos must be an array_like with shape (N, 3).")

        n_a = len(at_pos)

        if not np_check_shape(at_typ, (n_a,)):
            raise ValueError("at_typ must be an array_like with shape (N,).")

        if at_m is None:
            at_m = np.array(
                [lookup_atomic_mass(sym) for sym in at_typ], dtype=np.float64
            )

            if (at_m <= 0.0).any():
                warnings.warn(
                    "Atomic mass lookup returned m <= 0 for one or "
                    "more atoms. The atomic masses likely need to be "
                    "specified explicitly with the at_m keyword.",
                    RuntimeWarning,
                )
        else:
            at_m = np_asarray_copy(at_m, dtype=np.float64)

            if not np_check_shape(at_m, (n_a,)):
                raise ValueError(
                    "If supplied, at_m must be an array_like with shape (N,)."
                )

        if (at_m <= 0.0).any():
            raise ValueError("Atomic masses must be larger than zero.")

        if conv_trans is not None:
            conv_trans = np_asarray_copy(conv_trans, dtype=np.float64)

            if not np_check_shape(conv_trans, (3, 3)):
                raise ValueError(
                    "If supplied, prim_trans must be an array_like "
                    "with shape (3, 3)."
                )

            # A valid transformation matrix to a conventional cell
            # should have integer elements, although this may not be
            # the case if the matrix has not been specified with
            # sufficient precision.

            abs_diff = np.abs(np.rint(conv_trans) - conv_trans)

            if (abs_diff > ZERO_TOLERANCE).any():
                warnings.warn(
                    "One or more elements in conv_trans deviates from "
                    "integer values by up to {0:.3e}. This could "
                    "indicate an invalid tranformation matrix or "
                    "insufficient precision.".format(abs_diff.max()),
                    UserWarning,
                )
        else:
            conv_trans = np.identity(3, dtype=np.float64)

        latt_vecs_conv = np.dot(conv_trans, latt_vecs)

        if n_a > 0:
            if cart_to_frac:
                at_pos = cartesian_to_fractional_coordinates(at_pos, latt_vecs)
            else:
                if (np.abs(at_pos) > 1.0).any():
                    warnings.warn(
                        "One or more of at_pos are outside the range "
                        "[-1, 1] expected for fractional coordinates - "
                        "use cart_to_frac=True to convert if needed.",
                        UserWarning,
                    )

        self._v_latt = latt_vecs
        self._v_latt_conv = latt_vecs_conv

        self._at_pos = at_pos
        self._at_typ = at_typ
        self._at_m = at_m

        self._conv_trans = conv_trans

    @property
    def lattice_vectors(self):
        """numpy.ndarray : Lattice vectors (shape: `(3, 3)`)."""
        return np_readonly_view(self._v_latt)

    @property
    def primitive_lattice_vectors(self):
        """numpy.ndarray : Lattive vectors of the primitive cell
        (shape: `(3, 3)`, alias for `lattice_vectors`."""
        return self.lattice_vectors

    @property
    def conventional_lattice_vectors(self):
        """numpy.ndarray : Lattive vectors of the conventional cell
        (shape: `(3, 3)`."""
        return np_readonly_view(self._v_latt_conv)

    @property
    def atom_positions(self):
        """numpy.ndarray : Atomic positions (shape: `(N, 3)`)."""
        return np_readonly_view(self._at_pos)

    @property
    def atom_types(self):
        """numpy.ndarray : Atom types (shape: `(N,)`)."""
        return np_readonly_view(self._at_typ)

    @property
    def atomic_masses(self):
        """numpy.ndarray : Atomic masses (shape: `(N,)`)."""
        return np_readonly_view(self._at_m)

    @property
    def conventional_transformation_matrix(self):
        """numpy.ndarray : Transformation matrix to convert the
        structure to its conventional cell."""
        return np_readonly_view(self._conv_trans)

    @property
    def num_atoms(self):
        """int : Number of atoms in the structure."""
        return self._at_pos.shape[0]

    def volume(self, conv=False):
        """Calculate the unit-cell volume.

        Parameters
        ----------
        conv : bool, optional
            If `True`, return the volume of the conventional unit cell
            (default: `False`).

        Returns
        -------
        v : float
            Unit-cell volume.
        """

        v_1, v_2, v_3 = self._v_latt_conv if conv else self._v_latt
        return np.dot(v_1, np.cross(v_2, v_3))

    def reciprocal_lattice_vectors(self, conv=False):
        """Calculate and return the reciprocal lattice vectors.

        Parameters
        ----------
        conv : bool, optional
            If `True`, return the volume of the conventional unit cell
            (default: `False`).

        Returns
        -------
        recip_latt_vec : numpy.ndarray
            Recipocal lattice vectors (shape: `(3, 3)`).
        """

        a_1, a_2, a_3 = self._v_latt_conv if conv else self._v_latt
        v = self.volume(conv=conv)

        return np.array(
            [
                np.cross(a_2, a_3) / v,
                np.cross(a_3, a_1) / v,
                np.cross(a_1, a_2) / v,
            ],
            dtype=np.float64,
        )

    def real_space_normal(self, hkl, conv=False):
        """Calculate the real-space normal to the surface with Miller
        index `hkl`.

        Parameters
        ----------
        hkl : array_like
            Integer Miller indices of the surface (shape: `(3,)`).,
        conv : bool, optional
            If `True`, return the volume of the conventional unit cell
            (default: `False`).

        Returns
        -------
        norm : numpy.ndarray
            Real-space sufrace normal in Cartesian coordinates (shape:
            `(3,)`).
        """

        hkl = np.asarray(hkl)

        if not np_check_shape(hkl, (3,)):
            raise ValueError("hkl must be an array_like with shape `(3,)`.")

        b_1, b_2, b_3 = self.reciprocal_lattice_vectors(conv=conv)

        # Use the reciprocal metric tensor to obtain the real-space
        # normal in fractional coordinates.

        recip_metric = np.array(
            [
                [np.dot(b_1, b_1), np.dot(b_1, b_2), np.dot(b_1, b_3)],
                [np.dot(b_2, b_1), np.dot(b_2, b_2), np.dot(b_2, b_3)],
                [np.dot(b_3, b_1), np.dot(b_3, b_2), np.dot(b_3, b_3)],
            ]
        )

        norm_frac = np.dot(recip_metric, hkl)

        norm_cart = fractional_to_cartesian_coordinates(
            norm_frac, self._v_latt_conv if conv else self._v_latt
        )

        return norm_cart / np.linalg.norm(norm_cart)

    def cartesian_positions(self):
        """Return the atomic positions converted to Cartesian
        coordinates.

        Returns
        -------
        pos_cart : numpy.ndarray
            Atom positions in Cartesian coordinates (shape: `(N, 3)`).
        """

        return fractional_to_cartesian_coordinates(self._at_pos, self._v_latt)

    def to_phonopy_atoms(self):
        """Return the structure as a `PhonopyAtoms` instance.

        Returns
        -------
        atoms : PhonopyAtoms
            `PhonopyAtoms` object containing the structure data.

        Notes
        -----
        This function requires the `phonopy` package.
        """

        if not _PHONOPY_AVAILABLE:
            raise RuntimeError(
                "Structure.to_phonopy_atoms() requires the "
                "phonopy.structure.PhonopyAtoms class."
            )

        # The phonopy API uses the idiom "if x" to detect when a
        # parameter x is set, which raises if x is a NumPy array with
        # more than one element.

        return PhonopyAtoms(
            cell=self.lattice_vectors.tolist(),
            scaled_positions=self.atom_positions.tolist(),
            symbols=self.atom_types.tolist(),
            masses=self.atomic_masses.tolist(),
        )

    def to_dict(self):
        """Return the internal data as a dictionary of native Python
        types for serialisation.

        Returns
        -------
        d : dict
            Dictionary structure containing internal data as native
            Python types.
        """

        return {
            "lattice_vectors": self._v_latt.tolist(),
            "atom_positions": self._at_pos.tolist(),
            "atom_types": list(self._at_typ),
            "atomic_masses": self._at_m.tolist(),
            "conventional_transformation_matrix": self._conv_trans.tolist(),
        }

    @staticmethod
    def from_dict(d):
        """Create a new `Structure` instance from a dictionary
        generated by `Structure.to_dict()`.

        Parameters
        ----------
        d : dict
            Dictionary generated by `to_dict()`.

        Returns
        -------
        struct : Structure
            `Structure` object constructed from the data in `d`.
        """

        return Structure(
            d["lattice_vectors"],
            d["atom_positions"],
            d["atom_types"],
            at_m=d["atomic_masses"],
            conv_trans=d["conventional_transformation_matrix"],
        )

atom_positions property

numpy.ndarray : Atomic positions (shape: (N, 3)).

atom_types property

numpy.ndarray : Atom types (shape: (N,)).

atomic_masses property

numpy.ndarray : Atomic masses (shape: (N,)).

conventional_lattice_vectors property

numpy.ndarray : Lattive vectors of the conventional cell (shape: (3, 3).

conventional_transformation_matrix property

numpy.ndarray : Transformation matrix to convert the structure to its conventional cell.

lattice_vectors property

numpy.ndarray : Lattice vectors (shape: (3, 3)).

num_atoms property

int : Number of atoms in the structure.

primitive_lattice_vectors property

numpy.ndarray : Lattive vectors of the primitive cell (shape: (3, 3), alias for lattice_vectors.

__init__(latt_vecs, at_pos, at_typ, at_m=None, conv_trans=None, cart_to_frac=False)

Create a new instance of the Structure class.

Parameters

latt_vecs : array_like Lattice vectors (shape: (3, 3)). at_pos : array_like Atomic positions (shape: (N, 3)). at_typ : array_like Atom types (shape: (N,)). at_m : array_like, optional Atomic masses (optional, shape: (N,)). conv_trans : array_like, optional Specifies a transformation to the conventonal unit cell (default: identity matrix). cart_to_frac : bool, optional If True, convert at_pos from Cartesian to fractional coordinates (default: False).

Source code in lib/phonopy_spectroscopy/structure.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
def __init__(
    self,
    latt_vecs,
    at_pos,
    at_typ,
    at_m=None,
    conv_trans=None,
    cart_to_frac=False,
):
    """Create a new instance of the `Structure` class.

    Parameters
    ----------
    latt_vecs : array_like
        Lattice vectors (shape: `(3, 3)`).
    at_pos : array_like
        Atomic positions (shape: `(N, 3)`).
    at_typ : array_like
        Atom types (shape: `(N,)`).
    at_m : array_like, optional
        Atomic masses (optional, shape: `(N,)`).
    conv_trans : array_like, optional
        Specifies a transformation to the conventonal unit cell
        (default: identity matrix).
    cart_to_frac : bool, optional
        If `True`, convert `at_pos` from Cartesian to fractional
        coordinates (default: `False`).
    """

    latt_vecs = np_asarray_copy(latt_vecs, dtype=np.float64)

    if not np_check_shape(latt_vecs, (3, 3)):
        raise ValueError(
            "latt_vecs must be an array_like with shape (3, 3)."
        )

    at_pos = np_asarray_copy(at_pos, dtype=np.float64)
    at_typ = np.array([str(typ) for typ in at_typ], dtype=object)

    if len(at_pos) > 0 and not np_check_shape(at_pos, (None, 3)):
        raise ValueError("at_pos must be an array_like with shape (N, 3).")

    n_a = len(at_pos)

    if not np_check_shape(at_typ, (n_a,)):
        raise ValueError("at_typ must be an array_like with shape (N,).")

    if at_m is None:
        at_m = np.array(
            [lookup_atomic_mass(sym) for sym in at_typ], dtype=np.float64
        )

        if (at_m <= 0.0).any():
            warnings.warn(
                "Atomic mass lookup returned m <= 0 for one or "
                "more atoms. The atomic masses likely need to be "
                "specified explicitly with the at_m keyword.",
                RuntimeWarning,
            )
    else:
        at_m = np_asarray_copy(at_m, dtype=np.float64)

        if not np_check_shape(at_m, (n_a,)):
            raise ValueError(
                "If supplied, at_m must be an array_like with shape (N,)."
            )

    if (at_m <= 0.0).any():
        raise ValueError("Atomic masses must be larger than zero.")

    if conv_trans is not None:
        conv_trans = np_asarray_copy(conv_trans, dtype=np.float64)

        if not np_check_shape(conv_trans, (3, 3)):
            raise ValueError(
                "If supplied, prim_trans must be an array_like "
                "with shape (3, 3)."
            )

        # A valid transformation matrix to a conventional cell
        # should have integer elements, although this may not be
        # the case if the matrix has not been specified with
        # sufficient precision.

        abs_diff = np.abs(np.rint(conv_trans) - conv_trans)

        if (abs_diff > ZERO_TOLERANCE).any():
            warnings.warn(
                "One or more elements in conv_trans deviates from "
                "integer values by up to {0:.3e}. This could "
                "indicate an invalid tranformation matrix or "
                "insufficient precision.".format(abs_diff.max()),
                UserWarning,
            )
    else:
        conv_trans = np.identity(3, dtype=np.float64)

    latt_vecs_conv = np.dot(conv_trans, latt_vecs)

    if n_a > 0:
        if cart_to_frac:
            at_pos = cartesian_to_fractional_coordinates(at_pos, latt_vecs)
        else:
            if (np.abs(at_pos) > 1.0).any():
                warnings.warn(
                    "One or more of at_pos are outside the range "
                    "[-1, 1] expected for fractional coordinates - "
                    "use cart_to_frac=True to convert if needed.",
                    UserWarning,
                )

    self._v_latt = latt_vecs
    self._v_latt_conv = latt_vecs_conv

    self._at_pos = at_pos
    self._at_typ = at_typ
    self._at_m = at_m

    self._conv_trans = conv_trans

cartesian_positions()

Return the atomic positions converted to Cartesian coordinates.

Returns

pos_cart : numpy.ndarray Atom positions in Cartesian coordinates (shape: (N, 3)).

Source code in lib/phonopy_spectroscopy/structure.py
411
412
413
414
415
416
417
418
419
420
421
def cartesian_positions(self):
    """Return the atomic positions converted to Cartesian
    coordinates.

    Returns
    -------
    pos_cart : numpy.ndarray
        Atom positions in Cartesian coordinates (shape: `(N, 3)`).
    """

    return fractional_to_cartesian_coordinates(self._at_pos, self._v_latt)

from_dict(d) staticmethod

Create a new Structure instance from a dictionary generated by Structure.to_dict().

Parameters

d : dict Dictionary generated by to_dict().

Returns

struct : Structure Structure object constructed from the data in d.

Source code in lib/phonopy_spectroscopy/structure.py
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
@staticmethod
def from_dict(d):
    """Create a new `Structure` instance from a dictionary
    generated by `Structure.to_dict()`.

    Parameters
    ----------
    d : dict
        Dictionary generated by `to_dict()`.

    Returns
    -------
    struct : Structure
        `Structure` object constructed from the data in `d`.
    """

    return Structure(
        d["lattice_vectors"],
        d["atom_positions"],
        d["atom_types"],
        at_m=d["atomic_masses"],
        conv_trans=d["conventional_transformation_matrix"],
    )

real_space_normal(hkl, conv=False)

Calculate the real-space normal to the surface with Miller index hkl.

Parameters

hkl : array_like Integer Miller indices of the surface (shape: (3,))., conv : bool, optional If True, return the volume of the conventional unit cell (default: False).

Returns

norm : numpy.ndarray Real-space sufrace normal in Cartesian coordinates (shape: (3,)).

Source code in lib/phonopy_spectroscopy/structure.py
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
def real_space_normal(self, hkl, conv=False):
    """Calculate the real-space normal to the surface with Miller
    index `hkl`.

    Parameters
    ----------
    hkl : array_like
        Integer Miller indices of the surface (shape: `(3,)`).,
    conv : bool, optional
        If `True`, return the volume of the conventional unit cell
        (default: `False`).

    Returns
    -------
    norm : numpy.ndarray
        Real-space sufrace normal in Cartesian coordinates (shape:
        `(3,)`).
    """

    hkl = np.asarray(hkl)

    if not np_check_shape(hkl, (3,)):
        raise ValueError("hkl must be an array_like with shape `(3,)`.")

    b_1, b_2, b_3 = self.reciprocal_lattice_vectors(conv=conv)

    # Use the reciprocal metric tensor to obtain the real-space
    # normal in fractional coordinates.

    recip_metric = np.array(
        [
            [np.dot(b_1, b_1), np.dot(b_1, b_2), np.dot(b_1, b_3)],
            [np.dot(b_2, b_1), np.dot(b_2, b_2), np.dot(b_2, b_3)],
            [np.dot(b_3, b_1), np.dot(b_3, b_2), np.dot(b_3, b_3)],
        ]
    )

    norm_frac = np.dot(recip_metric, hkl)

    norm_cart = fractional_to_cartesian_coordinates(
        norm_frac, self._v_latt_conv if conv else self._v_latt
    )

    return norm_cart / np.linalg.norm(norm_cart)

reciprocal_lattice_vectors(conv=False)

Calculate and return the reciprocal lattice vectors.

Parameters

conv : bool, optional If True, return the volume of the conventional unit cell (default: False).

Returns

recip_latt_vec : numpy.ndarray Recipocal lattice vectors (shape: (3, 3)).

Source code in lib/phonopy_spectroscopy/structure.py
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
def reciprocal_lattice_vectors(self, conv=False):
    """Calculate and return the reciprocal lattice vectors.

    Parameters
    ----------
    conv : bool, optional
        If `True`, return the volume of the conventional unit cell
        (default: `False`).

    Returns
    -------
    recip_latt_vec : numpy.ndarray
        Recipocal lattice vectors (shape: `(3, 3)`).
    """

    a_1, a_2, a_3 = self._v_latt_conv if conv else self._v_latt
    v = self.volume(conv=conv)

    return np.array(
        [
            np.cross(a_2, a_3) / v,
            np.cross(a_3, a_1) / v,
            np.cross(a_1, a_2) / v,
        ],
        dtype=np.float64,
    )

to_dict()

Return the internal data as a dictionary of native Python types for serialisation.

Returns

d : dict Dictionary structure containing internal data as native Python types.

Source code in lib/phonopy_spectroscopy/structure.py
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
def to_dict(self):
    """Return the internal data as a dictionary of native Python
    types for serialisation.

    Returns
    -------
    d : dict
        Dictionary structure containing internal data as native
        Python types.
    """

    return {
        "lattice_vectors": self._v_latt.tolist(),
        "atom_positions": self._at_pos.tolist(),
        "atom_types": list(self._at_typ),
        "atomic_masses": self._at_m.tolist(),
        "conventional_transformation_matrix": self._conv_trans.tolist(),
    }

to_phonopy_atoms()

Return the structure as a PhonopyAtoms instance.

Returns

atoms : PhonopyAtoms PhonopyAtoms object containing the structure data.

Notes

This function requires the phonopy package.

Source code in lib/phonopy_spectroscopy/structure.py
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
def to_phonopy_atoms(self):
    """Return the structure as a `PhonopyAtoms` instance.

    Returns
    -------
    atoms : PhonopyAtoms
        `PhonopyAtoms` object containing the structure data.

    Notes
    -----
    This function requires the `phonopy` package.
    """

    if not _PHONOPY_AVAILABLE:
        raise RuntimeError(
            "Structure.to_phonopy_atoms() requires the "
            "phonopy.structure.PhonopyAtoms class."
        )

    # The phonopy API uses the idiom "if x" to detect when a
    # parameter x is set, which raises if x is a NumPy array with
    # more than one element.

    return PhonopyAtoms(
        cell=self.lattice_vectors.tolist(),
        scaled_positions=self.atom_positions.tolist(),
        symbols=self.atom_types.tolist(),
        masses=self.atomic_masses.tolist(),
    )

volume(conv=False)

Calculate the unit-cell volume.

Parameters

conv : bool, optional If True, return the volume of the conventional unit cell (default: False).

Returns

v : float Unit-cell volume.

Source code in lib/phonopy_spectroscopy/structure.py
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
def volume(self, conv=False):
    """Calculate the unit-cell volume.

    Parameters
    ----------
    conv : bool, optional
        If `True`, return the volume of the conventional unit cell
        (default: `False`).

    Returns
    -------
    v : float
        Unit-cell volume.
    """

    v_1, v_2, v_3 = self._v_latt_conv if conv else self._v_latt
    return np.dot(v_1, np.cross(v_2, v_3))

cartesian_to_fractional_coordinates(cart_pos, latt_vecs)

Convert positions from Cartesian to fractional coordinates.

Parameters

cart_pos : array_like Atom position or set of positions in Cartesian coordinates (shape: (3,) or (N, 3)). latt_vecs : array_like Lattice vectors (shape: (3, 3)).

Returns

frac_pos : numpy.ndarray Atom positions in fractional coordinates (same shape as cart_pos).

Source code in lib/phonopy_spectroscopy/structure.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def cartesian_to_fractional_coordinates(cart_pos, latt_vecs):
    """Convert positions from Cartesian to fractional coordinates.

    Parameters
    ----------
    cart_pos : array_like
        Atom position or set of positions in Cartesian coordinates
        (shape: `(3,)` or `(N, 3)`).
    latt_vecs : array_like
        Lattice vectors (shape: `(3, 3)`).

    Returns
    -------
    frac_pos : numpy.ndarray
        Atom positions in fractional coordinates (same shape as
        `cart_pos`).
    """

    cart_pos, n_dim_add = np_expand_dims(np.asarray(cart_pos), (None, 3))

    latt_vecs = np.asarray(latt_vecs)

    if not np_check_shape(latt_vecs, (3, 3)):
        raise ValueError("latt_vecs must be an array_like with shape (3, 3).")

    trans_mat = np.linalg.inv(latt_vecs)

    frac_pos = np.zeros_like(cart_pos)

    for i, p in enumerate(cart_pos):
        frac_pos[i] = np.dot(p, trans_mat) % 1.0

    return frac_pos if n_dim_add == 0 else frac_pos[0]

fractional_to_cartesian_coordinates(frac_pos, latt_vecs)

Convert positions from fractional to Cartesian coordinates.

Parameters

frac_pos : array_like Atom position or set of positions in fractional coordinates (shape: (3,) or (N, 3)). latt_vecs : array_like Lattice vectors (shape: (3, 3)).

Returns

cart_pos : numpy.ndarray Atom positions in Cartesian coordinates (same shape as frac_pos).

Source code in lib/phonopy_spectroscopy/structure.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def fractional_to_cartesian_coordinates(frac_pos, latt_vecs):
    """Convert positions from fractional to Cartesian coordinates.

    Parameters
    ----------
    frac_pos : array_like
        Atom position or set of positions in fractional coordinates
        (shape: `(3,)` or `(N, 3)`).
    latt_vecs : array_like
        Lattice vectors (shape: `(3, 3)`).

    Returns
    -------
    cart_pos : numpy.ndarray
        Atom positions in Cartesian coordinates (same shape as
        `frac_pos`).
    """

    frac_pos, n_dim_add = np_expand_dims(np.asarray(frac_pos), (None, 3))

    latt_vecs = np.asarray(latt_vecs)

    if not np_check_shape(latt_vecs, (3, 3)):
        raise ValueError("latt_vecs must be an array_like with shape (3, 3).")

    cart_pos = np.zeros_like(frac_pos)

    for i, p in enumerate(frac_pos):
        cart_pos[i] = np.dot(p.T, latt_vecs)

    return cart_pos if n_dim_add == 0 else cart_pos[0]

lookup_atomic_mass(symbol)

Lookup an atomic mass from an atomic symbol.

Parameters

symbol : str Atomic symbol.

Returns

m : float Atomic mass (amu).

Notes

This function requires the phonopy package.

Source code in lib/phonopy_spectroscopy/structure.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def lookup_atomic_mass(symbol):
    """Lookup an atomic mass from an atomic symbol.

    Parameters
    ----------
    symbol : str
        Atomic symbol.

    Returns
    -------
    m : float
        Atomic mass (amu).

    Notes
    -----
    This function requires the `phonopy` package.
    """

    if not _PHONOPY_AVAILABLE:
        raise RuntimeError(
            "lookup_atomic_mass() requires the "
            "phonopy.atoms.atom_data attribute."
        )

    symbol = str(symbol).title()

    for _, db_symbol, _, db_mass in atom_data:
        if symbol == db_symbol:
            return db_mass

    raise ValueError(
        'Data for symbol="{0}" not available in '
        "phonopy.atoms.atom_data.".format(symbol)
    )