aboutsummaryrefslogtreecommitdiff
path: root/scripts/peakogram-stream
blob: 233a4e6f19f6d65ed85640d6488efa4a0dd84a5d (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Check a stream for saturation
#
# Copyright © 2016-2017 Deutsches Elektronen-Synchrotron DESY,
#                       a research centre of the Helmholtz Association.
# Copyright © 2016      The Research Foundation for SUNY
#
# Authors:
#   2016-2017 Thomas White <taw@physics.org>
#   2014-2016 Thomas Grant <tgrant@hwi.buffalo.edu>
#
# This file is part of CrystFEL.
#
# CrystFEL is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CrystFEL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CrystFEL.  If not, see <http://www.gnu.org/licenses/>.

import sys
import argparse
import math as m
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm

def c2(a):
    return m.cos(a) * m.cos(a)

def s2(a):
    return m.sin(a) * m.sin(a)

# Return 1/d for hkl in cell, in 1/Angstroms
def resolution(scell, shkl):

    a = float(scell[0])*10.0
    b = float(scell[1])*10.0
    c = float(scell[2])*10.0  # nm -> Angstroms

    al = m.radians(float(scell[3]))
    be = m.radians(float(scell[3]))
    ga = m.radians(float(scell[3])) # in degrees

    h = int(shkl[0])
    k = int(shkl[1])
    l = int(shkl[2])

    pf = 1.0 - c2(al) - c2(be) - c2(ga) + 2.0*m.cos(al)*m.cos(be)*m.cos(ga)
    n1 = h*h*s2(al)/(a*a) + k*k*s2(be)/(b*b) + l*l*s2(ga)/(c*c)
    n2a = 2.0*k*l*(m.cos(be)*m.cos(ga) - m.cos(al))/(b*c)
    n2b = 2.0*l*h*(m.cos(ga)*m.cos(al) - m.cos(be))/(c*a)
    n2c = 2.0*h*k*(m.cos(al)*m.cos(be) - m.cos(ga))/(a*b)

    return m.sqrt((n1 + n2a + n2b + n2c) / pf)


parser = argparse.ArgumentParser()
parser.add_argument("-i", default="my.stream", help="stream filename")
parser.add_argument("-l", action="store_true", help="log scale y-axis")
parser.add_argument("--rmin", type=float, help="minimum resolution cutoff (1/d in Angstroms^-1)")
parser.add_argument("--rmax", type=float, help="maximum resolution cutoff (1/d in Angstroms^-1)")
parser.add_argument("--imin", type=float, help="minimum peak intensity cutoff")
parser.add_argument("--imax", type=float, help="maximum peak intensity cutoff")
parser.add_argument("--nmax", default=np.inf, type=int, help="maximum number of peaks to read")
parser.add_argument("-o", default="peakogram", help="output file prefix")
args = parser.parse_args()

data = []
n=0
in_list = 0
cell = []

with open(args.i) as f:
    for line in f:

        if line.find("Cell parameters") != -1:
            cell[0:3] = line.split()[2:5]
            cell[3:6] = line.split()[6:9]
            continue
        if line.find("Reflections measured after indexing") != -1:
            in_list = 1
            continue
        if line.find("End of reflections") != -1:
            in_list = 0
        if in_list == 1:
            in_list = 2
            continue
        elif in_list != 2:
            continue

        # From here, we are definitely handling a reflection line

        # Add reflection to list
        columns = line.split()
        n += 1
        try:
            data.append([resolution(cell, columns[0:3]),columns[5]])
        except:
            print("Error with line: "+line.rstrip("\r\n"))
            print("Cell: "+str(cell))

        if n%1000==0:
            sys.stdout.write("\r%i peaks found" % n)
            sys.stdout.flush()

        if n >= args.nmax:
            break



data = np.asarray(data,dtype=float)

sys.stdout.write("\r%i peaks found" % n)
sys.stdout.flush()

print("")

x = data[:,0]
y = data[:,1]

xmin = np.min(x[x>0])
xmax = np.max(x)
ymin = np.min(y[y>0])
ymax = np.max(y)

if args.rmin is not None:
    xmin = args.rmin
if args.rmax is not None:
    xmax = args.rmax
if args.imin is not None:
    ymin = args.imin
if args.imax is not None:
    ymax = args.imax

keepers = np.where((x>xmin) & (x<xmax) & (y>ymin) & (y<ymax))

x = x[keepers]
y = y[keepers]

if args.l:
    y = np.log10(y)
    ymin = np.log10(ymin)
    ymax = np.log10(ymax)

bins=300
H,xedges,yedges = np.histogram2d(y,x,bins=bins)

fig = plt.figure()
ax1 = plt.subplot(111)
plot = ax1.pcolormesh(yedges,xedges,H, norm=LogNorm())
cbar = plt.colorbar(plot)
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.xlabel("1/d (A^-1)")
if args.l:
    plt.ylabel("Log(Reflection max intensity)")
else:
    plt.ylabel("Reflection max intensity")
plt.title(args.i)
plt.show()