Here we include some programs we developed for analysis of lipid bilayers. Those programs were used in computations for article DMG-alpha - a computational geometry package for multi-molecular systems (submitted).
This script computes volume per lipid and approximate solvent accessible surface of the surface of lipid bilayer.
from pydmga.geometry import OrthogonalGeometry
from pydmga.container import Container
from pydmga.diagram import Diagram
from pydmga.io import pdb
from math import sqrt
# this is basic filename of the dataset, withou .pdb extension
filename = "drec-1_590-600ns"
# use heavy atoms only - if True then we skip all hydrogen atoms
hao = True
# old lipid stops at what residue?
end_lipid_at = "UDC"
# new lipid starts at what residue?
start_lipid_at = "KDO"
# we will read from <filename>.pdb
in_file = file("{0}.pdb".format(filename), "r")
# we will write to <filename>.dat
out_file = file("{0}.dat".format(filename), "w")
try:
# this counts current frame, for output
frame = 0
# we collect volume and area per lipid per frame
out_file.write("frame lipid volume area\n")
while True: # iterate over all frames
# here we remember data from pdb for future use
particles = []
while True: # iterate over elements in frame
item = pdb.PDBRecord(pdb.readnext(in_file))
if item.type() == "CRYST1":
# create box geometry periodic in all directions
geometry = OrthogonalGeometry(item["a"], item["b"], item["c"], True, True, True)
# create container for atoms
container = Container(geometry)
if item.type() == "ATOM":
# add new item, if we are using only hao, then skip it if its hydrogen
if (item["atom"][0] != 'H' and item["atom"][1] != 'H') or not hao:
# add perticle to the container
container.add(item.as_particle())
# remember all data for future use
particles.append(item)
if item.type() == "ENDMDL" or item.type() == "TER":
# stop reading this frame
break
# create new Power Diagram
diagram = Diagram(container)
# here we will count which lipid molecule we have
molecule_no = 0
# this is to allow triggering start_lipid_at test for the first iteration
residue = end_lipid_at
#iterate over all cells in this diagram
for i, cell in enumerate(diagram):
# if we found one solvent then skip the rest of atoms - they are solvent
if particles[i]["residue"] == "SOL" or particles[i]["residue"] == "ION":
break
# we change lipid molecule only if we pass from <end_lipid_at> residue to <start_lipid_at> residue
if residue == end_lipid_at and particles[i]["residue"] == start_lipid_at:
# write data to a file if there is a data
if molecule_no: out_file.write("{0} {1} {2} {3}\n".format(frame, molecule_no, volume, area))
molecule_no +=1
area = 0.0
volume = 0.0
# to track when to change residue
residue = particles[i]["residue"]
# find cell volume
volume += cell.volume()
# iterate over all sides to find contact area for this atom
for side in cell.sides:
neighbour = side.neighbour
if particles[neighbour]['residue'] == "SOL" or particles[neighbour]['residue'] == "ION":
# we have solvent <-> particle contact
area += side.area()
# need to write last lipid (we changed frames, not lpipid inside the frame)
out_file.write("{0} {1} {2} {3}\n".format(frame, molecule_no, volume, area))
# count new frame
frame += 1
except StopIteration:
# pdb file ends
pass
This script computes number of contacts lipid to solvent and lipid to ion.
from pydmga.geometry import OrthogonalGeometry
from pydmga.container import Container
from pydmga.diagram import Diagram
from pydmga.io import pdb
from math import sqrt
# this is basic filename of the dataset, withou .pdb extension
filename = "drec-1_590-600ns"
# old lipid stops at what residue?
end_lipid_at = "UDC"
# new lipid starts at what residue?
start_lipid_at = "KDO"
# we will read from <filename>.pdb
in_file = file("{0}.pdb".format(filename), "r")
# we will write to <filename>.dat
out_file = file("{0}.dat".format(filename), "w")
try:
# this counts current frame, for output
frame = 0
# we collect number of water in contact and number of ions in contact
out_file.write("frame lipid nb_h2o nb_ion\n")
while True: # iterate over all frames
# here we remember data from pdb for future use
particles = []
while True: # iterate over elements in frame
item = pdb.PDBRecord(pdb.readnext(in_file))
if item.type() == "CRYST1":
# create box geometry periodic in all directions
geometry = OrthogonalGeometry(item["a"], item["b"], item["c"], True, True, True)
# create container for atoms
container = Container(geometry)
if item.type() == "ATOM":
# add new item, for simplicity we use only heavy atoms
if (item["atom"][0] != 'H' and item["atom"][1] != 'H'):
# add perticle to the container
container.add(item.as_particle())
# remember all data for future use
particles.append(item)
if item.type() == "ENDMDL" or item.type() == "TER":
# stop reading this frame
break
# create new Power Diagram
diagram = Diagram(container)
# here we will count which lipid molecule we have
molecule_no = 0
# this is to allow triggering start_lipid_at test for the first iteration
residue = end_lipid_at
#iterate over all cells in this diagram
for i, cell in enumerate(diagram):
# break from iteration when SOL/ION part of file reached
if particles[i]["residue"] == "SOL" or particles[i]["residue"] == "ION": break
# we change lipid molecule only if we pass from <end_lipid_at> residue to <start_lipid_at> residue
if residue == end_lipid_at and particles[i]["residue"] == start_lipid_at:
# write data to a file if there is a data
if molecule_no: out_file.write("{0} {1} {2} {3}\n".format(frame, molecule_no, len(nb_h2o), len(nb_ion)))
molecule_no +=1
# here we hold water particles in contact
nb_h2o = []
# here we hold ions in contact
nb_ion = []
# to track when to change residue
residue = particles[i]["residue"]
# iterate over all sides to find neighbours
for side in cell.sides:
n = side.neighbour
if particles[n]['residue'] == "SOL" and not n in nb_h2o: nb_h2o.append(n)
if particles[n]['residue'] == "ION" and not n in nb_ion: nb_ion.append(n)
# need to write last lipid (we changed frames, not lpipid inside the frame)
out_file.write("{0} {1} {2} {3}\n".format(frame, molecule_no, len(nb_h2o), len(nb_ion)))
# count new frame
frame += 1
except StopIteration:
# pdb file ends
pass
This script computes 2D voronoi diagram on the plane for all atoms in GN2 groups and cumulates them to get area per lipid.
from pydmga.geometry import OrthogonalGeometry
from pydmga.geometry import CastOrthoPlaneGeometry
from pydmga.container import Container
from pydmga.diagram import Diagram
from pydmga.io import pdb
filename = "drec-1_590-600ns"
groups = ["GN2"]
end_lipid_at = "UDC"
start_lipid_at = "KDO"
in_file = file("{0}.pdb".format(filename), "r")
out_file = file("{0}.dat".format(filename), "w")
try:
frame = 0
out_file.write("frame lipid sa\n")
while True:
lipid_by_atom = []
residue = ''
molecule_id = 0
while True:
item = pdb.PDBRecord(pdb.readnext(in_file))
if item.type() == "CRYST1":
(a, b, c) = (item["a"], item["b"], item["c"])
box_geometry = OrthogonalGeometry(a, b, c, True, True, True)
geometry_up = CastOrthoPlaneGeometry(box_geometry, (0, 0, 1))
container_up = Container(geometry_up)
if item.type() == "ATOM":
if residue == end_lipid_at and item['residue'] == start_lipid_at:
molecule_id += 1
if item["residue"] in groups and item["atom"][0] != 'H' and item["atom"][1] != 'H':
if item['z'] > c / 2:
container_up.add(item.as_particle())
lipid_by_atom.append(molecule_id)
residue = item["residue"]
if item.type() == "ENDMDL" or item.type() == "TER":
break
diagram_up = Diagram(container_up)
all_area = 0.0
molecule_id = lipid_by_atom[0]
sa = 0.0
for i, cell in enumerate(diagram_up):
if molecule_id != lipid_by_atom[i]:
out_file.write("{0} {1} {2}\n".format(frame, molecule_id, sa))
sa = 0.0
molecule_id = lipid_by_atom[i]
for side in cell.sides:
neighbour = side.neighbour
if geometry_up.on_boundary(neighbour):
sa += side.area()
out_file.write("{0} {1} {2}\n".format(frame, molecule_id, sa))
frame += 1
except StopIteration:
pass
This script computes 2D voronoi diagram on the plane for geometric centers of GN2 groups.
from pydmga.geometry import OrthogonalGeometry
from pydmga.geometry import CastOrthoPlaneGeometry
from pydmga.container import Container
from pydmga.diagram import Diagram
from pydmga.io import pdb
filename = "drec-1_590-600ns"
gc = False
groups = ["GN2"]
end_lipid_at = "UDC"
start_lipid_at = "KDO"
in_file = file("{0}.pdb".format(filename), "r")
out_file = file("{0}.dat".format(filename), "w")
try:
frame = 0
out_file.write("frame lipid sa\n")
while True:
lipid_by_atom = []
residue = ''
this_group = []
molecule_id = 0
while True:
item = pdb.PDBRecord(pdb.readnext(in_file))
if item.type() == "CRYST1":
(a, b, c) = (item["a"], item["b"], item["c"])
box_geometry = OrthogonalGeometry(a, b, c, True, True, True)
geometry_up = CastOrthoPlaneGeometry(box_geometry, (0, 0, 1))
container_up = Container(geometry_up)
if item.type() == "ATOM":
if residue == end_lipid_at and item['residue'] == start_lipid_at:
molecule_id += 1
x = sum([p[0] for p in this_group]) / len(this_group)
y = sum([p[1] for p in this_group]) / len(this_group)
z = sum([p[2] for p in this_group]) / len(this_group)
if z > c / 2:
container_up.add(container_up.size(), x, y, z, 1.0)
lipid_by_atom.append(molecule_id)
this_group = []
if item["residue"] in groups and item["atom"][0] != 'H' and item["atom"][1] != 'H':
this_group.append(item.as_coords())
residue = item["residue"]
if item.type() == "ENDMDL" or item.type() == "TER":
x = sum([p[0] for p in this_group]) / len(this_group)
y = sum([p[1] for p in this_group]) / len(this_group)
z = sum([p[2] for p in this_group]) / len(this_group)
if z > c / 2:
container_up.add(container_up.size(), x, y, z, 1.0)
lipid_by_atom.append(molecule_id)
break
diagram_up = Diagram(container_up)
for i, cell in enumerate(diagram_up):
molecule_id = lipid_by_atom[i]
for side in cell.sides:
neighbour = side.neighbour
if geometry_up.on_boundary(neighbour):
out_file.write("{0} {1} {2}\n".format(frame, molecule_id, side.area()))
frame += 1
except StopIteration:
pass
This program was used in the computation of water molecules trapped inside lipid bilayer in poster presentation at Bioinformatics Conference 2013, SocBIN/BIT13.
import sys
sys.path.append('../')
from pydmga.geometry import OrthogonalGeometry
from pydmga.geometry import CastSphereGeometry
from pydmga.geometry import CastCylinderGeometry
from pydmga.container import Container
from pydmga.diagram import Diagram
from pydmga.render import geometry
from pydmga.render import graphics
from pydmga.render import render
from random import random
#from dmga.io.pdb import PDBReader
solvent_from = -1
data = []
import fileinput
i = 0
cryst_line = ""
for line in fileinput.input():
tag = line[0:6].strip()
#print tag
if (tag == 'CRYST1'):
cryst_line = line
box_x = float(line[6:15].strip())
box_y = float(line[15:24].strip())
box_z = float(line[24:33].strip())
tilt_x = float(line[33:40].strip())
tilt_y = float(line[40:47].strip())
tilt_z = float(line[47:54].strip())
group = line[55:66]
z_value = int(line[66:70].strip())
#print "we have box:", (box_x, box_y, box_z), (tilt_x, tilt_y, tilt_z), group, z_value
if (tag == 'ATOM'):
id = int(line[6:11].strip())
atom_name = line[12:16]
alt_loc = line[16:17]
res_name = line[17:20]
chain_id = line[21:22]
seq_no = int(line[22:27])
x = float(line[30:38].strip())
y = float(line[38:46].strip())
z = float(line[46:54].strip())
r = float(line[54:60].strip())
# drop rest...
if (atom_name[1] != 'H'):
data.append( (i, x, y, z, r) )
if (solvent_from < 0 and res_name.strip() == 'SOL'):
solvent_from = i
i += 1
#print "We have atom:", id, atom_name, alt_loc, res_name, chain_id, seq_no, (x, y, z, r)
geometry = OrthogonalGeometry(box_x, box_y, box_z, True, True, True)
container = Container(geometry)
#print "Data lenght:", solvent_from, len(data)
container.add(data)
diagram = Diagram(container)
#display = render.Render()
colors = []
surface_by_part = []
surface_by_part_half = []
mark = [False for i in range(len(data)+1)]
print len(mark)
for i in range(solvent_from, len(data)):
if (mark[i]): continue
queue = [i]
#print "new part at", i
mark[i] = True
surface_by_part.append([])
surface_by_part_half.append([])
while(len(queue) > 0):
i = queue.pop()
cell = diagram.get_cell(i)
for side in cell.sides:
neighbour = side.neighbour
polygon = side.as_coords()
if (neighbour < solvent_from):
if (neighbour < 50 * 160):
surface_by_part_half[-1].append(0)
else:
surface_by_part_half[-1].append(1)
surface_by_part[-1].append(polygon) ##add new polygon to this part
else:
if (not(mark[neighbour])):
mark[neighbour] = True
queue.append(neighbour)
outer = surface_by_part[0]
surface_by_part[0] = []
surface_by_part.insert(0, [])
for i in range(len(outer)):
surface_by_part[surface_by_part_half[0][i]].append(outer[i])
import sys
filename = ".".join(sys.argv[1].split(".")[0:-1])
print "filename is", filename
pa_id = 100000000
#print "There are", len(surface_by_part), "parts of water in this system."
f = None
for i, part in enumerate(surface_by_part):
file_count = 0
for polygon in part:
if (pa_id + len(polygon) >= 9999):
if (f is not None): f.close()
file_count += 1
f = open("/home/robson/{0}_{1:03d}_{2:03d}.pdb".format(filename, i, file_count), "w")
f.write(cryst_line)
pa_id = 0
#print last vertex of polygon
to_connect = []
for v in polygon:
pa_id += 1
to_connect.append(pa_id)
if (i == 0):
if v[2] < 30.0:
v = (v[0], v[1], v[2] + box_z)
if (i == 1):
if v[2] > 30.0:
v = (v[0], v[1], v[2] - box_z)
f.write("HETATM{0: 5d} PS1 PSD P 1 {1: 8.3f}{2: 8.3f}{3: 8.3f} 0.00 0.00 PSDOPS \n".format(pa_id, v[0], v[1], v[2]))
to_connect.insert(0, pa_id)
for j in range(len(polygon)):
f.write("CONECT{0: 5d}{1: 5d}\n".format(to_connect[j], to_connect[j+1]))
pa_id = 100000000
if not f.closed:
f.close()
#set connect_cutoff,0.0
#set connect_mode,1
#display.add_outline_polygon(polygon, color)
#display.run()