structures_example¶
This notebook imports the fundamental objects of the streamm.structure module and goes through the functionality of each
from pprint import pprint
import copy
Set up a log file for this example so we can read what exactly streamm is doing, if we feel like it.
import logging
logging.basicConfig(filename='structures_example.log',level=logging.INFO)
Let’s start with the Particle object
from streamm.structures.particle import Particle
Create a particle object with label ‘C1’
p_i = Particle(label='C1')
print(p_i)
Assign the carbon element to the particle
p_i.set_element('C')
Let’s oxidize the carbon just to make the charge non-zero
p_i.charge = -1.0
Check that the element properties were set to the particle
print(p_i.show_attributes())
Say we want to change the units to SI
Let’s look at the current units of the particle instance
default_unit_conf = copy.deepcopy(p_i.unit_conf)
pprint(default_unit_conf)
Create a dictionary with new units
new_unit_conf = {'length':'m','mass':'kg','charge':'C'}
p_i.update_units(new_unit_conf)
print(p_i.show_attributes())
That’s cool, but we should stick with the default units, so let’s change them back
p_i.update_units(default_unit_conf)
print(p_i.show_attributes())
Let’s create another particle and set the element to hydrogen
p_j = Particle(symbol='H')
print(p_j.show_attributes())
Let’s make an empty structure container
from streamm.structures.structure import Structure
mol_i = Structure('methane')
Now let’s construct a molecule
We can add the carbon at the origin using the add_partpos()
function.
pos_i = [0.0,0.0,0.0]
mol_i.add_partpos(p_i,pos_i)
for p_index,particle_i in mol_i.particles.items():
if( particle_i.symbol == 'H' ):
particle_i.residue = 1
h_cnt += 1
for p_index,particle_i in mol_i.particles.items():
print(p_index,particle_i)
print("Now the structure container has {} particle ".format(mol_i.n_particles))
Find the positions of the hydrogens to give a tetrahedral molecular geometry
import numpy as np
import decimal
bond_length = p_i.bonded_radius + p_j.bonded_radius
print(bond_length,mol_i.unit_conf['length'])
tet_a = bond_length/np.sqrt(3)
print(tet_a)
Add hydrogens
pos_j = [tet_a,tet_a,tet_a]
mol_i.add_partpos(p_j,pos_j)
for p_index,particle_i in mol_i.particles.items():
print(p_index,particle_i)
We can add the subsequent hydrogens using the same particle object since add_partpos makes a deepcopy of the object when adding to the structure container
pos_j = [-tet_a,-tet_a,tet_a]
mol_i.add_partpos(p_j,pos_j)
pos_j = [-tet_a,tet_a,-tet_a]
mol_i.add_partpos(p_j,pos_j)
pos_j = [tet_a,-tet_a,-tet_a]
mol_i.add_partpos(p_j,pos_j)
Check the position array
print(mol_i.positions)
The particles instance variable of the structure container is a dictionary, so we can just loop over that using the iteritems() function.
for p_index,particle_i in mol_i.particles.items():
print(p_index,particle_i)
Hum, let’s fix the labels of the hydrogens…
h_cnt = 1
for p_index,particle_i in mol_i.particles.items():
if( particle_i.symbol == 'H' ):
particle_i.label = 'H{}'.format(h_cnt)
h_cnt += 1
for p_index,particle_i in mol_i.particles.items():
print(p_index,particle_i)
Okay, that looks better
Print .xyz file and check geometry with a molecular viewer such as Avogadro (https://avogadro.cc/)
mol_i.write_xyz()
Looks good, you should have the geometry of a methane molecule with a C-H bond length of 1.2 Angstroms
However, we have not told streamm about the bonds. There are a few ways to do this, let’s do it explicitly with the Bond object fist.
from streamm.structures.bond import Bond
based on the particle index values
b_ij = Bond(0,1)
Now add the bond to the bonds dictionary in the structure container
mol_i.add_bond(b_ij)
print("Now the structure container has {} particle/s and {} bond/s".format(mol_i.n_particles,mol_i.n_bonds))
Neat, but adding all the bonds, bond angles and dihedrals explicitly would be pretty tedious, so let’s use some functions to do that.
First, let’s guess the bonded_nblist
of the molecule based on the
bonded_radius
of each particle (atom)
mol_i.bonded_nblist = mol_i.guess_nblist(0,radii_buffer=1.35)
print(mol_i.bonded_nblist)
Let’s take a look at the neighbor lists list
and index
instance
variables
print(mol_i.bonded_nblist.list)
print(mol_i.bonded_nblist.index)
Looking at the index
for particle 0, we get that it has neighbors in
the list
from 0:3 (index[0]:index[0+1]-1). Therefore, we know
particle 0 has [1, 2, 3, 4] for neighbors.
print(mol_i.bonded_nblist.calc_nnab(0))
Now we can use the bonded neighbor list to construct the bonds, bond angles and dihedrals
mol_i.bonded_bonds()
mol_i.bonded_angles()
mol_i.bonded_dih()
print(mol_i.print_properties())
A little easier than adding everything by hand
We can dump a json file methane_struc.json
for checkpointing the
entire structure
mol_json = mol_i.export_json()
print(mol_i.tag)
We can reload the molecule as another instance of the Structure object
mol_test = Structure('methane')
mol_test.import_json()
Then we can use the structure’s eq and ne functions to make sure they are the same
if( mol_test != mol_i ):
print("Molecules not equal")
elif( mol_test == mol_i ):
print("Molecules equal")
else:
print("Uh Oh")
Now let’s set some groups. This is a little unnecessary for methane, but it will come in super handy if you have a large simulation of thousands of molecules.
To do this we will set the residue variable for each particle.
mol_i.particles[0].residue = 0
for p_index,particle_i in mol_i.particles.items():
if( particle_i.symbol == 'H' ):
particle_i.residue = 1
print(particle_i, particle_i.residue)
import streamm.structures.group as group
groups_i = group.Groups('methane_residues',mol_i)
Find groups based on residue variable
groups_i.group_prop('residue',groups_i.tag)
for g_index,group_i in groups_i.groups.items():
print(group_i.pkeys)
print(group_i.write_coord())
Looks good. We have two groups in the group container, the first with the carbon particle index 0 and the rest are the hydrogens.
res_json = groups_i.export_json()
Now let’s change the units
mol_i.update_units({'length':'pm'})
Check the positions
print(mol_i.positions)
Check the particle bond radii
for p_index,particle_i in mol_i.particles.items():
print(particle_i,particle_i.bonded_radius)