Skip to content

gemdat.simulation_metrics

This module contains classes for calculating metrics and other properties from trajectories.

SimulationMetrics(trajectory)

Class for calculating different metrics and properties from a molecular dynamics simulation.

Parameters:

  • trajectory (Trajectory) –

    Input trajectory

Source code in src/gemdat/simulation_metrics.py
24
25
26
27
28
29
30
31
32
def __init__(self, trajectory: Trajectory):
    """Initialize class.

    Parameters
    ----------
    trajectory: Trajectory
        Input trajectory
    """
    self.trajectory = trajectory

amplitudes()

Calculate vibration amplitudes.

Returns:

  • amplitudes ( ndarray ) –

    Output array of vibration amplitudes

Source code in src/gemdat/simulation_metrics.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
@weak_lru_cache()
def amplitudes(self) -> np.ndarray:
    """Calculate vibration amplitudes.

    Returns
    -------
    amplitudes : np.ndarray
        Output array of vibration amplitudes
    """
    amplitudes = []
    speed = self.speed()

    for i, speed_range in enumerate(speed):
        signs = np.sign(speed_range)

        # get indices where sign flips
        splits = np.where(signs != np.roll(signs, shift=-1))[0]
        # strip first and last splits
        subarrays = np.array_split(speed_range, splits[1:-1] + 1)

        amplitudes.extend([np.sum(array) for array in subarrays])

    return np.asarray(amplitudes)

attempt_frequency()

Return attempt frequency and standard deviation in Hz.

Returns:

  • attempt_freq ( FloatWithUnit ) –

    Attempt frequency

  • attempt_freq_std ( FloatWithUnit ) –

    Attempt frequency standard deviation

Source code in src/gemdat/simulation_metrics.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
@weak_lru_cache()
def attempt_frequency(self) -> tuple[FloatWithUnit, FloatWithUnit]:
    """Return attempt frequency and standard deviation in Hz.

    Returns
    -------
    attempt_freq : FloatWithUnit
        Attempt frequency
    attempt_freq_std : FloatWithUnit
        Attempt frequency standard deviation
    """
    speed = self.speed()

    freq_mean = meanfreq(speed, fs=self.trajectory.sampling_frequency)

    attempt_freq_std = np.std(freq_mean)
    attempt_freq_std = FloatWithUnit(attempt_freq_std, 'hz')

    attempt_freq = np.mean(freq_mean)
    attempt_freq = FloatWithUnit(attempt_freq, 'hz')

    return attempt_freq, attempt_freq_std

haven_ratio(*, dimensions=3)

Calculate Haven's ratio.

Parameters:

  • dimensions (int, default: 3 ) –

    Number of diffusion dimensions

Returns:

  • haven_ratio ( float ) –
Source code in src/gemdat/simulation_metrics.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
@weak_lru_cache()
def haven_ratio(self, *, dimensions: int = 3) -> float:
    """Calculate Haven's ratio.

    Parameters
    ----------
    dimensions : int
        Number of diffusion dimensions

    Returns
    -------
    haven_ratio : float
    """
    return self.tracer_diffusivity(
        dimensions=dimensions) / self.tracer_diffusivity_center_of_mass(
            dimensions=dimensions)

mol_per_liter()

Calculate density.

Returns:

  • particle_density ( FloatWithUnit ) –

    Particle density as \(mol/l\).

Source code in src/gemdat/simulation_metrics.py
63
64
65
66
67
68
69
70
71
72
73
@weak_lru_cache()
def mol_per_liter(self) -> FloatWithUnit:
    """Calculate density.

    Returns
    -------
    particle_density : FloatWithUnit
        Particle density as $mol/l$.
    """
    mol_per_liter = (self.particle_density() * 1e-3) / Avogadro
    return FloatWithUnit(mol_per_liter, 'mol l^-1')

particle_density()

Calculate number of particles per unit of volume from trajectory.

Returns:

  • particle_density ( FloatWithUnit ) –

    Number of particles in \(m^{-3}\)

Source code in src/gemdat/simulation_metrics.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@weak_lru_cache()
def particle_density(self) -> FloatWithUnit:
    """Calculate number of particles per unit of volume from trajectory.

    Returns
    -------
    particle_density : FloatWithUnit
        Number of particles in $m^{-3}$
    """
    lattice = self.trajectory.get_lattice()
    volume_ang = lattice.volume
    volume_m3 = volume_ang * angstrom**3
    particle_density = len(self.trajectory.species) / volume_m3
    return FloatWithUnit(particle_density, 'm^-3')

speed()

Calculate speed.

Corresponds to change in distance from the base position.

Returns:

  • speed ( ndarray ) –

    Output array with speeds

Source code in src/gemdat/simulation_metrics.py
34
35
36
37
38
39
40
41
42
43
44
45
46
@weak_lru_cache()
def speed(self) -> np.ndarray:
    """Calculate speed.

    Corresponds to change in distance from the base position.

    Returns
    -------
    speed : np.ndarray
        Output array with speeds
    """
    distances = self.trajectory.distances_from_base_position()
    return np.diff(distances, prepend=0)

tracer_conductivity(*, z_ion, dimensions=3)

Return tracer conductivity as S/m.

Defined as: elementary_charge^2 * charge_ion^2 * diffusivity * particle_density / (k_B * T)

Parameters:

  • z_ion (int) –

    Charge of the ion

  • dimensions (int, default: 3 ) –

    Number of diffusion dimensions

Returns:

  • tracer_conductivity ( FloatWithUnit ) –

    Tracer conductivity in \(S/m\)

Source code in src/gemdat/simulation_metrics.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
@weak_lru_cache()
def tracer_conductivity(self,
                        *,
                        z_ion: int,
                        dimensions: int = 3) -> FloatWithUnit:
    """Return tracer conductivity as S/m.

    Defined as: elementary_charge^2 * charge_ion^2 * diffusivity *
        particle_density / (k_B * T)

    Parameters
    ----------
    z_ion : int
        Charge of the ion
    dimensions : int
        Number of diffusion dimensions

    Returns
    -------
    tracer_conductivity : FloatWithUnit
        Tracer conductivity in $S/m$
    """
    temperature = self.trajectory.metadata['temperature']
    tracer_diff = self.tracer_diffusivity(dimensions=dimensions)
    tracer_conduc = ((elementary_charge**2) * (z_ion**2) * tracer_diff *
                     self.particle_density()) / (Boltzmann * temperature)

    return FloatWithUnit(tracer_conduc, 'S m^-1')

tracer_diffusivity(*, dimensions=3)

Calculate tracer diffusivity.

Defined as: MSD / (2dimensionstime)

Parameters:

  • dimensions (int, default: 3 ) –

    Number of diffusion dimensions

Returns:

  • tracer_diffusivity ( FloatWithUnit ) –

    Tracer diffusivity in \(m^2/s\)

Source code in src/gemdat/simulation_metrics.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
@weak_lru_cache()
def tracer_diffusivity(self, *, dimensions: int = 3) -> FloatWithUnit:
    """Calculate tracer diffusivity.

    Defined as: MSD / (2*dimensions*time)

    Parameters
    ----------
    dimensions : int
        Number of diffusion dimensions

    Returns
    -------
    tracer_diffusivity : FloatWithUnit
        Tracer diffusivity in $m^2/s$
    """
    distances = self.trajectory.distances_from_base_position()
    msd = np.mean(distances[:, -1]**2)  # Angstrom^2

    tracer_diff = (msd * angstrom**2) / (2 * dimensions *
                                         self.trajectory.total_time)

    return FloatWithUnit(tracer_diff, 'm^2 s^-1')

tracer_diffusivity_center_of_mass(*, dimensions=3)

Calculate the tracer diffusivity of the center of mass.

Parameters:

  • dimensions (int, default: 3 ) –

    Number of diffusion dimensions

Returns:

  • tracer_diffusivity ( FloatWithUnit ) –

    Tracer diffusivity in \(m^2/s\)

Source code in src/gemdat/simulation_metrics.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
@weak_lru_cache()
def tracer_diffusivity_center_of_mass(
    self,
    *,
    dimensions: int = 3,
) -> FloatWithUnit:
    """Calculate the tracer diffusivity of the center of mass.

    Parameters
    ----------
    dimensions : int
        Number of diffusion dimensions

    Returns
    -------
    tracer_diffusivity : FloatWithUnit
        Tracer diffusivity in $m^2/s$
    """
    center_of_mass = self.trajectory.center_of_mass()

    metrics = SimulationMetrics(center_of_mass)

    return metrics.tracer_diffusivity(dimensions=dimensions)

vibration_amplitude()

Calculate vibration amplitude.

Returns:

  • vibration_amp ( FloatWithUnit ) –

    Vibration amplitude in \(Ã…\)

Source code in src/gemdat/simulation_metrics.py
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
@weak_lru_cache()
def vibration_amplitude(self) -> FloatWithUnit:
    """Calculate vibration amplitude.

    Returns
    -------
    vibration_amp : FloatWithUnit
        Vibration amplitude in $Ã…$
    """
    amplitudes = self.amplitudes()

    mean_vib = np.mean(amplitudes)
    vibration_amp = np.std(amplitudes)

    mean_vib = FloatWithUnit(mean_vib, 'ang')
    vibration_amp = FloatWithUnit(vibration_amp, 'ang')

    return vibration_amp

SimulationMetricsStd(trajectories)

Class for calculating different metrics and properties from a molecular dynamics simulation.

Calculates the mean and standard deviation for a given list of trajectories

Parameters:

Source code in src/gemdat/simulation_metrics.py
244
245
246
247
248
249
250
251
252
253
254
def __init__(self, trajectories: list[Trajectory]):
    """Initialize class.

    Parameters
    ----------
    trajectories: list[Trajectory]
        Input trajectories
    """
    self.metrics = [
        SimulationMetrics(trajectory) for trajectory in trajectories
    ]

amplitudes()

Calculate vibration amplitudes.

Returns:

  • amplitudes_mean, amplitudes_std : tuple[np.ndarray, np.ndarray] –

    Output array of vibration amplitudes, mean and standard deviation

Source code in src/gemdat/simulation_metrics.py
332
333
334
335
336
337
338
339
340
341
def amplitudes(self) -> tuple[np.ndarray, np.ndarray]:
    """Calculate vibration amplitudes.

    Returns
    -------
    amplitudes_mean, amplitudes_std : tuple[np.ndarray, np.ndarray]
        Output array of vibration amplitudes, mean and standard deviation
    """
    amplitudes = [metric.amplitudes() for metric in self.metrics]
    return (np.mean(amplitudes, axis=0), np.std(amplitudes, axis=0))

speed()

Calculate mean speed and standard deviations.

Corresponds to change in distance from the base position.

Returns:

  • speed_mean, speed_std : tuple[np.ndarray, np.ndarray] –

    Output arrays with speeds

Source code in src/gemdat/simulation_metrics.py
256
257
258
259
260
261
262
263
264
265
266
267
def speed(self) -> tuple[np.ndarray, np.ndarray]:
    """Calculate mean speed and standard deviations.

    Corresponds to change in distance from the base position.

    Returns
    -------
    speed_mean, speed_std : tuple[np.ndarray, np.ndarray]
        Output arrays with speeds
    """
    speeds = [metric.speed() for metric in self.metrics]
    return (np.mean(speeds, axis=0), np.std(speeds, axis=0))

tracer_conductivity(*, z_ion, dimensions)

Return tracer conductivity as S/m.

Defined as: elementary_charge^2 * charge_ion^2 * diffusivity * particle_density / (k_B * T)

Parameters:

  • z_ion (int) –

    Charge of the ion

  • dimensions (int) –

    Number of diffusion dimensions

Returns:

  • tracer_conductivities ( ufloat ) –

    Tracer conductivities in \(S/m\), mean and standard deviation

Source code in src/gemdat/simulation_metrics.py
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
def tracer_conductivity(self, *, z_ion: int, dimensions: int) -> u.ufloat:
    """Return tracer conductivity as S/m.

    Defined as: elementary_charge^2 * charge_ion^2 * diffusivity *
        particle_density / (k_B * T)

    Parameters
    ----------
    z_ion : int
        Charge of the ion
    dimensions : int
        Number of diffusion dimensions

    Returns
    -------
    tracer_conductivities : u.ufloat
        Tracer conductivities in $S/m$, mean and standard deviation
    """
    conductivities = [
        metric.tracer_conductivity(z_ion=z_ion, dimensions=dimensions)
        for metric in self.metrics
    ]
    mean_conductivities = FloatWithUnit(np.mean(conductivities), 'S m^-1')
    std_conductivities = FloatWithUnit(np.std(conductivities), 'S m^-1')
    return u.ufloat(mean_conductivities, std_conductivities)

tracer_diffusivity(*, dimensions)

Calculate tracer diffusivity.

Defined as: MSD / (2dimensionstime)

Parameters:

  • dimensions (int) –

    Number of diffusion dimensions

Returns:

  • tracer_diffusivity ( ufloat ) –

    Tracer diffusivity in \(m^2/s\), mean and standard deviation

Source code in src/gemdat/simulation_metrics.py
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def tracer_diffusivity(self, *, dimensions: int) -> u.ufloat:
    """Calculate tracer diffusivity.

    Defined as: MSD / (2*dimensions*time)

    Parameters
    ----------
    dimensions : int
        Number of diffusion dimensions

    Returns
    -------
    tracer_diffusivity : u.ufloat
        Tracer diffusivity in $m^2/s$, mean and standard deviation
    """
    diffusivities = [
        metric.tracer_diffusivity(dimensions=dimensions)
        for metric in self.metrics
    ]
    mean_diffusivities = FloatWithUnit(np.mean(diffusivities), 'm^2 s^-1')
    std_diffusivities = FloatWithUnit(np.std(diffusivities), 'm^2 s^-1')
    return u.ufloat(mean_diffusivities, std_diffusivities)

vibration_amplitude()

Calculate vibration amplitude.

Returns:

  • vibration_amp_mean, vibration_amp_std : tuple[FloatWithUnit, FloatWithUnit] –

    Vibration amplitude in \(Ã…\), mean and standard deviation

Source code in src/gemdat/simulation_metrics.py
318
319
320
321
322
323
324
325
326
327
328
329
330
def vibration_amplitude(self) -> u.ufloat:
    """Calculate vibration amplitude.

    Returns
    -------
    vibration_amp_mean, vibration_amp_std : tuple[FloatWithUnit, FloatWithUnit]
        Vibration amplitude in $Ã…$, mean and standard deviation
    """
    vibes = [metric.vibration_amplitude() for metric in self.metrics]
    mean_vibes = FloatWithUnit(np.mean(vibes), 'ang')
    standard_vibes = FloatWithUnit(np.std(vibes),
                                   'ang')  # Standard deviation
    return u.ufloat(mean_vibes, standard_vibes)