From d7bf38c5d974ffa0df6e290aae4ba82743e085cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 18:32:12 +0200 Subject: [PATCH 01/10] :bug: Explicitly assert that length of displacement selection is > 0 --- picometer/instructions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/picometer/instructions.py b/picometer/instructions.py index 7fda268..6d4b07a 100644 --- a/picometer/instructions.py +++ b/picometer/instructions.py @@ -326,6 +326,7 @@ class DisplacementInstructionHandler(SerialInstructionHandler): def handle_one(self, instruction: Instruction, ms_key: str, ms: ModelState) -> None: focus = ms.nodes.locate(self.processor.selection) + assert len(focus) > 0 for label, displacements in focus.table.iterrows(): for suffix in 'Uiso U11 U22 U33 U23 U13 U12'.split(): label_ = label + '_' + suffix From f18ff361fb5e2b76aae9a87fe27bbea3b34bfa82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 19:15:15 +0200 Subject: [PATCH 02/10] :sparkles: introduce `settings.complete_uiso_from_umatrix` --- picometer/instructions.py | 5 +++++ picometer/settings.yaml | 1 + 2 files changed, 6 insertions(+) diff --git a/picometer/instructions.py b/picometer/instructions.py index 6d4b07a..43dc6c7 100644 --- a/picometer/instructions.py +++ b/picometer/instructions.py @@ -218,6 +218,11 @@ def _load_model_state(self, cif_path, block_name): label = cif_path + (':' + block_name if block_name else '') self.processor.model_states[label] = ModelState(atoms=atoms) logger.info(f'Loaded model state {label}') + if self.processor.settings['complete_uiso_from_umatrix']: + if 'U_iso' not in atoms.table.columns: + atoms.table['U_iso'] = pd.NA + u_equiv = atoms.table[['U_11', 'U_22', 'U_33']].mean(axis=1) + atoms.table['U_iso'].fillna(u_equiv, inplace=True) if not self.processor.settings['auto_write_unit_cell']: return et = self.processor.evaluation_table diff --git a/picometer/settings.yaml b/picometer/settings.yaml index f06ec18..acf0570 100644 --- a/picometer/settings.yaml +++ b/picometer/settings.yaml @@ -1,3 +1,4 @@ settings: auto_write_unit_cell: True clear_selection_after_use: True + complete_uiso_from_umatrix: False From 09f760eb3cb65edaf3fa30754a8fb8ee81a9f133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 20:36:20 +0200 Subject: [PATCH 03/10] :sparkles: introduce `settings.complete_umatrix_from_uiso` --- picometer/instructions.py | 29 +++++++++++++++++++++++++---- picometer/settings.py | 2 ++ picometer/settings.yaml | 1 + 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/picometer/instructions.py b/picometer/instructions.py index 43dc6c7..e7dc279 100644 --- a/picometer/instructions.py +++ b/picometer/instructions.py @@ -15,6 +15,7 @@ from typing import Any, Union, Protocol from numpy import rad2deg +import numpy as np import pandas as pd import yaml @@ -218,11 +219,31 @@ def _load_model_state(self, cif_path, block_name): label = cif_path + (':' + block_name if block_name else '') self.processor.model_states[label] = ModelState(atoms=atoms) logger.info(f'Loaded model state {label}') + if self.processor.settings['complete_uiso_from_umatrix']: - if 'U_iso' not in atoms.table.columns: - atoms.table['U_iso'] = pd.NA - u_equiv = atoms.table[['U_11', 'U_22', 'U_33']].mean(axis=1) - atoms.table['U_iso'].fillna(u_equiv, inplace=True) + if 'U11' in atoms.table.columns: + if 'Uiso' not in atoms.table.columns: + atoms.table['Uiso'] = pd.NA + u_equiv = atoms.table[['U11', 'U22', 'U33']].mean(axis=1) + atoms.table['Uiso'].fillna(u_equiv, inplace=True) + + if self.processor.settings['complete_umatrix_from_uiso']: + u_columns = ['U11', 'U12', 'U13', 'U22', 'U23', 'U33'] + if 'Uiso' in atoms.table.columns: + for col in u_columns: + if col not in atoms.table.columns: + atoms.table[col] = pd.NA + mask1 = atoms.table['Uiso'].notna() + mask2 = atoms.table[['U11', 'U22', 'U33']].isna().all(axis=1) + # based on http://dx.doi.org/10.1107/S0021889802008580 + n_mat = np.diag([atoms.base.a_r, atoms.base.b_r, atoms.base.c_r]) + n_inv = np.linalg.inv(n_mat) + u_star = (m := np.linalg.inv(atoms.base.A_d.T)) @ m.T + u_cif = n_inv @ u_star @ n_inv.T + for label in atoms.table.index[mask1 & mask2]: + u_atom = atoms.table.at[label, 'Uiso'] * u_cif + atoms.table.loc[label, u_columns] = u_atom[np.triu_indices(3)] + if not self.processor.settings['auto_write_unit_cell']: return et = self.processor.evaluation_table diff --git a/picometer/settings.py b/picometer/settings.py index 4068407..bfb2d83 100644 --- a/picometer/settings.py +++ b/picometer/settings.py @@ -19,6 +19,8 @@ class DefaultSettings: """Store default values of all settings. Use `AnyValue` if no default.""" auto_write_unit_cell: bool = True clear_selection_after_use: bool = True + complete_uiso_from_umatrix: bool = False + complete_umatrix_from_uiso: bool = False @classmethod def get_field(cls, key: str) -> Field: diff --git a/picometer/settings.yaml b/picometer/settings.yaml index acf0570..a2aa79b 100644 --- a/picometer/settings.yaml +++ b/picometer/settings.yaml @@ -2,3 +2,4 @@ settings: auto_write_unit_cell: True clear_selection_after_use: True complete_uiso_from_umatrix: False + complete_umatrix_from_uiso: False From 9bd7a796ce3045b939333595f8c0b2d48b76b71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 21:17:14 +0200 Subject: [PATCH 04/10] :bug: Fix incorrect labelling when creating new U matrix --- picometer/instructions.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/picometer/instructions.py b/picometer/instructions.py index e7dc279..c859d11 100644 --- a/picometer/instructions.py +++ b/picometer/instructions.py @@ -240,9 +240,10 @@ def _load_model_state(self, cif_path, block_name): n_inv = np.linalg.inv(n_mat) u_star = (m := np.linalg.inv(atoms.base.A_d.T)) @ m.T u_cif = n_inv @ u_star @ n_inv.T - for label in atoms.table.index[mask1 & mask2]: - u_atom = atoms.table.at[label, 'Uiso'] * u_cif - atoms.table.loc[label, u_columns] = u_atom[np.triu_indices(3)] + for atom_label in atoms.table.index[mask1 & mask2]: + u_atom = atoms.table.at[atom_label, 'Uiso'] * u_cif + atoms.table.loc[atom_label, u_columns] = u_atom[np.triu_indices(3)] + print(atoms.table) if not self.processor.settings['auto_write_unit_cell']: return From 696e72745fb10dd51fcab45c1b989b70e0fc43ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 21:17:33 +0200 Subject: [PATCH 05/10] :white_check_mark: Make atoms spherical in ferrocene2.cif test --- tests/ferrocene2.cif | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ferrocene2.cif b/tests/ferrocene2.cif index 6700503..5cd3f0b 100644 --- a/tests/ferrocene2.cif +++ b/tests/ferrocene2.cif @@ -71,9 +71,9 @@ _atom_site_aniso_U_33 _atom_site_aniso_U_23 _atom_site_aniso_U_13 _atom_site_aniso_U_12 -Fe .01 .01 .01 .0 .0 .0 -C(11) .02 .02 .02 .0 .0 .0 -C(12) .02 .02 .02 .0 .0 .0 -C(13) .02 .02 .02 .0 .0 .0 -C(14) .02 .02 .02 .0 .0 .0 -C(15) .02 .02 .02 .0 .0 .0 +Fe .01 .01 .01 .0 .005143 .0 +C(11) .02 .02 .02 .0 .010286 .0 +C(12) .02 .02 .02 .0 .010286 .0 +C(13) .02 .02 .02 .0 .010286 .0 +C(14) .02 .02 .02 .0 .010286 .0 +C(15) .02 .02 .02 .0 .010286 .0 From de820c785dcd7e5cac2e34ab4018767fcf01e410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 21:17:56 +0200 Subject: [PATCH 06/10] :white_check_mark: Add tests for `complete_uiso_from_umatrix` and `complete_umatrix_from_uiso` settings --- tests/test_instructions.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_instructions.py b/tests/test_instructions.py index ad6e59a..ac21c36 100644 --- a/tests/test_instructions.py +++ b/tests/test_instructions.py @@ -299,6 +299,30 @@ def test_displacement(self): self.assertEqual(results[1], 0.02) np.testing.assert_equal(results[0], np.nan) + def test_displacement_complete_uiso_from_umatrix(self): + r = 'settings: \n complete_uiso_from_umatrix: True\n' + self.routine_text + r += ' - select: C(11)\n - displacement\n' + p = process(Routine.from_string(r)) + results = p.evaluation_table['C(11)_Uiso'].to_numpy() + self.assertEqual(results[0], 0.02) + self.assertEqual(results[1], 0.02) + np.testing.assert_equal(results[2], np.nan) + np.testing.assert_equal(results[3], np.nan) + np.testing.assert_equal(results[4], np.nan) + np.testing.assert_equal(results[5], np.nan) + + def test_displacement_complete_umatrix_from_Uiso(self): + r = 'settings: \n complete_umatrix_from_uiso: True\n' + self.routine_text + r += ' - select: C(11)\n - displacement\n' + p = process(Routine.from_string(r)) + results = p.evaluation_table['C(11)_U13'].to_numpy() + self.assertAlmostEqual(results[0], 0.010286, places=6) + self.assertAlmostEqual(results[0], 0.010286, places=6) + np.testing.assert_equal(results[2], np.nan) + np.testing.assert_equal(results[3], np.nan) + np.testing.assert_equal(results[4], np.nan) + np.testing.assert_equal(results[5], np.nan) + def test_distance_plane_plane(self): self.routine_text += ' - select: cp_A_plane\n' self.routine_text += ' - select: cp_B_plane\n' From ffc1992a1115b0ae221acdbec0e7a31fb2a88f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Wed, 18 Jun 2025 21:18:58 +0200 Subject: [PATCH 07/10] :bug: Remove a print remaining after debugging --- picometer/instructions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/picometer/instructions.py b/picometer/instructions.py index c859d11..a337974 100644 --- a/picometer/instructions.py +++ b/picometer/instructions.py @@ -243,7 +243,6 @@ def _load_model_state(self, cif_path, block_name): for atom_label in atoms.table.index[mask1 & mask2]: u_atom = atoms.table.at[atom_label, 'Uiso'] * u_cif atoms.table.loc[atom_label, u_columns] = u_atom[np.triu_indices(3)] - print(atoms.table) if not self.processor.settings['auto_write_unit_cell']: return From 265736a6caac902dd51a69ef1f143770314c16b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Thu, 19 Jun 2025 14:39:43 +0200 Subject: [PATCH 08/10] :sparkles: Correctly transform the U matrix when applying transformation with off-diagonal matrix elements --- picometer/atom.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/picometer/atom.py b/picometer/atom.py index 4eaee9a..da7ece1 100644 --- a/picometer/atom.py +++ b/picometer/atom.py @@ -119,6 +119,20 @@ def fract_xyz(self) -> np.ndarray: def cart_xyz(self) -> np.ndarray: return self.orthogonalise(self.fract_xyz) + @property + def fract_uij(self) -> np.ndarray: + """Return a 3D array i.e. stack of 3x3 fract. displacement tensors.""" + t = self.table + default = pd.Series([np.nan] * len(t), index=t.index) + uij = np.zeros((len(t), 3, 3), dtype=np.float64) + uij[:, 0, 0] = t.get('U11', default).to_numpy(dtype=np.float64) + uij[:, 1, 1] = t.get('U22', default).to_numpy(dtype=np.float64) + uij[:, 2, 2] = t.get('U33', default).to_numpy(dtype=np.float64) + uij[:, 0, 1] = uij[:, 1, 0] = t.get('U12', default).to_numpy(dtype=np.float64) + uij[:, 0, 2] = uij[:, 2, 0] = t.get('U13', default).to_numpy(dtype=np.float64) + uij[:, 1, 2] = uij[:, 2, 1] = t.get('U23', default).to_numpy(dtype=np.float64) + return uij + def fractionalise(self, cart_xyz: np.ndarray) -> np.ndarray: """Multiply 3xN vector by crystallographic matrix to get fract coord""" return np.linalg.inv(self.base.A_d.T) @ cart_xyz @@ -158,6 +172,17 @@ def transform(self, symm_op_code: str) -> 'AtomSet': data['fract_x'] = fract_xyz[:, 0] data['fract_y'] = fract_xyz[:, 1] data['fract_z'] = fract_xyz[:, 2] + if {'U11', 'U22', 'U33', 'U12', 'U13', 'U23'}.issubset(data.columns): + uij = self.fract_uij # shape: (n_atoms, 3, 3) + mask = ~np.isnan(uij).all(axis=(1, 2)) # atoms with defined Uij + if np.any(mask): + uij_rot = (s := symm_op.tf) @ uij[mask] @ s.T + data.loc[mask, 'U11'] = uij_rot[:, 0, 0] + data.loc[mask, 'U22'] = uij_rot[:, 1, 1] + data.loc[mask, 'U33'] = uij_rot[:, 2, 2] + data.loc[mask, 'U12'] = uij_rot[:, 0, 1] + data.loc[mask, 'U13'] = uij_rot[:, 0, 2] + data.loc[mask, 'U23'] = uij_rot[:, 1, 2] return self.__class__(self.base, data) @property From 6703b9b1e9ec835c2120e6e4776dfd1e67e69ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Thu, 19 Jun 2025 15:31:42 +0200 Subject: [PATCH 09/10] :white_check_mark: Test newly-implemented u-matrix transformation --- tests/test_instructions.py | 1 - tests/test_transformations.py | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/test_transformations.py diff --git a/tests/test_instructions.py b/tests/test_instructions.py index ac21c36..73687b1 100644 --- a/tests/test_instructions.py +++ b/tests/test_instructions.py @@ -7,7 +7,6 @@ import unittest import numpy as np -import pandas import pandas as pd from pandas.testing import assert_frame_equal diff --git a/tests/test_transformations.py b/tests/test_transformations.py new file mode 100644 index 0000000..0cc34d0 --- /dev/null +++ b/tests/test_transformations.py @@ -0,0 +1,42 @@ +import importlib.resources +import unittest + +import numpy as np + +from picometer.atom import AtomSet + + +class TestTransformations(unittest.TestCase): + rot3_at_cobalt_code = '1-y,1+x-y,z' + rot6_at_origin_code = 'x-y,x,z' + + @classmethod + def setUpClass(cls) -> None: + with importlib.resources.path('tests', 'cobalt.cif') as cif_path: + cls.atoms = AtomSet.from_cif(str(cif_path)) + + def test_transform_coordinates(self) -> None: + t = self.atoms.table + t3 = self.atoms.transform(self.rot3_at_cobalt_code).table + t6 = self.atoms.transform(self.rot6_at_origin_code).table + self.assertAlmostEqual(t.at['Co1', 'fract_x'], t3.at['Co1', 'fract_x'], places=3) + self.assertAlmostEqual(t.at['Co1', 'fract_y'], t3.at['Co1', 'fract_y'], places=3) + self.assertAlmostEqual(t.at['Co1', 'fract_z'], t3.at['Co1', 'fract_z'], places=3) + self.assertNotAlmostEqual(t.at['Co1', 'fract_x'], t6.at['Co1', 'fract_x'], places=3) + self.assertNotAlmostEqual(t.at['Co1', 'fract_y'], t6.at['Co1', 'fract_y'], places=3) + self.assertAlmostEqual(t.at['Co1', 'fract_z'], t6.at['Co1', 'fract_z'], places=3) + + def test_transform_u_matrix(self) -> None: + t = self.atoms.table + t3 = self.atoms.transform(self.rot3_at_cobalt_code).table + t6 = self.atoms.transform(self.rot6_at_origin_code).table + us = ['U11', 'U22', 'U33', 'U12', 'U13', 'U23'] + np.testing.assert_allclose(t.loc['Co1', us], t3.loc['Co1', us], rtol=0.01) + np.testing.assert_allclose(t.loc['Co1', us], t6.loc['Co1', us], rtol=0.01) + with np.testing.assert_raises(AssertionError): + np.testing.assert_allclose(t.loc['O1', us], t3.loc['O1', us], rtol=0.1) + np.testing.assert_equal(t.loc['O1', us], np.array([.067,.066,.018,.031,-.007,-.008])) + + +if __name__ == '__main__': + unittest.main() From 6faaae9bae4d21aec2ecb69990a0ead6f2effbe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Thu, 19 Jun 2025 15:36:04 +0200 Subject: [PATCH 10/10] :white_check_mark: Add a file `cobalt.cif` for testing --- tests/cobalt.cif | 311 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 tests/cobalt.cif diff --git a/tests/cobalt.cif b/tests/cobalt.cif new file mode 100644 index 0000000..1836257 --- /dev/null +++ b/tests/cobalt.cif @@ -0,0 +1,311 @@ +#------------------------------------------------------------------------------ +#$Date: 2016-02-21 02:03:34 +0200 (Sun, 21 Feb 2016) $ +#$Revision: 176798 $ +#$URL: svn://www.crystallography.net/cod/cif/2/23/23/2232341.cif $ +#------------------------------------------------------------------------------ +# +# This file is available in the Crystallography Open Database (COD), +# http://www.crystallography.net/. The original data for this entry +# were provided by IUCr Journals, http://journals.iucr.org/. +# +# The file may be used within the scientific community so long as +# proper attribution is given to the journal article from which the +# data were obtained. +# +data_2232341 +loop_ +_publ_author_name +'Golenia, Irina A.' +'Boyko, Alexander N.' +'Kotova, Natalia V.' +'Haukka, Matti' +'Kalibabchuk, Valentina A.' +_publ_section_title +; + fac-Tris(pyridine-2-carboxylato-\k^2^N,O)cobalt(III) +; +_journal_coeditor_code HY2479 +_journal_issue 11 +_journal_name_full 'Acta Crystallographica Section E' +_journal_page_first m1596 +_journal_page_last m1597 +_journal_paper_doi 10.1107/S1600536811043303 +_journal_volume 67 +_journal_year 2011 +_chemical_formula_iupac '[Co (C6 H4 N O2)3]' +_chemical_formula_moiety 'C18 H12 Co N3 O6' +_chemical_formula_sum 'C18 H12 Co N3 O6' +_chemical_formula_weight 425.24 +_chemical_name_systematic +; +fac-Tris(pyridine-2-carboxylato-\k^2^N,O)cobalt(III) +; +_space_group_IT_number 168 +_symmetry_cell_setting hexagonal +_symmetry_space_group_name_Hall 'P 6' +_symmetry_space_group_name_H-M 'P 6' +_atom_sites_solution_hydrogens geom +_atom_sites_solution_primary direct +_atom_sites_solution_secondary difmap +_audit_creation_method SHELXL-97 +_cell_angle_alpha 90.00 +_cell_angle_beta 90.00 +_cell_angle_gamma 120.00 +_cell_formula_units_Z 2 +_cell_length_a 12.8617(12) +_cell_length_b 12.8617(12) +_cell_length_c 6.2122(9) +_cell_measurement_reflns_used 713 +_cell_measurement_temperature 120(2) +_cell_measurement_theta_max 24.48 +_cell_measurement_theta_min 3.20 +_cell_volume 889.96(17) +_computing_cell_refinement 'DENZO/SCALEPACK (Otwinowski & Minor, 1997)' +_computing_data_collection 'COLLECT (Nonius, 1998)' +_computing_data_reduction 'DENZO/SCALEPACK (Otwinowski & Minor, 1997)' +_computing_molecular_graphics 'DIAMOND (Brandenburg, 1999)' +_computing_publication_material 'SHELXL97 (Sheldrick, 2008)' +_computing_structure_refinement 'SHELXL97 (Sheldrick, 2008)' +_computing_structure_solution 'SIR2004 (Burla et al., 2005)' +_diffrn_ambient_temperature 120(2) +_diffrn_detector_area_resol_mean 9 +_diffrn_measured_fraction_theta_full 0.993 +_diffrn_measured_fraction_theta_max 0.993 +_diffrn_measurement_device '95mm CCD camera on \k-goniostat' +_diffrn_measurement_device_type 'Nonius KappaCCD' +_diffrn_measurement_method '\f and \w scans with \k offset' +_diffrn_radiation_monochromator 'horizontally mounted graphite crystal' +_diffrn_radiation_source 'fine-focus sealed tube' +_diffrn_radiation_type MoK\a +_diffrn_radiation_wavelength 0.71073 +_diffrn_reflns_av_R_equivalents 0.0428 +_diffrn_reflns_av_sigmaI/netI 0.0346 +_diffrn_reflns_limit_h_max 15 +_diffrn_reflns_limit_h_min -15 +_diffrn_reflns_limit_k_max 15 +_diffrn_reflns_limit_k_min -15 +_diffrn_reflns_limit_l_max 7 +_diffrn_reflns_limit_l_min -7 +_diffrn_reflns_number 5635 +_diffrn_reflns_theta_full 25.00 +_diffrn_reflns_theta_max 25.00 +_diffrn_reflns_theta_min 3.17 +_exptl_absorpt_coefficient_mu 1.006 +_exptl_absorpt_correction_T_max 0.9695 +_exptl_absorpt_correction_T_min 0.8001 +_exptl_absorpt_correction_type multi-scan +_exptl_absorpt_process_details '(DENZO/SCALEPACK; Otwinowski & Minor, 1997)' +_exptl_crystal_colour pink +_exptl_crystal_density_diffrn 1.587 +_exptl_crystal_density_method 'not measured' +_exptl_crystal_description block +_exptl_crystal_F_000 432 +_exptl_crystal_size_max 0.23 +_exptl_crystal_size_mid 0.08 +_exptl_crystal_size_min 0.03 +_refine_diff_density_max 1.048 +_refine_diff_density_min -0.594 +_refine_ls_abs_structure_details 'Flack (1983), 400 Friedel pairs' +_refine_ls_abs_structure_Flack -0.02(7) +_refine_ls_extinction_method none +_refine_ls_goodness_of_fit_ref 1.158 +_refine_ls_hydrogen_treatment constr +_refine_ls_matrix_type full +_refine_ls_number_parameters 86 +_refine_ls_number_reflns 978 +_refine_ls_number_restraints 1 +_refine_ls_restrained_S_all 1.157 +_refine_ls_R_factor_all 0.0753 +_refine_ls_R_factor_gt 0.0682 +_refine_ls_shift/su_max 0.000 +_refine_ls_shift/su_mean 0.000 +_refine_ls_structure_factor_coef Fsqd +_refine_ls_weighting_details +'calc w=1/[\s^2^(Fo^2^)+(0.1316P)^2^+0.9442P] where P=(Fo^2^+2Fc^2^)/3' +_refine_ls_weighting_scheme calc +_refine_ls_wR_factor_gt 0.1873 +_refine_ls_wR_factor_ref 0.1972 +_reflns_number_gt 893 +_reflns_number_total 978 +_reflns_threshold_expression I>2\s(I) +_cod_data_source_file hy2479.cif +_cod_data_source_block I +_cod_original_cell_volume 890.0(2) +_cod_database_code 2232341 +_cod_database_fobs_code 2232341 +loop_ +_symmetry_equiv_pos_as_xyz +'x, y, z' +'x-y, x, z' +'-y, x-y, z' +'-x, -y, z' +'-x+y, -x, z' +'y, -x+y, z' +loop_ +_atom_site_type_symbol +_atom_site_label +_atom_site_fract_x +_atom_site_fract_y +_atom_site_fract_z +_atom_site_U_iso_or_equiv +_atom_site_adp_type +_atom_site_calc_flag +_atom_site_refinement_flags +_atom_site_occupancy +_atom_site_symmetry_multiplicity +Co Co1 0.3333 0.6667 0.3408(2) 0.0379(5) Uani d S 1 3 +O O1 0.4550(7) 0.7860(7) 0.5147(11) 0.0514(18) Uani d . 1 1 +O O2 0.6490(9) 0.8907(8) 0.5627(16) 0.083(3) Uani d . 1 1 +N N1 0.4619(6) 0.6785(6) 0.1705(12) 0.0332(15) Uani d . 1 1 +C C1 0.4622(10) 0.6303(9) -0.0009(17) 0.051(2) Uani d . 1 1 +H H1 0.3875 0.5756 -0.0656 0.061 Uiso calc R 1 1 +C C2 0.5687(9) 0.6533(9) -0.1037(17) 0.050(2) Uani d . 1 1 +H H2 0.5659 0.6145 -0.2355 0.061 Uiso calc R 1 1 +C C3 0.6747(10) 0.7308(9) -0.0138(18) 0.052(2) Uani d . 1 1 +H H3 0.7483 0.7480 -0.0795 0.062 Uiso calc R 1 1 +C C4 0.6729(9) 0.7796(9) 0.159(2) 0.052(3) Uani d . 1 1 +H H4 0.7469 0.8358 0.2241 0.062 Uiso calc R 1 1 +C C5 0.5690(8) 0.7548(9) 0.2577(18) 0.048(2) Uani d . 1 1 +C C6 0.5660(11) 0.8159(9) 0.4512(18) 0.057(3) Uani d . 1 1 +loop_ +_atom_site_aniso_label +_atom_site_aniso_U_11 +_atom_site_aniso_U_22 +_atom_site_aniso_U_33 +_atom_site_aniso_U_12 +_atom_site_aniso_U_13 +_atom_site_aniso_U_23 +Co1 0.0513(7) 0.0513(7) 0.0111(8) 0.0256(3) 0.000 0.000 +O1 0.067(4) 0.066(4) 0.018(4) 0.031(4) -0.007(3) -0.008(3) +O2 0.105(7) 0.067(5) 0.054(6) 0.027(4) -0.036(5) 0.004(4) +N1 0.045(4) 0.047(4) 0.014(3) 0.028(3) -0.001(3) 0.007(3) +C1 0.065(5) 0.056(5) 0.034(5) 0.031(4) 0.006(4) 0.008(4) +C2 0.061(5) 0.058(5) 0.041(6) 0.036(5) 0.010(4) 0.006(4) +C3 0.060(6) 0.059(6) 0.046(6) 0.038(5) 0.014(5) 0.016(5) +C4 0.042(5) 0.067(6) 0.055(7) 0.033(4) 0.012(5) 0.023(6) +C5 0.048(5) 0.057(5) 0.042(6) 0.029(4) -0.005(4) 0.021(5) +C6 0.071(7) 0.052(6) 0.036(6) 0.021(5) -0.027(6) 0.010(5) +loop_ +_atom_type_symbol +_atom_type_description +_atom_type_scat_dispersion_real +_atom_type_scat_dispersion_imag +_atom_type_scat_source +C C 0.0033 0.0016 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' +H H 0.0000 0.0000 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' +N N 0.0061 0.0033 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' +O O 0.0106 0.0060 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' +Co Co 0.3494 0.9721 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4' +loop_ +_geom_angle_atom_site_label_1 +_geom_angle_atom_site_label_2 +_geom_angle_atom_site_label_3 +_geom_angle_site_symmetry_1 +_geom_angle_site_symmetry_3 +_geom_angle +O1 Co1 O1 3_665 . 90.6(3) +O1 Co1 O1 3_665 5_565 90.6(3) +O1 Co1 O1 . 5_565 90.6(3) +O1 Co1 N1 3_665 3_665 85.4(3) +O1 Co1 N1 . 3_665 92.1(2) +O1 Co1 N1 5_565 3_665 175.1(3) +O1 Co1 N1 3_665 5_565 92.1(2) +O1 Co1 N1 . 5_565 175.1(3) +O1 Co1 N1 5_565 5_565 85.4(3) +N1 Co1 N1 3_665 5_565 92.1(3) +O1 Co1 N1 3_665 . 175.1(3) +O1 Co1 N1 . . 85.4(3) +O1 Co1 N1 5_565 . 92.1(2) +N1 Co1 N1 3_665 . 92.1(3) +N1 Co1 N1 5_565 . 92.1(3) +C6 O1 Co1 . . 113.3(7) +C1 N1 C5 . . 117.1(9) +C1 N1 Co1 . . 131.3(7) +C5 N1 Co1 . . 111.5(7) +N1 C1 C2 . . 122.4(10) +N1 C1 H1 . . 118.8 +C2 C1 H1 . . 118.8 +C3 C2 C1 . . 119.3(10) +C3 C2 H2 . . 120.4 +C1 C2 H2 . . 120.4 +C4 C3 C2 . . 117.6(10) +C4 C3 H3 . . 121.2 +C2 C3 H3 . . 121.2 +C3 C4 C5 . . 122.2(11) +C3 C4 H4 . . 118.9 +C5 C4 H4 . . 118.9 +N1 C5 C4 . . 121.4(11) +N1 C5 C6 . . 115.8(10) +C4 C5 C6 . . 122.5(11) +O2 C6 O1 . . 116.2(13) +O2 C6 C5 . . 130.0(13) +O1 C6 C5 . . 113.8(10) +loop_ +_geom_bond_atom_site_label_1 +_geom_bond_atom_site_label_2 +_geom_bond_site_symmetry_2 +_geom_bond_distance +Co1 O1 3_665 1.889(7) +Co1 O1 . 1.889(7) +Co1 O1 5_565 1.889(7) +Co1 N1 3_665 1.904(7) +Co1 N1 5_565 1.904(7) +Co1 N1 . 1.904(7) +O1 C6 . 1.339(15) +O2 C6 . 1.232(14) +N1 C1 . 1.233(14) +N1 C5 . 1.343(12) +C1 C2 . 1.402(14) +C1 H1 . 0.9500 +C2 C3 . 1.344(16) +C2 H2 . 0.9500 +C3 C4 . 1.251(15) +C3 H3 . 0.9500 +C4 C5 . 1.354(14) +C4 H4 . 0.9500 +C5 C6 . 1.447(15) +loop_ +_geom_hbond_atom_site_label_D +_geom_hbond_atom_site_label_H +_geom_hbond_atom_site_label_A +_geom_hbond_site_symmetry_A +_geom_hbond_distance_DH +_geom_hbond_distance_HA +_geom_hbond_distance_DA +_geom_hbond_angle_DHA +C3 H3 O2 2_654 0.95 2.60 3.212(14) 123 +loop_ +_geom_torsion_atom_site_label_1 +_geom_torsion_atom_site_label_2 +_geom_torsion_atom_site_label_3 +_geom_torsion_atom_site_label_4 +_geom_torsion_site_symmetry_1 +_geom_torsion +O1 Co1 O1 C6 3_665 179.0(6) +O1 Co1 O1 C6 5_565 88.4(8) +N1 Co1 O1 C6 . -3.7(7) +O1 Co1 N1 C1 . -175.4(8) +O1 Co1 N1 C1 5_565 94.2(9) +N1 Co1 N1 C1 3_665 -83.4(7) +N1 Co1 N1 C1 5_565 8.8(8) +O1 Co1 N1 C5 . 3.7(6) +O1 Co1 N1 C5 5_565 -86.7(6) +N1 Co1 N1 C5 3_665 95.7(7) +N1 Co1 N1 C5 5_565 -172.1(6) +C5 N1 C1 C2 . -0.3(13) +Co1 N1 C1 C2 . 178.7(6) +N1 C1 C2 C3 . -0.2(14) +C1 C2 C3 C4 . -0.2(14) +C2 C3 C4 C5 . 1.2(15) +C1 N1 C5 C4 . 1.3(13) +Co1 N1 C5 C4 . -177.9(7) +C1 N1 C5 C6 . 176.1(7) +Co1 N1 C5 C6 . -3.1(8) +C3 C4 C5 N1 . -1.8(14) +C3 C4 C5 C6 . -176.3(8) +Co1 O1 C6 O2 . -177.8(7) +Co1 O1 C6 C5 . 2.9(9) +N1 C5 C6 O2 . -179.0(10) +C4 C5 C6 O2 . -4.2(13) +N1 C5 C6 O1 . 0.2(9) +C4 C5 C6 O1 . 174.9(9)