ipi 3.3.0__tar.gz → 3.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. {ipi-3.3.0 → ipi-3.3.1}/PKG-INFO +1 -1
  2. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi +4 -0
  3. ipi-3.3.1/ipi/_version.py +1 -0
  4. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/barostats.py +227 -1
  5. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/forcefields.py +3 -2
  6. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/initializer.py +7 -16
  7. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/dynamics.py +4 -0
  8. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/instanton.py +5 -0
  9. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/planetary.py +5 -0
  10. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/normalmodes.py +35 -2
  11. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/outputs.py +2 -16
  12. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/properties.py +45 -8
  13. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/simulation.py +63 -40
  14. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/thermostats.py +6 -0
  15. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/barostats.py +62 -3
  16. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/normalmodes.py +11 -2
  17. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/simulation.py +29 -1
  18. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/_mace.py +288 -170
  19. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/doublewell.py +3 -1
  20. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/metatomic.py +7 -2
  21. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/tools.py +83 -2
  22. {ipi-3.3.0 → ipi-3.3.1}/ipi/scripting/templates.py +70 -21
  23. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/nmtransform.py +137 -6
  24. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/setup.py +16 -8
  25. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/softexit.py +74 -19
  26. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/units.py +13 -0
  27. {ipi-3.3.0 → ipi-3.3.1}/ipi.egg-info/PKG-INFO +1 -1
  28. {ipi-3.3.0 → ipi-3.3.1}/pyproject.toml +4 -0
  29. ipi-3.3.0/ipi/_version.py +0 -1
  30. {ipi-3.3.0 → ipi-3.3.1}/README.md +0 -0
  31. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-committee-reweight +0 -0
  32. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-contract-trajectory +0 -0
  33. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-convert-input +0 -0
  34. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-driver-py +0 -0
  35. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-get_Ascp +0 -0
  36. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-getacf +0 -0
  37. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-getproperty +0 -0
  38. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-gleacf +0 -0
  39. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-kinetic2tag +0 -0
  40. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-mergebeadspdb +0 -0
  41. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-mux-positions +0 -0
  42. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-paraweights +0 -0
  43. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-planetary +0 -0
  44. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-posforce2kinetic +0 -0
  45. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-py_driver +0 -0
  46. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-remdsort +0 -0
  47. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-style +0 -0
  48. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-tests +0 -0
  49. {ipi-3.3.0 → ipi-3.3.1}/bin/i-pi-trimsim +0 -0
  50. {ipi-3.3.0 → ipi-3.3.1}/ipi/__init__.py +0 -0
  51. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/__init__.py +0 -0
  52. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/atoms.py +0 -0
  53. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/beads.py +0 -0
  54. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/cell.py +0 -0
  55. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/ensembles.py +0 -0
  56. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/forces.py +0 -0
  57. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/__init__.py +0 -0
  58. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/al6xxx_kmc.py +0 -0
  59. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/alchemy.py +0 -0
  60. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/atomswap.py +0 -0
  61. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/constrained_dynamics.py +0 -0
  62. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/driven_dynamics.py +0 -0
  63. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/geop.py +0 -0
  64. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/motion.py +0 -0
  65. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/multi.py +0 -0
  66. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/neb.py +0 -0
  67. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/phonons.py +0 -0
  68. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/ramp.py +0 -0
  69. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/replay.py +0 -0
  70. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/scphonons.py +0 -0
  71. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/stringmep.py +0 -0
  72. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/motion/vscf.py +0 -0
  73. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/smotion/__init__.py +0 -0
  74. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/smotion/dmd.py +0 -0
  75. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/smotion/metad.py +0 -0
  76. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/smotion/multi.py +0 -0
  77. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/smotion/remd.py +0 -0
  78. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/smotion/smotion.py +0 -0
  79. {ipi-3.3.0 → ipi-3.3.1}/ipi/engine/system.py +0 -0
  80. {ipi-3.3.0 → ipi-3.3.1}/ipi/external/__init__.py +0 -0
  81. {ipi-3.3.0 → ipi-3.3.1}/ipi/external/importlib/__init__.py +0 -0
  82. {ipi-3.3.0 → ipi-3.3.1}/ipi/external/importlib/bundledimportlib.py +0 -0
  83. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/__init__.py +0 -0
  84. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/atoms.py +0 -0
  85. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/beads.py +0 -0
  86. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/cell.py +0 -0
  87. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/ensembles.py +0 -0
  88. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/forcefields.py +0 -0
  89. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/forces.py +0 -0
  90. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/initializer.py +0 -0
  91. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/interface.py +0 -0
  92. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/__init__.py +0 -0
  93. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/al6xxx_kmc.py +0 -0
  94. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/alchemy.py +0 -0
  95. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/atomswap.py +0 -0
  96. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/constrained_dynamics.py +0 -0
  97. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/driven_dynamics.py +0 -0
  98. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/dynamics.py +0 -0
  99. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/geop.py +0 -0
  100. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/instanton.py +0 -0
  101. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/motion.py +0 -0
  102. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/neb.py +0 -0
  103. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/phonons.py +0 -0
  104. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/planetary.py +0 -0
  105. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/ramp.py +0 -0
  106. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/scphonons.py +0 -0
  107. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/stringmep.py +0 -0
  108. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/motion/vscf.py +0 -0
  109. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/outputs.py +0 -0
  110. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/prng.py +0 -0
  111. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/smotion/__init__.py +0 -0
  112. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/smotion/dmd.py +0 -0
  113. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/smotion/metad.py +0 -0
  114. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/smotion/remd.py +0 -0
  115. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/smotion/smotion.py +0 -0
  116. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/system.py +0 -0
  117. {ipi-3.3.0 → ipi-3.3.1}/ipi/inputs/thermostats.py +0 -0
  118. {ipi-3.3.0 → ipi-3.3.1}/ipi/interfaces/__init__.py +0 -0
  119. {ipi-3.3.0 → ipi-3.3.1}/ipi/interfaces/mpi.py +0 -0
  120. {ipi-3.3.0 → ipi-3.3.1}/ipi/interfaces/sockets.py +0 -0
  121. {ipi-3.3.0 → ipi-3.3.1}/ipi/interfaces/utils.py +0 -0
  122. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/__init__.py +0 -0
  123. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/_ase.py +0 -0
  124. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/bath.py +0 -0
  125. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/doubledoublewell.py +0 -0
  126. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/doublewell_with_bath.py +0 -0
  127. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/doublewell_with_friction.py +0 -0
  128. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/driverdipole.py +0 -0
  129. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/dummy.py +0 -0
  130. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/elphmod.py +0 -0
  131. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/gas.py +0 -0
  132. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/harmonic.py +0 -0
  133. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/morse.py +0 -0
  134. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/pet.py +0 -0
  135. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/psiflow.py +0 -0
  136. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/rascal.py +0 -0
  137. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/so3lr.py +0 -0
  138. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/spherical_LJ.py +0 -0
  139. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/spline.py +0 -0
  140. {ipi-3.3.0 → ipi-3.3.1}/ipi/pes/xtb.py +0 -0
  141. {ipi-3.3.0 → ipi-3.3.1}/ipi/scripting/__init__.py +0 -0
  142. {ipi-3.3.0 → ipi-3.3.1}/ipi/scripting/calculators.py +0 -0
  143. {ipi-3.3.0 → ipi-3.3.1}/ipi/scripting/interactive.py +0 -0
  144. {ipi-3.3.0 → ipi-3.3.1}/ipi/scripting/parsing.py +0 -0
  145. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/__init__.py +0 -0
  146. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/constrtools.py +0 -0
  147. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/decorators.py +0 -0
  148. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/depend.py +0 -0
  149. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/distance.py +0 -0
  150. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/exchange.py +0 -0
  151. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/hesstools.py +0 -0
  152. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/inputvalue.py +0 -0
  153. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/instools.py +0 -0
  154. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/__init__.py +0 -0
  155. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/backends/__init__.py +0 -0
  156. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/backends/io_ase.py +0 -0
  157. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/backends/io_binary.py +0 -0
  158. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/backends/io_json.py +0 -0
  159. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/backends/io_pdb.py +0 -0
  160. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/backends/io_xyz.py +0 -0
  161. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/inputs/__init__.py +0 -0
  162. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/inputs/io_json.py +0 -0
  163. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/inputs/io_xml.py +0 -0
  164. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/io/io_units.py +0 -0
  165. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/lebedev_grids.npy +0 -0
  166. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/mathtools.py +0 -0
  167. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/messages.py +0 -0
  168. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/mintools.py +0 -0
  169. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/parsing.py +0 -0
  170. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/phonontools.py +0 -0
  171. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/prng.py +0 -0
  172. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/scripting.py +0 -0
  173. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/sparse.py +0 -0
  174. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/tools/__init__.py +0 -0
  175. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/tools/acf_xyz.py +0 -0
  176. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/tools/gle.py +0 -0
  177. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/tools/instanton_interpolation.py +0 -0
  178. {ipi-3.3.0 → ipi-3.3.1}/ipi/utils/tools/instanton_postproc.py +0 -0
  179. {ipi-3.3.0 → ipi-3.3.1}/ipi.egg-info/SOURCES.txt +0 -0
  180. {ipi-3.3.0 → ipi-3.3.1}/ipi.egg-info/dependency_links.txt +0 -0
  181. {ipi-3.3.0 → ipi-3.3.1}/ipi.egg-info/requires.txt +0 -0
  182. {ipi-3.3.0 → ipi-3.3.1}/ipi.egg-info/top_level.txt +0 -0
  183. {ipi-3.3.0 → ipi-3.3.1}/licenses/license_GPL.txt +0 -0
  184. {ipi-3.3.0 → ipi-3.3.1}/licenses/license_MIT.txt +0 -0
  185. {ipi-3.3.0 → ipi-3.3.1}/setup.cfg +0 -0
  186. {ipi-3.3.0 → ipi-3.3.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ipi
3
- Version: 3.3.0
3
+ Version: 3.3.1
4
4
  Summary: A Python interface for ab initio path integral molecular dynamics simulations
5
5
  Home-page: http://ipi-code.org
6
6
  Author: The i-PI developers
@@ -60,6 +60,10 @@ def main(fn_input, options):
60
60
  # construct simulation based on input file
61
61
  simulation = Simulation.load_from_xml(open(fn_input), request_banner=True, custom_verbosity=options.verbosity, sockets_prefix=options.sockets_prefix)
62
62
 
63
+ # when running as a standalone program, ends the process as soon as the
64
+ # soft exit cleanup is complete (see Softexit.kill)
65
+ softexit.hard_exit = True
66
+
63
67
  # run the simulation
64
68
  simulation.run()
65
69
 
@@ -0,0 +1 @@
1
+ __version__ = "3.3.1"
@@ -25,10 +25,11 @@ from ipi.utils.mathtools import (
25
25
  sinch,
26
26
  mat_taylor,
27
27
  )
28
+ from ipi.utils.messages import warning, verbosity
28
29
  from ipi.engine.thermostats import Thermostat
29
30
  from ipi.engine.cell import Cell
30
31
 
31
- __all__ = ["Barostat", "BaroBZP", "BaroRGB", "BaroSCBZP", "BaroMTK"]
32
+ __all__ = ["Barostat", "BaroSCR", "BaroBZP", "BaroRGB", "BaroSCBZP", "BaroMTK"]
32
33
 
33
34
 
34
35
  def mask_from_fix(fix):
@@ -426,6 +427,231 @@ dproperties(
426
427
  )
427
428
 
428
429
 
430
+ class BaroSCR(Barostat):
431
+ """Bernetti--Bussi stochastic cell-rescaling barostat.
432
+
433
+ Mode ``stochastic-rescaling`` implements the reversible, isotropic
434
+ Trotter scheme with instantaneous kinetic pressure described in
435
+ Bernetti and Bussi, J. Chem. Phys. 153, 114107 (2020)
436
+ [doi:10.1063/5.0020514]. Positions and cell vectors are scaled by the
437
+ same factor, while momenta are scaled by its inverse.
438
+
439
+ This implementation is restricted to classical dynamics. The particle
440
+ thermostat remains responsible for temperature control; stochastic cell
441
+ rescaling does not have a separate piston or cell thermostat.
442
+ """
443
+
444
+ def __init__(
445
+ self,
446
+ dt=None,
447
+ temp=None,
448
+ tau=None,
449
+ ebaro=None,
450
+ thermostat=None,
451
+ pext=None,
452
+ compressibility=None,
453
+ ):
454
+ """Initializes the stochastic cell-rescaling barostat.
455
+
456
+ Args:
457
+ dt: Optional simulation time step.
458
+ temp: Optional simulation temperature.
459
+ tau: Pressure relaxation time.
460
+ ebaro: Accumulated effective-energy correction, used on restart.
461
+ thermostat: Must be the dummy thermostat. Kept for input
462
+ compatibility with other barostats.
463
+ pext: Optional external pressure.
464
+ compressibility: Estimate of the isothermal compressibility.
465
+ """
466
+
467
+ super(BaroSCR, self).__init__(dt, temp, tau, ebaro, thermostat)
468
+
469
+ self._compressibility = depend_value(
470
+ name="compressibility",
471
+ value=-1.0 if compressibility is None else compressibility,
472
+ )
473
+ self.prng = None
474
+ self._scr_state = None
475
+
476
+ if pext is not None:
477
+ self.pext = pext
478
+
479
+ def bind(self, beads, nm, cell, forces, bias=None, prng=None, fixdof=None, nmts=1):
480
+ """Binds the physical system and random-number generator."""
481
+
482
+ super(BaroSCR, self).bind(beads, nm, cell, forces, bias, prng, fixdof, nmts)
483
+
484
+ if self.tau <= 0.0:
485
+ raise ValueError(
486
+ "The stochastic cell-rescaling relaxation time must be positive."
487
+ )
488
+ if self.compressibility <= 0.0:
489
+ raise ValueError(
490
+ "The stochastic cell-rescaling compressibility must be positive."
491
+ )
492
+ if self.beads.nbeads != 1:
493
+ raise ValueError(
494
+ "Stochastic cell rescaling currently supports classical "
495
+ "dynamics only (nbeads=1)."
496
+ )
497
+ if type(self.thermostat) is not Thermostat:
498
+ raise ValueError(
499
+ "Stochastic cell rescaling does not use a separate cell thermostat."
500
+ )
501
+ if prng is None:
502
+ raise ValueError(
503
+ "Stochastic cell rescaling requires the simulation random-number "
504
+ "generator."
505
+ )
506
+
507
+ self.prng = prng
508
+ self._pot = depend_value(
509
+ name="pot", func=self.get_pot, dependencies=[cell._V, self._pext]
510
+ )
511
+ self._cell_jacobian = depend_value(
512
+ name="cell_jacobian",
513
+ func=self.get_cell_jacobian,
514
+ dependencies=[cell._V, self._temp],
515
+ )
516
+
517
+ def get_pot(self):
518
+ """Returns the external-pressure contribution to the enthalpy."""
519
+
520
+ return self.pext * self.cell.V
521
+
522
+ def get_cell_jacobian(self):
523
+ """Returns the Jacobian contribution for lambda = sqrt(volume)."""
524
+
525
+ return -0.5 * Constants.kb * self.temp * np.log(self.cell.V)
526
+
527
+ def get_lambda_force(self):
528
+ """Returns the drift force acting on lambda = sqrt(volume)."""
529
+
530
+ volume = self.cell.V
531
+ if not np.isfinite(volume) or volume <= 0.0:
532
+ raise ValueError(
533
+ "Stochastic cell rescaling encountered a non-positive or "
534
+ "non-finite volume."
535
+ )
536
+ pressure = (
537
+ sum(np.trace(self.stress_mts(level)) for level in range(self.nmtslevels))
538
+ / 3.0
539
+ )
540
+ if not np.isfinite(pressure):
541
+ raise ValueError(
542
+ "Stochastic cell rescaling encountered a non-finite internal "
543
+ "pressure."
544
+ )
545
+
546
+ lam = np.sqrt(volume)
547
+ return (
548
+ -2.0
549
+ * lam
550
+ * (self.pext - pressure - Constants.kb * self.temp / (2.0 * volume))
551
+ )
552
+
553
+ def prepare(self):
554
+ """Draws a cell move and returns its isotropic length scale."""
555
+
556
+ lambda_force = self.get_lambda_force()
557
+ volume = self.cell.V
558
+ lam = np.sqrt(volume)
559
+ coupling_dt = 2.0 * self.qdt
560
+ kbt = Constants.kb * self.temp
561
+ diffusion = kbt * self.compressibility / (4.0 * self.tau)
562
+ delta_lambda = (
563
+ diffusion * lambda_force * coupling_dt / kbt
564
+ + np.sqrt(2.0 * diffusion * coupling_dt) * self.prng.g
565
+ )
566
+ new_lambda = lam + delta_lambda
567
+
568
+ if not np.isfinite(new_lambda) or new_lambda <= 0.0:
569
+ raise ValueError(
570
+ "Stochastic cell rescaling proposed a non-positive or non-finite "
571
+ "sqrt(volume). Increase tau, reduce stride or the MD time step, "
572
+ "and check the compressibility."
573
+ )
574
+
575
+ delta_log_lambda = np.log1p(delta_lambda / lam)
576
+ scale = np.exp((2.0 / 3.0) * delta_log_lambda)
577
+ if scale < 0.99 or scale > 1.01:
578
+ warning(
579
+ "Stochastic cell rescaling changed a cell length by more than "
580
+ "1%. Consider increasing tau or reducing stride.",
581
+ verbosity.low,
582
+ )
583
+
584
+ self._scr_state = {
585
+ "volume": volume,
586
+ "lambda": lam,
587
+ "lambda_force": lambda_force,
588
+ "delta_lambda": delta_lambda,
589
+ "delta_log_lambda": delta_log_lambda,
590
+ "diffusion": diffusion,
591
+ "coupling_dt": coupling_dt,
592
+ }
593
+ return scale
594
+
595
+ def qcstep(self):
596
+ """Propagates one half of the reversible cell-rescaling map.
597
+
598
+ The standard NPT integrator calls this method twice around the free
599
+ ring-polymer propagation. The first call draws the stochastic cell
600
+ move and applies drift--rescale; the second applies rescale--drift and
601
+ closes the effective-energy bookkeeping.
602
+ """
603
+
604
+ masses = dstrip(self.nm.dynm3)[0]
605
+
606
+ if self._scr_state is None:
607
+ scale = self.prepare()
608
+ half_scale = np.sqrt(scale)
609
+ self._scr_state["half_scale"] = half_scale
610
+
611
+ self.nm.qnm[0, :] += dstrip(self.nm.pnm)[0] * self.qdt / masses
612
+ self.nm.qnm[0, :] *= half_scale
613
+ self.nm.pnm[0, :] *= 1.0 / half_scale
614
+ self.cell.h *= half_scale
615
+ else:
616
+ half_scale = self._scr_state["half_scale"]
617
+
618
+ self.nm.qnm[0, :] *= half_scale
619
+ self.nm.pnm[0, :] *= 1.0 / half_scale
620
+ self.cell.h *= half_scale
621
+ self.nm.qnm[0, :] += dstrip(self.nm.pnm)[0] * self.qdt / masses
622
+ self.finalize()
623
+
624
+ def finalize(self):
625
+ """Accumulates the reversible effective-energy correction."""
626
+
627
+ if self._scr_state is None:
628
+ raise RuntimeError(
629
+ "Stochastic cell-rescaling finalize called without a pending move."
630
+ )
631
+
632
+ state = self._scr_state
633
+ new_volume = self.cell.V
634
+ new_lambda_force = self.get_lambda_force()
635
+ kbt = Constants.kb * self.temp
636
+
637
+ correction = self.pext * (new_volume - state["volume"])
638
+ correction -= kbt * state["delta_log_lambda"]
639
+ correction += (
640
+ 0.5 * state["delta_lambda"] * (state["lambda_force"] + new_lambda_force)
641
+ )
642
+ correction += (
643
+ state["diffusion"]
644
+ * state["coupling_dt"]
645
+ / (4.0 * kbt)
646
+ * (new_lambda_force**2 - state["lambda_force"] ** 2)
647
+ )
648
+ self.ebaro += correction
649
+ self._scr_state = None
650
+
651
+
652
+ dproperties(BaroSCR, ["compressibility"])
653
+
654
+
429
655
  class BaroBZP(Barostat):
430
656
  """Bussi-Zykova-Parrinello barostat class.
431
657
 
@@ -380,7 +380,7 @@ class FFSocket(ForceField):
380
380
  """Closes the socket and the thread."""
381
381
 
382
382
  super(FFSocket, self).stop()
383
- if self._thread is not None:
383
+ if self._thread not in (None, threading.current_thread()):
384
384
  # must wait until loop has ended before closing the socket
385
385
  self._thread.join()
386
386
  self.socket.close()
@@ -481,7 +481,7 @@ class FFMPI(ForceField):
481
481
  """Stops the poll thread and tells every driver root to exit."""
482
482
 
483
483
  super().stop()
484
- if self._thread is not None:
484
+ if self._thread not in (None, threading.current_thread()):
485
485
  # must wait until the poll loop has ended before signalling exit
486
486
  self._thread.join()
487
487
  self.interface.close()
@@ -1180,6 +1180,7 @@ class FFYaff(FFEval):
1180
1180
  logf = open(yafflog, "w")
1181
1181
  # Tell Python to close the file when the script exits
1182
1182
  atexit.register(logf.close)
1183
+ softexit.register_function(logf.close) # also with a hard exit
1183
1184
 
1184
1185
  # Redirect Yaff log to file
1185
1186
  log._file = codecs.getwriter(locale.getpreferredencoding())(logf)
@@ -146,30 +146,21 @@ def init_chk(filename):
146
146
  filename: A string giving the name of the checkpoint file to be read from.
147
147
 
148
148
  Returns:
149
- A Beads object, Cell object and Thermostat object as read from the
149
+ A Beads object, Cell object and Motion object as read from the
150
150
  checkpoint file.
151
151
  """
152
152
 
153
- # reads configuration from a checkpoint file
154
- rfile = open(filename, "r")
155
- xmlchk = xml_parse_file(rfile) # Parses the file.
153
+ # Parse only the state required by the initializer. A full checkpoint
154
+ # restart still uses InputSimulation.fetch(), which intentionally restores
155
+ # its force fields as well.
156
+ with open(filename, "r") as rfile:
157
+ xmlchk = xml_parse_file(rfile)
156
158
 
157
159
  from ipi.inputs.simulation import InputSimulation
158
160
 
159
161
  simchk = InputSimulation()
160
162
  simchk.parse(xmlchk.fields[0][1])
161
- sim = simchk.fetch()
162
- if len(sim.syslist) > 1:
163
- warning(
164
- "Restart from checkpoint with "
165
- + str(len(sim.syslist))
166
- + " systems will fetch data from the first system."
167
- )
168
- rcell = sim.syslist[0].cell
169
- rbeads = sim.syslist[0].beads
170
- rmotion = sim.syslist[0].motion
171
-
172
- return (rbeads, rcell, rmotion)
163
+ return simchk.fetch_checkpoint_state()
173
164
 
174
165
 
175
166
  def init_beads(
@@ -341,6 +341,10 @@ class DummyIntegrator:
341
341
  dpipe(self._tdt, self.thermostat._dt)
342
342
 
343
343
  if motion.enstype == "sc" or motion.enstype == "scnpt":
344
+ if self.nm.mode == "eco":
345
+ raise ValueError(
346
+ "Suzuki-Chin propagation assumes Trotter springs and cannot be used with mode='eco'."
347
+ )
344
348
  # coefficients to get the (baseline) trotter to sc conversion
345
349
  self.coeffsc = np.ones((self.beads.nbeads, 3 * self.beads.natoms), float)
346
350
  self.coeffsc[::2] /= -3.0
@@ -233,6 +233,11 @@ class InstantonMotion(Motion):
233
233
  prng: The random number generator object which controls random number generation.
234
234
  """
235
235
 
236
+ if nm.mode == "eco":
237
+ raise ValueError(
238
+ "Instanton calculations assume Trotter springs and cannot be used with mode='eco'."
239
+ )
240
+
236
241
  super(InstantonMotion, self).bind(ens, beads, nm, cell, bforce, prng, omaker)
237
242
 
238
243
  # Redefine normal modes
@@ -114,6 +114,11 @@ class Planetary(Motion):
114
114
  self.basebeads = beads
115
115
  self.basenm = nm
116
116
 
117
+ if nm.mode == "eco":
118
+ raise ValueError(
119
+ "The planetary model assumes Trotter springs and cannot be used with mode='eco'."
120
+ )
121
+
117
122
  # copies of all of the helper classes that are needed to bind the ccdyn object
118
123
  self.dbeads = beads.clone(nbeads=self.nbeads)
119
124
  self.dcell = cell.clone()
@@ -56,7 +56,8 @@ class NormalModes:
56
56
  between the replicas. Depends on the simulation temperature.
57
57
  omegan2: omegan**2.
58
58
  omegak: The normal mode frequencies for the free ring polymer.
59
- Depends on omegan.
59
+ Trotter values, or economised ("eco") values fitted to reproduce
60
+ harmonic radii of gyration. Depends on omegan, mode and nm_freqs.
60
61
  prop_pq: An array holding the exact normal mode propagator for the
61
62
  free ring polymer, using mass scaled coordinates.
62
63
  See J. Chem. Phys. 133, 124101 (2010). Depends on the bead masses
@@ -171,6 +172,15 @@ class NormalModes:
171
172
 
172
173
  self.bosons = self.resolve_bosons()
173
174
 
175
+ # eco springs are only defined for closed, distinguishable paths
176
+ if self.mode == "eco":
177
+ if len(self.bosons) > 0 or len(self.open_paths) > 0:
178
+ raise ValueError("ECO mode cannot be used with bosons or open paths.")
179
+ if len(self.nm_freqs) != 1:
180
+ raise ValueError(
181
+ "ECO mode requires one frequency, the maximum physical frequency to be reproduced."
182
+ )
183
+
174
184
  # stores a reference to the bound beads and ensemble objects
175
185
  self.ensemble = ensemble
176
186
  dpipe(motion._dt, self._dt)
@@ -263,7 +273,7 @@ class NormalModes:
263
273
  name="omegak",
264
274
  value=np.zeros(self.beads.nbeads, float),
265
275
  func=self.get_omegak,
266
- dependencies=[self._omegan],
276
+ dependencies=[self._omegan, self._nm_freqs, self._mode],
267
277
  )
268
278
  self._omegak2 = depend_array(
269
279
  name="omegak2",
@@ -454,8 +464,28 @@ class NormalModes:
454
464
  Returns:
455
465
  A list of the normal mode frequencies for the free ring polymer.
456
466
  The first element is the centroid frequency (0.0).
467
+ For mode="eco", returns economised frequencies optimized to
468
+ reproduce the radii of gyration of harmonic oscillators with
469
+ frequencies up to nm_freqs[0].
457
470
  """
458
471
 
472
+ if self.mode == "eco":
473
+ if len(self.nm_freqs) != 1:
474
+ raise ValueError(
475
+ "ECO mode requires one frequency, the maximum physical frequency to be reproduced."
476
+ )
477
+ # xmax = beta*hbar*omega_max, given that omegan = nbeads/(beta*hbar)
478
+ xmax = self.nm_freqs[0] * self.nbeads / self.omegan
479
+ # seeds the fit with the previous solution (the stale value held in
480
+ # the depend array), which speeds up re-fits when temperature changes
481
+ y0 = (
482
+ dstrip(self._omegak)[1 : self.nbeads // 2 + 1]
483
+ * self.nbeads
484
+ / self.omegan
485
+ )
486
+ if not np.all(y0 > 0): # zeros before the first evaluation
487
+ y0 = None
488
+ return self.omegan * nmtransform.eco_eva(self.nbeads, xmax, y0)
459
489
  return self.omegan * nmtransform.nm_eva(self.nbeads)
460
490
 
461
491
  def get_o_omegak(self):
@@ -592,6 +622,9 @@ class NormalModes:
592
622
  if self.mode == "rpmd":
593
623
  if len(self.nm_freqs) > 0:
594
624
  warning("nm.frequencies will be ignored for RPMD mode.", verbosity.low)
625
+ elif self.mode == "eco":
626
+ # eco changes the spring frequencies (statics), not the dynamical masses
627
+ pass
595
628
  elif self.mode == "manual":
596
629
  if len(self.nm_freqs) != self.nbeads - 1:
597
630
  raise ValueError(
@@ -12,7 +12,7 @@ import os
12
12
 
13
13
  import numpy as np
14
14
 
15
- from ipi.utils.messages import verbosity, info, warning
15
+ from ipi.utils.messages import verbosity, warning
16
16
  from ipi.utils.units import unit_to_user
17
17
  from ipi.utils.softexit import softexit
18
18
  from ipi.utils.depend import *
@@ -117,6 +117,7 @@ class BaseOutput(object):
117
117
  """Emergency call when i-pi must exit quickly"""
118
118
 
119
119
  self.close_stream()
120
+ self.out = None # anything written later is discarded
120
121
 
121
122
  def close_stream(self):
122
123
  """Closes the output stream"""
@@ -270,9 +271,6 @@ class PropertyOutput(BaseOutput):
270
271
  are not contained in the property_dict member of properties.
271
272
  """
272
273
 
273
- if softexit.triggered:
274
- return # don't write if we are about to exit!
275
-
276
274
  if not self.active():
277
275
  return
278
276
  self.out.write(" ")
@@ -453,8 +451,6 @@ class TrajectoryOutput(BaseOutput):
453
451
  def write(self):
454
452
  """Writes out the required trajectories."""
455
453
 
456
- if softexit.triggered:
457
- return # don't write if we are about to exit!
458
454
  if not self.active():
459
455
  return
460
456
 
@@ -693,7 +689,6 @@ class CheckpointOutput:
693
689
  self.stride = stride
694
690
  self._step = depend_value(name="step", value=step)
695
691
  self.overwrite = overwrite
696
- self._storing = False
697
692
  self._continued = False
698
693
 
699
694
  def bind(self, simul):
@@ -723,9 +718,7 @@ class CheckpointOutput:
723
718
  positions would have been consistent.
724
719
  """
725
720
 
726
- self._storing = True
727
721
  self.status.store(self.simul)
728
- self._storing = False
729
722
 
730
723
  def write(self, store=True):
731
724
  """Writes out the required trajectories.
@@ -744,13 +737,6 @@ class CheckpointOutput:
744
737
  stored before writing the checkpoint file.
745
738
  """
746
739
 
747
- if self._storing:
748
- info(
749
- "@ CHECKPOINT: Write called while storing. Force re-storing",
750
- verbosity.low,
751
- )
752
- self.store()
753
-
754
740
  if not self.active():
755
741
  return
756
742
 
@@ -1319,6 +1319,16 @@ class Properties:
1319
1319
 
1320
1320
  return fq * 0.5 / self.beads.nbeads
1321
1321
 
1322
+ def _require_trotter_springs(self, name):
1323
+ """Raises when an estimator derived for Trotter ring-polymer springs
1324
+ is requested with a different spring matrix."""
1325
+
1326
+ if self.nm.mode == "eco":
1327
+ raise ValueError(
1328
+ "The %s estimator assumes Trotter ring-polymer springs and cannot be used with mode='eco'."
1329
+ % name
1330
+ )
1331
+
1322
1332
  def get_sckintd(self, atom=""):
1323
1333
  """Calculates the Suzuki-Chin thermodynamic quantum centroid virial kinetic energy estimator.
1324
1334
 
@@ -1327,6 +1337,7 @@ class Properties:
1327
1337
  for. If not, the system kinetic energy is given.
1328
1338
  """
1329
1339
 
1340
+ self._require_trotter_springs("kinetic_tdsc")
1330
1341
  try:
1331
1342
  # iatom gives the index of the atom to be studied
1332
1343
  iatom = int(atom)
@@ -1470,7 +1481,9 @@ class Properties:
1470
1481
  atoms not to be considered in the distinguishable estimator (e.g. bosons)
1471
1482
  """
1472
1483
  q = dstrip(self.beads.q)
1484
+ qnm = dstrip(self.nm.qnm)
1473
1485
  m = dstrip(self.beads.m)
1486
+ omegak2 = dstrip(self.nm.omegak2)
1474
1487
  PkT32 = 1.5 * Constants.kb * self.ensemble.temp * self.beads.nbeads
1475
1488
 
1476
1489
  atd = 0.0
@@ -1482,14 +1495,23 @@ class Properties:
1482
1495
  if i in skip_atom_indices:
1483
1496
  continue
1484
1497
 
1485
- ktd = 0.0
1486
- for b in range(1, self.beads.nbeads):
1487
- for j in range(3 * i, 3 * (i + 1)):
1488
- ktd += (q[b, j] - q[b - 1, j]) ** 2
1489
- for j in range(3 * i, 3 * (i + 1)):
1490
- ktd += (q[self.beads.nbeads - 1, j] - q[0, j]) ** 2
1491
-
1492
- ktd *= -0.5 * m[i] * self.nm.omegan2 / self.beads.nbeads
1498
+ if i in self.nm.open_paths:
1499
+ # open-path atoms are not described by the ring-polymer normal modes;
1500
+ # uses the cyclic bead-difference spring energy (primitive-estimator
1501
+ # definition, including the ring-closure term)
1502
+ dq = q[:, 3 * i : 3 * (i + 1)] - np.roll(
1503
+ q[:, 3 * i : 3 * (i + 1)], 1, axis=0
1504
+ )
1505
+ ktd = -0.5 * m[i] * self.nm.omegan2 * (dq**2).sum() / self.beads.nbeads
1506
+ else:
1507
+ # spring energy of atom i, computed in the normal-mode representation
1508
+ # so that it is valid for any circulant spring matrix (Trotter or eco)
1509
+ ktd = (
1510
+ -0.5
1511
+ * m[i]
1512
+ * (omegak2 @ (qnm[:, 3 * i : 3 * (i + 1)] ** 2).sum(axis=1))
1513
+ / self.beads.nbeads
1514
+ )
1493
1515
  ktd += PkT32
1494
1516
  atd += ktd
1495
1517
  ncount += 1
@@ -1499,6 +1521,7 @@ class Properties:
1499
1521
  def get_sckinpr(self):
1500
1522
  """Calculates the quantum centroid virial kinetic energy estimator."""
1501
1523
 
1524
+ self._require_trotter_springs("kinetic_prsc")
1502
1525
  spring = self.nm.vspring / self.beads.nbeads
1503
1526
  PkT32 = (
1504
1527
  1.5
@@ -2330,6 +2353,7 @@ class Properties:
2330
2353
  sign(sum(weight*ke)) )
2331
2354
  """
2332
2355
 
2356
+ self._require_trotter_springs("isotope_thermo")
2333
2357
  try:
2334
2358
  # iatom gives the index of the atom to be studied
2335
2359
  iatom = int(atom)
@@ -2436,6 +2460,7 @@ class Properties:
2436
2460
  (spraverage, spr2average, sprexpaverage)
2437
2461
  """
2438
2462
 
2463
+ self._require_trotter_springs("isotope_zetatd")
2439
2464
  try:
2440
2465
  # iatom gives the index of the atom to be studied
2441
2466
  iatom = int(atom)
@@ -2539,6 +2564,7 @@ class Properties:
2539
2564
  q = dstrip(self.beads.q)
2540
2565
  v0 = self.forces.pot
2541
2566
  self.dbeads.q = q
2567
+ self.dcell.h = self.cell.h
2542
2568
 
2543
2569
  for i in range(self.beads.natoms):
2544
2570
  # selects only the atoms we care about
@@ -2586,6 +2612,7 @@ class Properties:
2586
2612
  (ti_weight, chin_weight)
2587
2613
  """
2588
2614
 
2615
+ self._require_trotter_springs("isotope_zetatd_4th")
2589
2616
  try:
2590
2617
  # iatom gives the index of the atom to be studied
2591
2618
  iatom = int(atom)
@@ -2707,6 +2734,7 @@ class Properties:
2707
2734
  (ti_weight, chin_weight)
2708
2735
  """
2709
2736
 
2737
+ self._require_trotter_springs("isotope_zetasc_4th")
2710
2738
  try:
2711
2739
  # iatom gives the index of the atom to be studied
2712
2740
  iatom = int(atom)
@@ -2738,6 +2766,7 @@ class Properties:
2738
2766
  f = dstrip(self.forces.f)
2739
2767
  v0 = self.forces.pot
2740
2768
  pots = self.forces.pots
2769
+ self.dcell.h = self.cell.h
2741
2770
 
2742
2771
  for i in range(self.beads.natoms):
2743
2772
  # selects only the atoms we care about
@@ -2804,6 +2833,7 @@ class Properties:
2804
2833
  )
2805
2834
 
2806
2835
  def get_chin_correction(self):
2836
+ self._require_trotter_springs("chin_weight")
2807
2837
  f = dstrip(self.forces.f)
2808
2838
  m3 = dstrip(self.beads.m3)
2809
2839
  pots = self.forces.pots
@@ -2827,6 +2857,7 @@ class Properties:
2827
2857
  return np.asarray([chin, chin2, chinexp])
2828
2858
 
2829
2859
  def get_ti_correction(self):
2860
+ self._require_trotter_springs("ti_weight")
2830
2861
  f = dstrip(self.forces.f)
2831
2862
  m3 = dstrip(self.beads.m3)
2832
2863
  # pots = self.forces.pots #
@@ -2854,6 +2885,7 @@ class Properties:
2854
2885
  for. If not, the system kinetic energy is given.
2855
2886
  """
2856
2887
 
2888
+ self._require_trotter_springs("ti_pot")
2857
2889
  try:
2858
2890
  # iatom gives the index of the atom to be studied
2859
2891
  iatom = int(atom)
@@ -3225,6 +3257,10 @@ class Trajectories:
3225
3257
  Args:
3226
3258
  alpha: m'/m the mass ratio
3227
3259
  """
3260
+ if self.system.nm.mode == "eco":
3261
+ raise ValueError(
3262
+ "The isotope_zetatd estimator assumes Trotter ring-polymer springs and cannot be used with mode='eco'."
3263
+ )
3228
3264
  try:
3229
3265
  # iatom gives the index of the atom to be studied
3230
3266
  iatom = int(atom)
@@ -3306,6 +3342,7 @@ class Trajectories:
3306
3342
  q = dstrip(self.system.beads.q)
3307
3343
  v0 = self.system.forces.pot / nb
3308
3344
  self.dbeads.q = q
3345
+ self.dcell.h = self.system.cell.h
3309
3346
 
3310
3347
  for i in range(nat):
3311
3348
  # selects only the atoms we care about