 options:
- Set the “Type” to NVT Berendsen.
- Set “Steps” to 20000.
- Set the “Log interval” to 200.
- Initial Velocity options:
- Set “Type” to Maxwell-Boltzmann.
- Set “Temperature” to 300 K.
- Untick the Remove center-of-mass momentum option.
- NVT Berendsen options:
- Set the “Thermal coupling” to 1 fs.
- Molecular Dynamics options:
Leave the remaining settings at defaults, like in the image above.
Adding Python hooks¶
It is possible in QuantumATK to define “hooks”; Python functions or classes that are called before or after each MD step. These hooks can be used to provide customized on-the-fly analysis or monitoring of the system, or – as in this case – to modify the structure dynamically during the simulation.
You will now define a pre-step hook that will be used to strain the nanotube slightly for each step of the MD run:
With the Python script open in the Editor, scroll down to the bottom of the script and locate the block defining the
md_trajectory. The predefined tags “Left” and “Right” can now be used to apply constraints to the system. Change the line
md_trajectoryblock, add the line
and add a comma to the line immediately above it (
You should also define what “strainer” is: Add the following line immediately before the
strainer = StressStrainUtility()
The bottom of the script should now look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
# ------------------------------------------------------------- # Molecular Dynamics # ------------------------------------------------------------- initial_velocity = MaxwellBoltzmannDistribution( temperature=300.0*Kelvin, remove_center_of_mass_momentum=False ) method = NVTBerendsen( time_step=1*femtoSecond, reservoir_temperature=300*Kelvin, thermostat_timescale=100*femtoSecond, initial_velocity=initial_velocity ) strainer = StressStrainUtility() md_trajectory = MolecularDynamics( bulk_configuration, constraints=bulk_configuration.indicesFromTags(["Left","Right"]), trajectory_filename='mdtrajectory_cnt.hdf5', steps=20000, log_interval=200, method=method, pre_step_hook=strainer, )
Line 17 above initializes an instance of the class
StressStrainUtility, which is a Python class that you now will define. Insert the following at the very top of the script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
# Define a prestep function which can expand the system class StressStrainUtility: """ Perform a strain of a configuration over time. """ def __init__(self, delta=0.0001, skip=0): """ @param delta The strain to apply in each step @param first steps to "skip" strain """ self.__delta = [0.0,0.0,delta]*Angstrom self.__skip = skip self.stresses =  self.lengths =  def __call__(self, step, time, configuration, forces, stress): """ Strainer call. """ # Get the lattice vectors. u1, u2, u3 = configuration.primitiveVectors() # Don't apply strain in the earliest MD steps if step < self.__skip: return # Store the history self.stresses.append( Stress(configuration).evaluate()[2,2].inUnitsOf(eV/Angstrom**3) ) self.lengths.append( u3.inUnitsOf(Angstrom) ) # Increase the lattice vectors. u3 = u3 + self.__delta # Set the new lattice. configuration.setBravaisLattice(UnitCell(u1,u2,u3)) # Move all the atoms that are constrained on the right side. constraints = configuration.indicesFromTags("Right") for c in constraints: xyz = numpy.array(configuration.cartesianCoordinates()[c]) + numpy.array(self.__delta) configuration.setCartesianCoordinates(indices=[c], cartesian_coordinates=[xyz]*Angstrom) def length(self): return numpy.array(self.lengths)*Angstrom def stress(self): return numpy.array(self.stresses)*eV/Angstrom**3
This class defines a method to enable straining of a unit cell along the z-direction. You will use it to study how a CNT with a defect responds to strain.
As you can see from the script, the class has two inputs,
- defines how much the u3 vector (the z-direction) is expanded on every step in the MD calculation.
- defines how many steps should pass before the configur