servalcat 0.4.131__cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. servalcat/__init__.py +10 -0
  2. servalcat/__main__.py +120 -0
  3. servalcat/ext.cpython-314t-x86_64-linux-gnu.so +0 -0
  4. servalcat/refine/__init__.py +0 -0
  5. servalcat/refine/cgsolve.py +100 -0
  6. servalcat/refine/refine.py +1162 -0
  7. servalcat/refine/refine_geom.py +245 -0
  8. servalcat/refine/refine_spa.py +400 -0
  9. servalcat/refine/refine_xtal.py +339 -0
  10. servalcat/refine/spa.py +151 -0
  11. servalcat/refine/xtal.py +312 -0
  12. servalcat/refmac/__init__.py +0 -0
  13. servalcat/refmac/exte.py +191 -0
  14. servalcat/refmac/refmac_keywords.py +660 -0
  15. servalcat/refmac/refmac_wrapper.py +423 -0
  16. servalcat/spa/__init__.py +0 -0
  17. servalcat/spa/fofc.py +488 -0
  18. servalcat/spa/fsc.py +391 -0
  19. servalcat/spa/localcc.py +197 -0
  20. servalcat/spa/realspcc_from_var.py +128 -0
  21. servalcat/spa/run_refmac.py +979 -0
  22. servalcat/spa/shift_maps.py +293 -0
  23. servalcat/spa/shiftback.py +137 -0
  24. servalcat/spa/translate.py +129 -0
  25. servalcat/utils/__init__.py +35 -0
  26. servalcat/utils/commands.py +1629 -0
  27. servalcat/utils/fileio.py +836 -0
  28. servalcat/utils/generate_operators.py +296 -0
  29. servalcat/utils/hkl.py +811 -0
  30. servalcat/utils/logger.py +140 -0
  31. servalcat/utils/maps.py +345 -0
  32. servalcat/utils/model.py +933 -0
  33. servalcat/utils/refmac.py +759 -0
  34. servalcat/utils/restraints.py +888 -0
  35. servalcat/utils/symmetry.py +298 -0
  36. servalcat/xtal/__init__.py +0 -0
  37. servalcat/xtal/french_wilson.py +262 -0
  38. servalcat/xtal/run_refmac_small.py +240 -0
  39. servalcat/xtal/sigmaa.py +1954 -0
  40. servalcat/xtal/twin.py +316 -0
  41. servalcat-0.4.131.dist-info/METADATA +60 -0
  42. servalcat-0.4.131.dist-info/RECORD +45 -0
  43. servalcat-0.4.131.dist-info/WHEEL +6 -0
  44. servalcat-0.4.131.dist-info/entry_points.txt +4 -0
  45. servalcat-0.4.131.dist-info/licenses/LICENSE +373 -0
@@ -0,0 +1,296 @@
1
+ """
2
+ Author: "Keitaro Yamashita, Garib N. Murshudov"
3
+ MRC Laboratory of Molecular Biology
4
+
5
+ This software is released under the
6
+ Mozilla Public License, version 2.0; see LICENSE.
7
+ """
8
+ from __future__ import absolute_import, division, print_function, generators
9
+ import numpy
10
+ import copy
11
+ eps_l = 1.0e-5
12
+
13
+ def generate_all_elements(axis1, order1, axis2=None, order2=0, toler=1.0e-6, toler2=1.e-3):
14
+ #
15
+ # Generate all group elements. Output will be as a list of cyclic groups.
16
+ #
17
+ if axis2 is None: axis2 = numpy.array([0.0,0.0,1.0])
18
+ grp_out = []
19
+ order_out = []
20
+ axes_out = []
21
+ if order2 == 0:
22
+ grp_out = generate_cyclic(axis1, order1)
23
+ order_out.append(order1)
24
+ axes_out.append(axis1)
25
+ return order_out, axes_out, grp_out
26
+
27
+ grp_out = generate_cyclic(axis1,order1)
28
+ order_out.append(order1)
29
+ axes_out.append(axis1)
30
+ grp1 = generate_cyclic(axis2,order2)
31
+ grp_out = add_groups_together(grp_out,grp1,toler2)
32
+ order_out.append(order2)
33
+ axes_out.append(axis2)
34
+
35
+ grp_out_new = copy.copy(grp_out)
36
+ things_to_do = True
37
+ while things_to_do:
38
+ things_to_do = False
39
+ for i, ri in enumerate(grp_out):
40
+ for j, rj in enumerate(grp_out):
41
+ if i !=0 and j!=0 and i != j:
42
+ r3 = numpy.dot(ri,rj)
43
+ if not is_in_the_list_rotation(r3, grp_out, toler2):
44
+ things_to_do = True
45
+ order3, axis3 = find_order(r3, toler2)
46
+ grp3 = generate_cyclic(axis3, order3)
47
+ grp_out_new = add_groups_together(grp_out_new, grp3,toler2)
48
+ order_out.append(order3)
49
+ axes_out.append(axis3)
50
+ r3 = numpy.dot(rj, ri)
51
+ if not is_in_the_list_rotation(r3, grp_out, toler2):
52
+ things_to_do = True
53
+ order3, axis3 = find_order(r3, toler2)
54
+ grp3 = generate_cyclic(axis3,order3)
55
+ grp_out_new = add_groups_together(grp_out_new, grp3,toler2)
56
+ order_out.append(order3)
57
+ axes_out.append(axis3)
58
+ grp_out = copy.copy(grp_out_new)
59
+ #
60
+ # Filter out axes (if they are parallel to each other then select one, for the order we should take
61
+ # the highest order). In our case it should happen only for the group O. We may have 2 and four fold symmetries
62
+ # with the same axis
63
+ axes_out_new = []
64
+ order_out_new = []
65
+ for i, axisi in enumerate(axes_out):
66
+ order_cp = order_out[i]
67
+ for j, axisj in enumerate(axes_out):
68
+ if i < j:
69
+ cangle = numpy.dot(axisi,axisj)/(numpy.linalg.norm(axisi)*numpy.linalg.norm(axisj))
70
+ if numpy.abs(cangle-1.0) < toler or numpy.abs(cangle+1) < toler:
71
+ # same axis
72
+ if order_cp <= order_out[j]:
73
+ order_cp= 0
74
+ break
75
+ if order_cp > 0:
76
+ axes_out_new.append(axisi)
77
+ order_out_new.append(order_cp)
78
+
79
+ return order_out_new, axes_out_new, grp_out
80
+ # generate_all_elements()
81
+
82
+ def find_order(r, toler=1.0e-3):
83
+ order = 1
84
+ r_id = numpy.identity(3)
85
+ r3 = numpy.copy(r_id)
86
+ things_to_do = True
87
+ A = r_id
88
+ while things_to_do and order < 100:
89
+ things_to_do = False
90
+ r3 = numpy.dot(r3, r)
91
+ if numpy.sum(numpy.abs(r3-r_id)) > toler:
92
+ A = A + r3
93
+ things_to_do = True
94
+ order += 1
95
+
96
+ if order >= 100:
97
+ raise RuntimeError("The order of the group is too high: order > 100")
98
+ A = A/order
99
+ axis_l = find_axis(A)
100
+
101
+ return order, axis_l
102
+ # find_order()
103
+
104
+ def add_groups_together(grp_in, grp_add, toler=1.e-3):
105
+ grp_out = copy.copy(grp_in)
106
+ grp_out.extend(filter(lambda r: not is_in_the_list_rotation(r, grp_out, toler), grp_add))
107
+ #for r in grp_add:
108
+ # if not is_in_the_list_rotation(r, grp_out):
109
+ # grp_out.append(r)
110
+ return grp_out
111
+ # add_groups_together()
112
+
113
+ def generate_cyclic(axis, order):
114
+ #
115
+ # This function generates all cyclic group elements using axis and order of the group
116
+ if order <=0 or numpy.sum(numpy.abs(axis)) < eps_l:
117
+ raise RuntimeError("Either order or axis is zero. order= {} axis= {}".format(order, axis))
118
+ gout = []
119
+ id_matr = numpy.identity(3)
120
+ gout.append(id_matr)
121
+ angle = 2.0*numpy.pi/order
122
+ axis = axis/numpy.linalg.norm(axis)
123
+ exp_matr = numpy.array([[0, -axis[2], axis[1]],
124
+ [axis[2], 0, -axis[0]],
125
+ [-axis[1], axis[0], 0]])
126
+ axis_outer = numpy.outer(axis, axis)
127
+ m_int = id_matr - axis_outer
128
+ for i in range(order-1):
129
+ angle_l = angle*(i+1)
130
+ stheta = numpy.sin(angle_l)
131
+ ctheta = numpy.cos(angle_l)
132
+ m_l = exp_matr*stheta + m_int*ctheta +axis_outer
133
+ m_l = numpy.where(numpy.abs(m_l) < 1e-9, 0, m_l)
134
+ gout.append(m_l)
135
+
136
+ return gout
137
+ # generate_cyclic()
138
+
139
+ def AngleAxis2rotatin(axis, angle):
140
+ #
141
+ # Convert axis and ange to a rotation matrix. Here we use a mtrix form of the relatiionship
142
+ # IT may not be the moost efficient algorithm, but it should work (it is more elegant)
143
+ if numpy.sum(numpy.abs(axis)) < eps_l:
144
+ raise RuntimeError("Axis is zero. axis= {} angle= {}".format(axis, angle))
145
+ id_matr = numpy.identity(3)
146
+ axis = axis/numpy.sqrt(numpy.dot(axis,axis))
147
+ exp_matr = numpy.array([[0, -axis[2], axis[1]],
148
+ [axis[2], 0, -axis[0]],
149
+ [-axis[1], axis[0], 0]])
150
+ axis_outer = numpy.outer(axis, axis)
151
+ m_int = id_matr - axis_outer
152
+ stheta = numpy.sin(angle)
153
+ ctheta = numpy.cos(angle)
154
+ m_l = exp_matr*stheta + m_int*ctheta +axis_outer
155
+ m_l = numpy.where(numpy.abs(m_l) < 1e-9, 0, m_l)
156
+ return m_l
157
+ # AngleAxis2rotatin()
158
+
159
+ def Rotation2AxisAngle_cyclic(m_in, eps_l=1.0e-5):
160
+ #
161
+ # Here we assume that rotation matrix is an element of a cyclic group
162
+ # This routine gives the smallest angle for this cyclic group.
163
+ # To find axis of the rotation we use the fact that if we define
164
+ # A = 1/n sum_i-0^(n-1) (R^i) then this operator is a projector to the axis of rotation
165
+ # i.e. for Ax will be on the axis for any x. IT could be equal 0, in this case we select another x
166
+ A = m_in
167
+ m1 = m_in
168
+ id_matr = numpy.identity(3)
169
+ cycle_number = 1
170
+ ended = False
171
+ while not ended and cycle_number < 200:
172
+ if numpy.sum(numpy.abs(m1-id_matr)) < eps_l:
173
+ ended = True
174
+ break
175
+ m1 = numpy.dot(m1,m_in)
176
+ A = A + m1
177
+ cycle_number = cycle_number + 1
178
+ # take a ranom vector
179
+ if cycle_number >= 150 :
180
+ print("matrix ",m_in)
181
+ print("Try to change the tolerance: eps_l = XXX")
182
+ raise RuntimeError("The matrix does not seem to be producing a finite cyclic group")
183
+ A = A/cycle_number
184
+ axis = numpy.zeros(3)
185
+ for xin in ((0,0,1.), (0,1.,0), (1.,0,0,)):
186
+ axis = numpy.dot(A,xin)
187
+ if numpy.dot(axis,axis) > eps_l:
188
+ axis = axis/numpy.sqrt(numpy.dot(axis,axis))
189
+ if numpy.dot(axis,axis) >= eps_l:
190
+ break
191
+
192
+ if axis[2] < 0.0:
193
+ axis = -axis
194
+ elif axis[2] == 0.0 and axis[1] < 0.0:
195
+ axis = -axis
196
+ angle = 2.0*numpy.pi/cycle_number
197
+ axis[axis==0.]=0.
198
+ return axis,angle,cycle_number
199
+ # Rotation2AxisAngle_cyclic()
200
+
201
+ def Rotation2AxisAngle_general(m_in, eps_l=1.0e-5):
202
+ #
203
+ # This routine should work for any rotation matrix
204
+ axis = numpy.array([1, 0.0, 0.0])
205
+ angle = numpy.arccos(max(-1.0, numpy.min((numpy.trace(m_in)-1)/2.0)))
206
+ if numpy.sum(numpy.abs(m_in-numpy.transpose(m_in))) < eps_l:
207
+ #
208
+ # It is a symmetric matrix. so I and m_in form a cyclic group
209
+ A = (numpy.identity(3) + m_in)/2.0
210
+ axis = numpy.zeros(3)
211
+ for a in ((0,0,1.), (0,1.,0), (1.,0,0,)):
212
+ axis = numpy.dot(A, a)
213
+ if numpy.linalg.norm(axis) >= eps_l: break
214
+ else:
215
+ axis[0] = m_in[1,2] - m_in[2,1]
216
+ axis[1] = m_in[0,2] - m_in[2,0]
217
+ axis[2] = m_in[0,1] - m_in[1,0]
218
+ if axis[2] < 0.0:
219
+ axis = -axis
220
+ angle = 2.0*numpy.pi - angle
221
+ elif axis[2] < eps_l and axis[1] < 0.0:
222
+ axis = -axis
223
+ angle = 2.0*numpy.pi - angle
224
+ axis = axis/numpy.linalg.norm(axis)
225
+ axis[axis==0.]=0.
226
+ return axis, angle
227
+ # Rotation2AxisAngle_general()
228
+
229
+ def is_in_the_list_rotation(m_in, m_list, toler = 1.0e-3):
230
+ id_matr = numpy.identity(3)
231
+ return numpy.any(numpy.abs(numpy.trace(numpy.dot(numpy.transpose(m_in), m_list)-id_matr[:,None], axis1=0,axis2=2)) < toler)
232
+ # is_in_the_list_rotation()
233
+
234
+ def closest_rotation(m_in, m_list):
235
+ id_matr = numpy.identity(3)
236
+ return min(numpy.abs(numpy.trace(numpy.dot(numpy.transpose(m_in), m_list)-id_matr[:,None], axis1=0,axis2=2)))
237
+ # closest_rotation()
238
+
239
+ def find_axis(amatr):
240
+ #
241
+ # We assume that amatr is a projector. I.e. y = amatr x is on the the symmetry axis.
242
+ # To avoid problem of 0 vector we try several times to make sure that 0 vector is not generated
243
+ axis1 = numpy.zeros(3)
244
+ for a in ((0,0,1.), (0,1.,0), (1.,0,0,)):
245
+ axis1 = numpy.dot(amatr, a)
246
+ if numpy.linalg.norm(axis1) >= 0.001:
247
+ break
248
+
249
+ axis1 /= numpy.linalg.norm(axis1)
250
+ axis1 = numpy.around(axis1, 10)
251
+ axis1 /= numpy.linalg.norm(axis1)
252
+ # Remove annoying negative signs
253
+ axis1[axis1==0.]=0.
254
+
255
+ if axis1[2] < 0.0:
256
+ axis1 *= -1
257
+ elif axis1[2] == 0.0 and axis1[1] < 0.0:
258
+ axis1 *= -1
259
+
260
+ return axis1
261
+ # find_axis()
262
+
263
+ def rotate_group_elements(Rg, matrices):
264
+ #
265
+ # assume an input list and return a list of matrices
266
+ #
267
+ mm_out = []
268
+ Rg_t = numpy.transpose(Rg)
269
+ for i, mm in enumerate(matrices):
270
+ m1 = numpy.dot(numpy.dot(Rg_t, mm), Rg)
271
+ mm_out.append(m1)
272
+ return(mm_out)
273
+ # rotate_group_elements()
274
+
275
+ if __name__ == "__main__":
276
+ import sys
277
+ from servalcat.utils import symmetry
278
+ symbol = sys.argv[1]
279
+ order, axes, grp = symmetry.operators_from_symbol(symbol)
280
+ #print(order)
281
+ #print(axes)
282
+ #print(grp)
283
+ #quit()
284
+ rgs = symmetry.get_matrices_using_relion(symbol)
285
+ all_ok = True
286
+ max_diff = 0
287
+ for i, m in enumerate(grp):
288
+ #print("Op", i)
289
+ #print(m)
290
+ #ok = is_in_the_list_rotation(m, rgs, toler=1e-4)
291
+ diff = closest_rotation(m, rgs)
292
+ ok = diff < 1e-4
293
+ #print("match? {} {:.1e}".format(ok, diff))
294
+ if not ok: all_ok = False
295
+ if diff > max_diff: max_diff = diff
296
+ print("Final=", all_ok, max_diff)