<jupyter_start><jupyter_text>Creating and importing molecular systems in OpenMM  PreliminariesFirst, we import OpenMM. It's recommended that you always import this way:<jupyter_code>from simtk import openmm, unit
from simtk.openmm import app
import numpy as np<jupyter_output><empty_output><jupyter_text>The OpenMM `System` objectThe OpenMM [`System`](http://docs.openmm.org/7.1.0/api-python/library.htmlsystem) object is a container that completely specifies how to compute the forces and energies for all particles in the molecular system. Because it is part of the C++ OpenMM API, `System` (and the related `Force` classes) are not true Python objects but instead SWIG-wrapped C++ objects, so you will find their naming and accessor conventions conform to C++ (rather than Pythonic) standards.There are many ways to create or import OpenMM `System` objects:* We can assemble all the particles and define their interactions ourselves programmatically using the OpenMM C++ API* We could load in a serialized version of the `System` object via the built-in XML serializer* We can use the various importers in the [`simtk.openmm.app`](http://docs.openmm.org/7.1.0/api-python/app.html) layer to read in a system definition in AMBER, CHARMM, or gromacs format* We can create our own `System` object from a PDB file using the OpenMM [`ForceField`](http://docs.openmm.org/7.1.0/userguide/application.htmlforce-fields) facility* We can use a large variety of pre-built test systems provided by the [`openmmtools.testsystems`](http://openmmtools.readthedocs.io) module for testing code on a battery of different system types with different kinds of forcesRemember that if you want more information on `openmm.System`, you can use `help(openmm.System)`:  Creating a periodic Lennard-Jones systemWe'll start by building a simple periodic Lennard-Jones system using the Python wrappers for the main OpenMM C++ API.<jupyter_code># Define the parameters of the Lennard-Jones periodic system
nparticles = 512
reduced_density = 0.05
mass = 39.9 * unit.amu
charge = 0.0 * unit.elementary_charge
sigma = 3.4 * unit.angstroms
epsilon = 0.238 * unit.kilocalories_per_mole

# Create a system and add particles to it
system = openmm.System()
for index in range(nparticles):
    # Particles are added one at a time
    # Their indices in the System will correspond with their indices in the Force objects we will add later
    system.addParticle(mass)
    
# Set the periodic box vectors
number_density = reduced_density / sigma**3
volume = nparticles * (number_density ** -1)
box_edge = volume ** (1. / 3.)
box_vectors = np.diag([box_edge/unit.angstrom for i in range(3)]) * unit.angstroms
system.setDefaultPeriodicBoxVectors(*box_vectors)

# Add Lennard-Jones interactions using a NonbondedForce
force = openmm.NonbondedForce()
force.setNonbondedMethod(openmm.NonbondedForce.CutoffPeriodic)
for index in range(nparticles): # all particles must have parameters assigned for the NonbondedForce
    # Particles are assigned properties in the same order as they appear in the System object
    force.addParticle(charge, sigma, epsilon)
force.setCutoffDistance(3.0 * sigma) # set cutoff (truncation) distance at 3*sigma
force.setUseSwitchingFunction(True) # use a smooth switching function to avoid force discontinuities at cutoff
force.setSwitchingDistance(2.5 * sigma) # turn on switch at 2.5*sigma
force.setUseDispersionCorrection(True) # use long-range isotropic dispersion correction
force_index = system.addForce(force) # system takes ownership of the NonbondedForce object<jupyter_output><empty_output><jupyter_text>The OpenMM Python API uses units throughoutNote the use of unit-bearing quantities via [`simtk.unit`](http://docs.openmm.org/7.1.0/userguide/library.htmlunits-and-dimensional-analysis). OpenMM's Python API uses a powerful units system that prevents many common kinds of mistakes with unit conversion, such as those that caused the loss of the [Mars Polar Lander](http://www.cnn.com/TECH/space/9909/30/mars.metric.02/). We'll examine the units system in more detail later---for now, we simply recognize that best practices dictate we feed OpenMM unit-bearing quantities (though this is not strictly necessary), and that it will return unit-bearing quantities.<jupyter_code># construct a Quantity using the multiply operator
bond_length = 1.53 * unit.nanometer
# equivalently using the explicit Quantity constructor
bond_length = unit.Quantity(1.53, unit.nanometer)
# or more verbosely
bond_length = unit.Quantity(value=1.53, unit=unit.nanometer)
# print a unit in human-readable form
print(bond_length)
# or display it in machine-readable form
repr(bond_length)<jupyter_output>1.53 nm<jupyter_text>Accesssors for System attributes and ForcesThe [`System`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.System.htmlsimtk.openmm.openmm.System) object has a number of useful accessors for examining the contents of the system and<jupyter_code># Get the number of particles in the System
print('The system has %d particles' % system.getNumParticles())
# Print a few particle masses
for index in range(5):
    print('Particle %5d has mass %12.3f amu' % (index, system.getParticleMass(index) / unit.amu))
# Print number of constraints
print('The system has %d constraints' % system.getNumConstraints())
# Get the number of forces and iterate through them
print('There are %d forces' % system.getNumForces())
for (index, force) in enumerate(system.getForces()):
    print('Force %5d : %s' % (index, force.__class__.__name__))<jupyter_output>The system has 512 particles
Particle     0 has mass       39.900 amu
Particle     1 has mass       39.900 amu
Particle     2 has mass       39.900 amu
Particle     3 has mass       39.900 amu
Particle     4 has mass       39.900 amu
The system has 0 constraints
There are 1 forces
Force     0 : NonbondedForce<jupyter_text>Define positions for the Lennard-Jones particlesTo compute energies or forces, we will need to define some positions for the system before we can compute energies or forces.We'll generate some randomly, but as we will see later, there are many more ways to load molecular positions.<jupyter_code>positions = box_edge * np.random.rand(nparticles,3) 
print(positions)<jupyter_output>[[ 50.06589405  38.74885235  35.33400422]
 [ 50.95223274  50.29185888  12.95023497]
 [ 28.94210046  34.42082076  60.99670999]
 ..., 
 [ 49.8772534   60.166914    30.42399294]
 [ 56.75521618  37.75775794  53.37899838]
 [ 60.90425164  10.08568524  43.13366285]] A<jupyter_text>Computing energies and forcesTo compute energies and forces efficiently, OpenMM requires you create a [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.htmlsimtk.openmm.openmm.Context) that handles the computation on a particular piece of hardware. This could be a GPU or CPU using a specific set of fast computation kernels.OpenMM forces us to explicitly move data (positions, velocities, forces) into and out of the `Context` through specific calls so that we remember that each of these operations carries overhead of moving data across the bus to the GPU, for example. To achieve maximum speed, OpenMM can perform a number of operations---such as integrating many molecular dynamics steps---fully on the GPU without slowing things down by moving data back and forth over the bus. We'll see examples of this soon.First, we just want to compute energies and forces and then minimize the energy of our system. To do that, we first need to create an [`Integrator`](http://docs.openmm.org/7.1.0/userguide/application.htmlintegrators) that will be bound to the [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.htmlsimtk.openmm.openmm.Context):<jupyter_code># Create an integrator
timestep = 1.0 * unit.femtoseconds
integrator = openmm.VerletIntegrator(timestep)
# Create a Context using the default platform (the fastest abailable one is picked automatically)
# NOTE: The integrator is bound irrevocably to the context, so we can't reuse it
context = openmm.Context(system, integrator)<jupyter_output><empty_output><jupyter_text>We will look at [`Integrator`](http://docs.openmm.org/7.1.0/userguide/application.htmlintegrators) objects more in depth in [Module 02 - Integrators and Sampling](https://github.com/choderalab/openmm-tutorials/blob/master/02%20-%20Integrators%20and%20sampling.ipynb)We can also optionally specify which platform we want. OpenMM comes with the following [`Platforms:`](http://docs.openmm.org/7.1.0/userguide/application.htmlplatforms)* [`Reference`](http://docs.openmm.org/7.1.0/userguide/library.htmlplatforms) - A slow double-precision single-threaded CPU-only implementation intended for comparing fast implementations with a "verifiably correct" one* [`CPU`](http://docs.openmm.org/7.1.0/userguide/library.htmlcpu-platform) - A fast multithreaded mixed-precision CPU-only implementation* [`OpenCL`](http://docs.openmm.org/7.1.0/userguide/library.htmlopencl-platform) - A highly portable OpenCL implementation that can be used with GPU or CPU OpenCL drivers; supports multiple precision models (single, mixed, double)* [`CUDA`](http://docs.openmm.org/7.1.0/userguide/library.htmlcuda-platform) - The fastest implementation that uses [CUDA](https://developer.nvidia.com/cuda-downloads) for NVIDIA GPUs; supports multiple precision models (single, mixed, double)<jupyter_code># We have to create a new integrator for every Context since it takes ownership of the integrator we pass it
integrator = openmm.VerletIntegrator(timestep)
# Create a Context using the multithreaded mixed-precision CPU platform
platform = openmm.Platform.getPlatformByName('CPU')
context = openmm.Context(system, integrator, platform)<jupyter_output><empty_output><jupyter_text>The `System` object can be used by multiple `Contexts` because the `System` is copied and converted to the efficient `Platform` specific kernels inside the `Context` object. Changing parameters or adding new `Force`'s on the Python `System` itself will not update the representation inside the `Context`.<jupyter_code>from copy import deepcopy
# Create a new integrator we can throw away
throwaway_integrator = openmm.VerletIntegrator(timestep)
# Copy the System object for this example
copy_system = deepcopy(system)
throwaway_context = openmm.Context(copy_system, throwaway_integrator)
# Change something in the Python System, e.g. double the box size
copy_system.setDefaultPeriodicBoxVectors(*box_vectors*2)
# Observe how the box size in the Context and Python System are different
print([vector for i, vector in enumerate(copy_system.getDefaultPeriodicBoxVectors())])
print([vector for i, vector in enumerate(throwaway_context.getState().getPeriodicBoxVectors())])
# Cleanup
del throwaway_integrator, throwaway_context<jupyter_output>[Quantity(value=(14.766431834276288, 0.0, 0.0), unit=nanometer), Quantity(value=(0.0, 14.766431834276288, 0.0), unit=nanometer), Quantity(value=(0.0, 0.0, 14.766431834276288), unit=nanometer)]
[Quantity(value=(7.383215917138144, 0.0, 0.0), unit=nanometer), Quantity(value=(0.0, 7.383215917138144, 0.0), unit=nanometer), Quantity(value=(0.0, 0.0, 7.383215917138144), unit=nanometer)]<jupyter_text>There are ways to update paramters in an existing `Context`, but that topic will be covered in later tutorials.Once we have a [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.htmlsimtk.openmm.openmm.Context), we need to tell OpenMM we want to retrieve the energy and forces for a specific set of particle positions. This is done by retrieving a [`State`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.State.htmlsimtk.openmm.openmm.State) object from the [`Context`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.Context.htmlsimtk.openmm.openmm.Context) that contains *only* the information we want to retrieve so as to minimize the amount of data that needs to be sent over the bus from a GPU:<jupyter_code># Set the positions
context.setPositions(positions)
# Retrieve the energy and forces
state = context.getState(getEnergy=True, getForces=True)
potential_energy = state.getPotentialEnergy()
print('Potential energy: %s' % potential_energy)
forces = state.getForces()
print('Forces: %s' % forces[0:5])<jupyter_output>Potential energy: 20731546.609353863 kJ/mol
Forces: [(-0.4904191792011261, -2.0151243209838867, 2.990215539932251), (-4.348661422729492, -2.4672372341156006, 3.2111189365386963), (0.010116085410118103, -0.08782704174518585, -0.008425451815128326), (-0.17573882639408112, -0.07705540955066681, 0.25119271874427795), (-1.2817492485046387, 1.4227875471115112, -0.6091694235801697)] kJ/(nm mol)<jupyter_text>Note that the forces are returned as a `list` of tuples with units attached. If we want a numpy array instead, we could convert it, but it's much easier just use the `asNumpy=True` argument to [`state.getForces`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.State.htmlsimtk.openmm.openmm.State.getForces)<jupyter_code># Get forces as numpy array
forces = state.getForces(asNumpy=True)
print('Forces: %s' % forces)<jupyter_output>Forces: [[ -4.90419179e-01  -2.01512432e+00   2.99021554e+00]
 [ -4.34866142e+00  -2.46723723e+00   3.21111894e+00]
 [  1.01160854e-02  -8.78270417e-02  -8.42545182e-03]
 ..., 
 [ -6.53141165e+00  -2.62020969e+00  -3.67551947e+00]
 [  2.32062773e+04   1.06050898e+05   2.38855234e+05]
 [ -4.50388193e+00   1.33601656e+01  -1.09453621e+01]] kJ/(nm mol)<jupyter_text>Minimizing the potential energyYou'll notice the energy and force magnitude is pretty large:<jupyter_code># Compute the energy
state = context.getState(getEnergy=True, getForces=True)
potential_energy = state.getPotentialEnergy()
print('Potential energy: %s' % potential_energy)
# Compute the force magnitude
forces = state.getForces(asNumpy=True)
force_magnitude = (forces**2).sum().sqrt()
print('Force magnitude: %s' % force_magnitude)<jupyter_output>Potential energy: 20731546.60935385 kJ/mol
Force magnitude: 3064549996.115365 kJ/(nm mol)<jupyter_text>If we tried to do dynamics at this point, the system will likely explode!OpenMM provides a [`LocalEnergyMinimizer`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.LocalEnergyMinimizer.htmlsimtk.openmm.openmm.LocalEnergyMinimizer) that can be used to bring the force magnitude to be low enough to be able to run a simulation that won't explode.<jupyter_code># Minimize the potential energy
openmm.LocalEnergyMinimizer.minimize(context)

# Compute the energy and force magnitude after minimization
state = context.getState(getEnergy=True, getForces=True)
potential_energy = state.getPotentialEnergy()
print('Potential energy: %s' % potential_energy)
forces = state.getForces(asNumpy=True)
force_magnitude = (forces**2).sum().sqrt()
print('Force magnitude: %s' % force_magnitude)<jupyter_output>Potential energy: -202.54488264416048 kJ/mol
Force magnitude: 138.81753123729027 kJ/(nm mol)<jupyter_text>Serializing the System object to disk or for transport over the networkYou can serialize and restore `System` objects as a string (which can be written to disk) via the [`XmlSerializer`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.openmm.XmlSerializer.htmlsimtk.openmm.openmm.XmlSerializer) class:<jupyter_code># Serialize to a string
system_xml = openmm.XmlSerializer.serialize(system)
# Restore from a string
restored_system = openmm.XmlSerializer.deserialize(system_xml)
assert(system.getNumParticles() == restored_system.getNumParticles())
# Peek at the first 15 lines of the XML file
system_xml.split('\n')[:15]<jupyter_output><empty_output><jupyter_text>Load a molecular system defined by AMBER, CHARMM, or gromacsThe OpenMM [`app` layer](http://docs.openmm.org/7.1.0/userguide/application.htmlusing-amber-files) provides convenience classes that help you load in systems defined in AMBER, CHARMM, or gromacs.   Loading an AMBER systemWe can use [`AmberPrmtopFile`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.app.amberprmtopfile.AmberPrmtopFile.htmlsimtk.openmm.app.amberprmtopfile.AmberPrmtopFile) to load an Amber `prmtop` file and [`InpcrdFile`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.app.amberinpcrdfile.AmberInpcrdFile.htmlsimtk.openmm.app.amberinpcrdfile.AmberInpcrdFile) to load an `inpcrd` file:<jupyter_code># Load in an AMBER system
from simtk.openmm import app
prmtop = app.AmberPrmtopFile('resources/alanine-dipeptide-implicit.prmtop')
inpcrd = app.AmberInpcrdFile('resources/alanine-dipeptide-implicit.inpcrd')
system = prmtop.createSystem(nonbondedMethod=app.NoCutoff, implicitSolvent=app.OBC2, constraints=app.HBonds)
positions = inpcrd.getPositions(asNumpy=True)

# Compute the potential energy
def compute_potential(system, positions):
    """Print the potential energy given a System and positions."""
    integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds)
    context = openmm.Context(system, integrator)
    context.setPositions(positions)
    print('Potential energy: %s' % context.getState(getEnergy=True).getPotentialEnergy())
    # Clean up
    del context, integrator
    
compute_potential(system, positions)<jupyter_output>Potential energy: -137.4395293410778 kJ/mol<jupyter_text>Loading a CHARMM systemWe can also [load CHARMM files](http://docs.openmm.org/7.1.0/userguide/application.htmlusing-charmm-files):<jupyter_code># Load in a CHARMM system
from simtk.openmm import app
psf = app.CharmmPsfFile('resources/ala_ala_ala.psf')
pdbfile = app.PDBFile('resources/ala_ala_ala.pdb')
params = app.CharmmParameterSet('resources/charmm22.rtf', 'resources/charmm22.par')
system = psf.createSystem(params, nonbondedMethod=app.NoCutoff, constraints=app.HBonds)
positions = pdbfile.getPositions(asNumpy=True)
compute_potential(system, positions)<jupyter_output>Potential energy: 187615.39653015137 kJ/mol<jupyter_text>Loading a gromacs systemWe can also [load gromacs files](http://docs.openmm.org/7.1.0/userguide/application.htmlusing-gromacs-files), though you'll want to have the gromacs parameter files installed first.You can install a version of gromacs via `conda` with:```conda install --yes -c bioconda gromacs```<jupyter_code># Load in a gromacs system
from simtk.openmm import app
gro = app.GromacsGroFile('resources/input.gro')
# Make sure you change this to your appropriate gromacs include directory!
gromacs_include_filepath = '/Users/choderaj/miniconda3/share/gromacs/top/'
top = app.GromacsTopFile('resources/input.top', periodicBoxVectors=gro.getPeriodicBoxVectors(), includeDir=gromacs_include_filepath)
system = top.createSystem(nonbondedMethod=app.PME, nonbondedCutoff=1*unit.nanometer, constraints=app.HBonds)
positions = gro.getPositions(asNumpy=True)
compute_potential(system, positions)<jupyter_output>Potential energy: -115290.90428611072 kJ/mol<jupyter_text>Creating a `System` using the OpenMM `ForceField` classOpenMM also provides a number of [force fields](http://docs.openmm.org/7.1.0/userguide/application.htmlforce-fields) that have been converted into a [universal XML force field description format](http://docs.openmm.org/7.1.0/userguide/application.htmlwriting-the-xml-file) that can also be [extended in a modular manner](http://docs.openmm.org/7.1.0/userguide/application.htmlextending-forcefield). Several [common AMBER protein force fields are provided](http://docs.openmm.org/7.1.0/userguide/application.htmlforce-fields) that work well for protein systems in which all atoms are already present.<jupyter_code># Create an OpenMM system using the ForceField class
pdb = app.PDBFile('resources/input.pdb')
forcefield = app.ForceField('amber99sb.xml', 'tip3p.xml')
system = forcefield.createSystem(pdb.topology, nonbondedMethod=app.PME, nonbondedCutoff=1*unit.nanometer, constraints=app.HBonds)
positions = pdb.positions
compute_potential(system, positions)<jupyter_output>Potential energy: -115281.71871208795 kJ/mol<jupyter_text>Visualizing the system and using `Topology` objects While the `System` objects don't contain any information on the *identities* of the particles or how these are organized into residues or molecules, we can extract a [`Topology`](http://docs.openmm.org/7.1.0/api-python/generated/simtk.openmm.app.topology.Topology.htmlsimtk.openmm.app.topology.Topology) object that provides this information from a PDB file:<jupyter_code># Extract the topology from a PDB file
pdbfile = app.PDBFile('resources/alanine-dipeptide-implicit.pdb')
positions = pdbfile.getPositions()
topology = pdbfile.getTopology()<jupyter_output><empty_output><jupyter_text>OpenMM provides a way to write a frame to a PDB file should you want to visualize your initial configuration:<jupyter_code># Write out a PDB file
with open('output.pdb', 'w') as outfile:
    app.PDBFile.writeFile(topology, positions, outfile)<jupyter_output><empty_output><jupyter_text>If working in a Jupyter notebook, we can use [`mdtraj`](http://mdtraj.org) and [`nglview`](https://github.com/arose/nglview) to visualize the system:<jupyter_code># Create an MDTraj Trajectory object
import mdtraj
mdtraj_topology = mdtraj.Topology.from_openmm(topology)
traj = mdtraj.Trajectory(positions/unit.nanometers, mdtraj_topology)

# View it in nglview
import nglview
view = nglview.show_mdtraj(traj)
view.add_ball_and_stick('all')
view.center_view(zoom=True)
view<jupyter_output><empty_output><jupyter_text>Prebuilt systems with `openmmtools.testsystems` The [`openmmtools.testsystems`](http://openmmtools.readthedocs.io/en/latest/testsystems.html) module provides a number of pre-built test systems that are very useful for testing your code or benchmarking your algorithms. The full list of test systems can be found [here](http://openmmtools.readthedocs.io/en/latest/testsystems.html), but we'll highlight a few below.<jupyter_code>from openmmtools import testsystems

t = testsystems.HarmonicOscillator()
system, positions, topology = t.system, t.positions, t.topology

print(positions)
help(t)
# Create a Lennard-Jones cluster with a harmonic spherical restraint:
t = testsystems.LennardJonesCluster()

def visualize(t):
    import mdtraj
    mdtraj_topology = mdtraj.Topology.from_openmm(t.topology)
    traj = mdtraj.Trajectory([t.positions/unit.nanometers], mdtraj_topology)

    # View it in nglview
    import nglview
    view = nglview.show_mdtraj(traj)
    if t.system.getNumParticles() < 2000:
        view.add_ball_and_stick('all')
    view.center_view(zoom=True)
    return view

visualize(t)
t = testsystems.LennardJonesFluid(reduced_density=0.90)
visualize(t)
t = testsystems.WaterBox()
visualize(t)
t = testsystems.AlanineDipeptideVacuum()
visualize(t)
# The Joint AMBER-CHARMM (JAC) DHFR in explicit solvent benchmark system
t = testsystems.DHFRExplicit()
visualize(t)<jupyter_output><empty_output><jupyter_text>There are lots and lots of test systems defined! You can find the complete list and descriptions [here](http://openmmtools.readthedocs.io/en/latest/testsystems.html).Try some!<jupyter_code># Get all subclasses of type `TestSystem`
from openmmtools.tests.test_testsystems import get_all_subclasses
for t in get_all_subclasses(testsystems.TestSystem):
    print(t.__name__)<jupyter_output>HarmonicOscillator
MethanolBox
AMOEBAIonBox
ConstraintCoupledHarmonicOscillator
CustomExternalForcesTestSystem
DHFRExplicit
AMOEBAProteinBox
AlanineDipeptideVacuum
AlchemicalAlanineDipeptide
LennardJonesFluid
LennardJonesFluidTruncated
LennardJonesFluidSwitched
LennardJonesGrid
SrcImplicit
WCAFluid
HostGuestImplicit
HostGuestImplicitHCT
HostGuestImplicitOBC1
HostGuestImplicitGBn
HostGuestImplicitGBn2
HostGuestImplicitOBC2
TolueneImplicit
TolueneImplicitHCT
TolueneImplicitOBC1
TolueneImplicitGBn2
TolueneImplicitGBn
TolueneImplicitOBC2
SrcExplicit
SrcExplicitReactionField
LysozymeImplicit
LennardJonesPair
HostGuestExplicit
MolecularIdealGas
DiatomicFluid
UnconstrainedDiatomicFluid
ConstrainedDiatomicFluid
DipolarFluid
UnconstrainedDipolarFluid
ConstrainedDipolarFluid
SodiumChlorideCrystal
WaterBox
FiveSiteWaterBox
FlexibleReactionFieldWaterBox
AlchemicalWaterBox
FlexiblePMEWaterBox
DischargedWaterBoxHsites
FlexibleWaterBox
FlexibleDischargedWaterBox
GiantFlexibleDischargedWaterBox
GiantF[...]
{'fraction_non_alphanumeric': 0.09580122790391034, 'fraction_numerical': 0.046973505294820556, 'mean_word_length': 5.986183074265976, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 76, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '22', 'dir': 'jupyter-structured-clean-dedup', 'id': '340347', 'license': 'MIT', 'n_tokens_mistral': 8566, 'n_tokens_neox': 7663, 'n_words': 2160, 'path': '01 - Creating and importing molecular systems in OpenMM.ipynb', 'repo_name': 'choderalab/openmm-tutorials', 'size': '24269'}