summaryrefslogtreecommitdiff
path: root/cad/plugins/NanoDynamics-1/TranslateStruts.py
blob: 7add0facebf420402b57ce406f6579845194b994 (plain)
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# Copyright 2008 Nanorex, Inc.  See LICENSE file for details.

"""
This program can be used to translate cartesian coordinates of PAM5
strut ends into the basis necessary to generate gromacs virtual
particles (which are used to represent the ends of those struts).
First it reads the locations of the three real atoms which represent
and define the base pair plane, and the coordinate basis within that
plane.  Those atoms are the groove (a Gv5 or Gr5 pseudo-atom), which
is at the origin of the virtual particle basis; an Ss5 referred to as
'a'; and another Ss5 referred to as 'b'.  In a normal strand of BDNA,
the two 'a' sugars on a stacked pair of base pairs are farther apart
than the 'b' sugars.  The 'a' sugars are on opposite strands from each
other.

Next, a set of positions of strut ends are read.  These should be
co-planer to the three atoms read in above.  The vector 'va'
represents the displacement from the groove atom to sugar 'a', and
'vb' represents the displacement from the groove atom to sugar 'b'.
The location of the strut end is then (groove + A*va + B*vb).

The three coefficients A, B, and C necessary to reach the strut end
are printed.  The third basis vector is the cross product of the first
two.  For strut ends which are coplaner, C should be negligable.  The
length of the displacement from the read strut end position to the one
calculated based on the new basis is printed as 'error'.  This same
quantity calculated without the C component is printed as 'error2d'.
Both error values should be small.

"""

import sys
import math

from Numeric import array
from LinearAlgebra import inverse

# a nice upgrade would be to read values selected from the NE1 history
# buffer, which look like this:
#
# [X = 20.260] [Y = 7.700] [Z = 3.480]
def readVector():
    line = sys.stdin.readline()
    (xs, ys, zs) = line.strip().split(" ")
    return [float(xs), float(ys), float(zs)]

# most of the routines below can probably be replaced with Numeric
# calls...
def vsub(a, b):
    return [a[0]-b[0], a[1]-b[1], a[2]-b[2]]

def vadd(a, b):
    return [a[0]+b[0], a[1]+b[1], a[2]+b[2]]

def vdot(a, b):
    return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]

def vmulk(a, k):
    return [a[0]*k, a[1]*k, a[2]*k]

def vcross(a, b):
    return [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]]

print "enter groove position"
g = readVector()
print "enter a"
a = readVector()
print "enter b"
b = readVector()

va = vsub(a, g)
vb = vsub(b, g)
vc = vcross(va, vb)

mat = array([[va[0], vb[0], vc[0]], [va[1], vb[1], vc[1]], [va[2], vb[2], vc[2]]])
inv = inverse(mat)

while (True):
    print "enter vector"
    v = readVector()
    vv = vsub(v, g)

    A = vv[0]*inv[0, 0] + vv[1]*inv[0, 1] + vv[2]*inv[0, 2]
    B = vv[0]*inv[1, 0] + vv[1]*inv[1, 1] + vv[2]*inv[1, 2]
    C = vv[0]*inv[2, 0] + vv[1]*inv[2, 1] + vv[2]*inv[2, 2]

    vcalc1 = vadd(vmulk(va, A), vmulk(vb, B))
    vcalc = vadd(vcalc1, vmulk(vc, C))
    delta = vsub(vv, vcalc)
    error = math.sqrt(vdot(delta, delta))
    delta2d = vsub(vv, vcalc1)
    error2d = math.sqrt(vdot(delta2d, delta2d))

    print "A: %f  B: %f  C: %f  error: %e  error2d: %e" % (A, B, C, error, error2d)