Re: [cctbxbb] Problems with conversion from conventional to primitive cell
Thanks for your script. I am doing this in C++. I can't find a xray::structure class in the C++ documentation. Does this only exist in Python ? Nevertheless, I run your script in Python and the result is somewhat different from what I get, but I still think it is wrong. If I create and visualize a supercell from the coordinates given by the script (e. g., with gdis) I no longer see the hexagonal arrangement of the atoms typical for the conventional cell. Since the conversion from conventional to primitive cell should only redefine the cell but not the atom positions (in Cartesian coordinates) I believe the output is incorrect. Best Regards, Jörg-Rüdiger Hill
--- J?rg-R?diger Hill
wrote: Dear All, I am trying to convert from a conventional cell to a primitive cell using cctbx, but I am having some problems.
Are you doing this in C++ or in Python?
What I do is the following: 1) I construct a spaceGroup object using the space group symbol 2) I retrieve the change of basis operator using z2p_op() from the space group object 3) I apply this operator to the conventional cell 4) I take a list of symmetry unique atoms and apply the operator to their fractional coordinates At this point I have a primitive cell which agrees exactly with what I get from other codes.
Note that there are ambiguities in the choice of the change-of-basis operator to the primitive cell. You may get different results from different programs, which are all correct. It is a coincidence if you get the same result.
The problem comes when I am trying to construct all atoms from the symmetry unique ones. I do this by the following procedure: 5) I take the space group object and call its change_basis() method with the z2p_op() operator 6) I loop over all order_z() symmetry operations in the space group applying the operation to the fractional coordinates making sure that I don't create two atoms at the same position
You could use the site_symmetry and sym_equiv_sites classes to deal with the special positions.
The whole procedure works well, e. g., for cubic crystals. However, if I take a hexagonal crystal (e. g., Cr2O3, R -3 c) the crystal build by steps 5 and 6 above is not correct. In this case the conventional cell has a=b != c, alpha=beta=90, and gamma=120, but the primitive cell has a=b=c and alpha=beta=gamma.
That's what I'd expect.
I have tried to add ":R" to the space group symbol and constructing a new spaceGroup object in step 5 above, but that does not make any difference. What do I have to do to build the crystal in this case or what is wrong with my procedure ?
Attached is a copy of the new cctbx/cctbx/examples/cr2o3_primitive_cell.py script (in the CVS already; will also be in the next set of auto-build bundles). Could you please compare your results to the output of this script?
The script shows a high-level implementation. I could add a lower-level equivalent that is more in line with what you'd do in C++. Let me know if this is what you need.
Cheers, Ralf
from cctbx import xray from cctbx import crystal from cctbx.array_family import flex
def demo(): """ Result of ICSD query: N * -Cr2O3-[R3-CH] Baster, M.;Bouree, F.;Kowalska, A.;Latacz, Z(2000) C 4.961950 4.961950 13.597400 90.000000 90.000000 120.000000 S GRUP R -3 C A Cr1 0.000000 0.000000 0.347570 0.000000 A O1 0.305830 0.000000 0.250000 """ crystal_symmetry = crystal.symmetry( unit_cell="4.961950 4.961950 13.597400 90.000000 90.000000 120.000000", space_group_symbol="R -3 C") scatterers = flex.xray_scatterer() scatterers.append(xray.scatterer( label="Cr1", site=(0.000000,0.000000,0.347570))) scatterers.append(xray.scatterer( label="O1", site=(0.305830,0.000000,0.250000))) icsd_structure = xray.structure( crystal_symmetry=crystal_symmetry, scatterers=scatterers) icsd_structure.show_summary().show_scatterers() print icsd_structure.show_distances(distance_cutoff=2.5) print primitive_structure = icsd_structure.primitive_setting() primitive_structure.show_summary().show_scatterers() print p1_structure = primitive_structure.expand_to_p1() p1_structure.show_summary().show_scatterers() print print "OK"
if (__name__ == "__main__"): demo()
-- ------------------------------------------------------------------------------- Dr. Jörg-Rüdiger Hill Tel.: +33 1 53 43 51 05 Director R & D Tel. (direct): +49 89 613 05 700 Scienomics Fax: +33 1 53 43 92 92 17 Square Edouard VII E-Mail: [email protected] 75009 Paris, France Web: http://www.scienomics.com/ -------------------------------------------------------------------------------
--- Jörg-Rüdiger Hill
Thanks for your script. I am doing this in C++. I can't find a xray::structure class in the C++ documentation. Does this only exist in Python ?
Yes. C++ is used only for low-level algorithms. It is too expensive to write everything in C++, too frustrating, too unsafe, and fortunately unnecessary.
Nevertheless, I run your script in Python and the result is somewhat different from what I get, but I still think it is wrong. If I create and visualize a supercell from the coordinates given by the script (e. g., with gdis) I no longer see the hexagonal arrangement of the atoms typical for the conventional cell. Since the conversion from conventional to primitive cell should only redefine the cell but not the atom positions (in Cartesian coordinates) I believe the output is incorrect.
Attached is an expanded script that shows 1. The coordination sequences for the original icsd_structure and the transformed p1_structure are identical. I.e. the local environment of each atom in the p1_structure is identical to that of the corresponding atom in the icsd_structure. 2. f_calc for both structures are identical; note that there is a factor of 3 in the amplitudes resulting from the transformation from the R cell to the primitive cell. About 1/3 of the cctbx code is just for internal testing. Here is an example related to your doubts: http://phenix-online.org/cctbx_sources/cctbx/cctbx/regression/tst_expand_to_... It is highly unlikely that there are gross bugs like the one you suspect.
Since the conversion from conventional to primitive cell should only redefine the cell but not the atom positions (in Cartesian coordinates)
You can convince yourself that this is not the case by working through your Cr2O3 example. You have to consider three matrices: - orthogonalization matrix of the R-centered cell - change-of-basis matrix R cell -> primitive cell - orthogonalization matrix of the primitive cell Here is a script that shows the three matrices (in Mathematica format): from cctbx import crystal from scitbx import matrix def demo(): icsd_symmetry = crystal.symmetry( unit_cell="4.961950 4.961950 13.597400 90.000000 90.000000 120.000000", space_group_symbol="R -3 C") icsd_symmetry.show_summary() print icsd_ortho_matrix = matrix.sqr( icsd_symmetry.unit_cell().orthogonalization_matrix()) print icsd_ortho_matrix.mathematica_form( label="icsd_ortho_matrix:", one_row_per_line=True) print z2p_op = icsd_symmetry.space_group().z2p_op() primitive_symmetry = icsd_symmetry.change_basis(cb_op=z2p_op) primitive_symmetry.show_summary() print primitive_ortho_matrix = matrix.sqr( primitive_symmetry.unit_cell().orthogonalization_matrix()) print primitive_ortho_matrix.mathematica_form( label="primitive_ortho_matrix:", one_row_per_line=True) print assert z2p_op.c().t().num() == (0,0,0) z2p_matrix = z2p_op.c().r().as_rational().as_float() print z2p_matrix.mathematica_form( label="z2p_matrix:", one_row_per_line=True) print print (primitive_ortho_matrix * z2p_matrix).mathematica_form( label="product:", one_row_per_line=True) print if (__name__ == "__main__"): demo() If you run the demo you will see that the "product" is not identical to the icsd_ortho_matrix. This means the Cartesian coordinates will be different. You can use Mathematica to recompute the matrix product, or just do it by hand. The convention for the orthogonalization matrix is shown in the uctbx.h C++ documentation. I believe you can find the z2p_matrix in Int. Vol. A, but I don't have the volume at hand right now to verify. I am certain the output of the script in my previous message is correct. Could you please double-check your input for gdis? Does gdis display your structure correctly if you simply transform to the rhombohedral basis? You could do the transformation of the two coordinates and the unit cell parameters by hand. The space group is simply the rhombohedral setting. I just saw gdis uses sginfo, therefore I guess it should understand r3c:r. Once you have verified gids deals correctly with r3c:r, you could expand the fractional coordinates manually. Keep the unit cell parameters and change the space group to P1. Once you know this is OK, try to find out what went wrong converting the output of my script to gdis input. Cheers, Ralf Here is the expanded version of my previous script, as explained above: from cctbx import xray from cctbx import miller from cctbx import crystal import cctbx.crystal.coordination_sequences from cctbx.array_family import flex def demo(): """ Result of ICSD query: N * -Cr2O3-[R3-CH] Baster, M.;Bouree, F.;Kowalska, A.;Latacz, Z(2000) C 4.961950 4.961950 13.597400 90.000000 90.000000 120.000000 S GRUP R -3 C A Cr1 0.000000 0.000000 0.347570 0.000000 A O1 0.305830 0.000000 0.250000 """ crystal_symmetry = crystal.symmetry( unit_cell="4.961950 4.961950 13.597400 90.000000 90.000000 120.000000", space_group_symbol="R -3 C") scatterers = flex.xray_scatterer() scatterers.append(xray.scatterer( label="Cr1", site=(0.000000,0.000000,0.347570))) scatterers.append(xray.scatterer( label="O1", site=(0.305830,0.000000,0.250000))) icsd_structure = xray.structure( crystal_symmetry=crystal_symmetry, scatterers=scatterers) icsd_structure.show_summary().show_scatterers() print icsd_pairs = icsd_structure.show_distances( distance_cutoff=2.5, keep_pair_asu_table=True) print primitive_structure = icsd_structure.primitive_setting() primitive_structure.show_summary().show_scatterers() print p1_structure = primitive_structure.expand_to_p1() p1_structure.show_summary().show_scatterers() print p1_pairs = p1_structure.show_distances( distance_cutoff=2.5, keep_pair_asu_table=True) print for label,structure,pairs in [("ICSD", icsd_structure,icsd_pairs), ("P1", p1_structure,p1_pairs)]: print "Coordination sequences for", label, "structure" term_table = crystal.coordination_sequences.simple( pair_asu_table=pairs.pair_asu_table, max_shell=10) crystal.coordination_sequences.show_terms( structure=structure, term_table=term_table) print icsd_f_calc = icsd_structure.structure_factors( d_min=1, algorithm="direct").f_calc() icsd_f_calc_in_p1 = icsd_f_calc.primitive_setting().expand_to_p1() p1_f_calc = icsd_f_calc_in_p1.structure_factors_from_scatterers( xray_structure=p1_structure, algorithm="direct").f_calc() for h,i,p in zip(icsd_f_calc_in_p1.indices(), icsd_f_calc_in_p1.data(), p1_f_calc.data()): print h, abs(i), abs(p)*3 print "OK" if (__name__ == "__main__"): demo() __________________________________ Yahoo! Music Unlimited Access over 1 million songs. Try it free. http://music.yahoo.com/unlimited/
participants (2)
-
Jörg-Rüdiger Hill
-
Ralf W. Grosse-Kunstleve