Ejemplo n.º 1
0
def fixed_u_eq_adp_as_cif_loop(xray_structure, proxies):
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4f"
  loop = model.loop(header=(
    "_restr_U_Ueq_atom_site_label_1",
    "_restr_U_Ueq_weight_param",
    "_restr_U_Ueq_target",
    "_restr_U_Ueq_diff"
  ))
  unit_cell = xray_structure.unit_cell()
  params = adp_restraints.adp_restraint_params(
    u_cart=xray_structure.scatterers().extract_u_cart(unit_cell),
    u_iso=xray_structure.scatterers().extract_u_iso(),
    use_u_aniso=xray_structure.use_u_aniso()
    )
  for proxy in proxies:
    restraint = adp_restraints.fixed_u_eq_adp(
      params=params,
      proxy=proxy)
    for i, i_seq in enumerate(proxy.i_seqs):
      loop.add_row((site_labels[i_seq],
                    fmt % math.sqrt(1/proxy.weight),
                    fmt % proxy.u_eq_ideal,
                    fmt % restraint.delta()))
  return loop
Ejemplo n.º 2
0
def distances_as_cif_loop(xray_structure, proxies):
  space_group_info = sgtbx.space_group_info(group=xray_structure.space_group())
  unit_cell = xray_structure.unit_cell()
  sites_cart = xray_structure.sites_cart()
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4f"
  loop = model.loop(header=(
    "_restr_distance_atom_site_label_1",
    "_restr_distance_atom_site_label_2",
    "_restr_distance_site_symmetry_2",
    "_restr_distance_target",
    "_restr_distance_target_weight_param",
    "_restr_distance_diff"
  ))
  for proxy in proxies:
    restraint = geometry_restraints.bond(
      unit_cell=unit_cell,
      sites_cart=sites_cart,
      proxy=proxy)
    i_seqs = proxy.i_seqs
    sym_op = proxy.rt_mx_ji
    if sym_op is None: sym_op = sgtbx.rt_mx()
    loop.add_row((site_labels[i_seqs[0]],
                  site_labels[i_seqs[1]],
                  space_group_info.cif_symmetry_code(sym_op),
                  fmt % restraint.distance_ideal,
                  fmt % math.sqrt(1/restraint.weight),
                  fmt % restraint.delta))
  return loop
Ejemplo n.º 3
0
 def __init__(self,
              pair_asu_table,
              site_labels,
              sites_frac=None,
              sites_cart=None,
              covariance_matrix=None,
              cell_covariance_matrix=None,
              parameter_map=None,
              include_bonds_to_hydrogen=False,
              fixed_angles=None,
              conformer_indices=None,
              eps=2e-16):
   assert [sites_frac, sites_cart].count(None) == 1
   fmt = "%.1f"
   asu_mappings = pair_asu_table.asu_mappings()
   space_group_info = sgtbx.space_group_info(group=asu_mappings.space_group())
   unit_cell = asu_mappings.unit_cell()
   if sites_cart is not None:
     sites_frac = unit_cell.fractionalize(sites_cart)
   self.loop = model.loop(header=(
     "_geom_angle_atom_site_label_1",
     "_geom_angle_atom_site_label_2",
     "_geom_angle_atom_site_label_3",
     "_geom_angle",
     "_geom_angle_site_symmetry_1",
     "_geom_angle_site_symmetry_3"
   ))
   angles = crystal.calculate_angles(
     pair_asu_table, sites_frac,
     covariance_matrix=covariance_matrix,
     cell_covariance_matrix=cell_covariance_matrix,
     parameter_map=parameter_map,
     conformer_indices=conformer_indices)
   for a in angles:
     i_seq, j_seq, k_seq = a.i_seqs
     if (not include_bonds_to_hydrogen
         and (site_labels[i_seq].startswith('H') or
              site_labels[k_seq].startswith('H'))):
       continue
     sym_code_ji = space_group_info.cif_symmetry_code(a.rt_mx_ji)
     sym_code_ki = space_group_info.cif_symmetry_code(a.rt_mx_ki)
     if sym_code_ji == "1": sym_code_ji = "."
     if sym_code_ki == "1": sym_code_ki = "."
     if (a.variance is not None and a.variance > eps
         and not(fixed_angles is not None and
                 ((i_seq, j_seq, k_seq) in fixed_angles or
                  (k_seq, j_seq, i_seq) in fixed_angles))):
       angle = format_float_with_su(a.angle, math.sqrt(a.variance))
     else:
       angle = fmt % a.angle
     self.loop.add_row((site_labels[i_seq],
                        site_labels[j_seq],
                        site_labels[k_seq],
                        angle,
                        sym_code_ji,
                        sym_code_ki,
                        ))
   self.angles = angles.angles
   self.variances = angles.variances
Ejemplo n.º 4
0
    def __init__(self,
                 crystal_symmetry,
                 cell_covariance_matrix=None,
                 format="coreCIF"):
        self.format = format.lower()
        assert self.format in ("corecif", "mmcif")
        if self.format == "mmcif": self.separator = '.'
        else: self.separator = '_'
        self.cif_block = model.block()
        cell_prefix = '_cell%s' % self.separator
        if crystal_symmetry.space_group() is not None:
            sym_loop = model.loop(data=OrderedDict((
                ('_space_group_symop' + self.separator + 'id',
                 range(1,
                       len(crystal_symmetry.space_group()) + 1)),
                ('_space_group_symop' + self.separator + 'operation_xyz',
                 [s.as_xyz() for s in crystal_symmetry.space_group()]))))
            self.cif_block.add_loop(sym_loop)
            sg_prefix = '_space_group%s' % self.separator
            sg_type = crystal_symmetry.space_group_info().type()
            sg = sg_type.group()
            self.cif_block[sg_prefix +
                           'crystal_system'] = sg.crystal_system().lower()
            self.cif_block[sg_prefix + 'IT_number'] = sg_type.number()
            self.cif_block[sg_prefix +
                           'name_H-M_alt'] = sg_type.lookup_symbol()
            self.cif_block[sg_prefix + 'name_Hall'] = sg_type.hall_symbol()

            sg_prefix = '_symmetry%s' % self.separator
            self.cif_block[sg_prefix +
                           'space_group_name_H-M'] = sg_type.lookup_symbol()
            self.cif_block[sg_prefix +
                           'space_group_name_Hall'] = sg_type.hall_symbol()
            self.cif_block[sg_prefix + 'Int_Tables_number'] = sg_type.number()

        if crystal_symmetry.unit_cell() is not None:
            uc = crystal_symmetry.unit_cell()
            params = list(uc.parameters())
            volume = uc.volume()
            if cell_covariance_matrix is not None:
                diag = cell_covariance_matrix.matrix_packed_u_diagonal()
                for i in range(6):
                    if diag[i] > 0:
                        params[i] = format_float_with_su(
                            params[i], math.sqrt(diag[i]))
                d_v_d_params = matrix.row(uc.d_volume_d_params())
                vcv = matrix.sqr(
                    cell_covariance_matrix.matrix_packed_u_as_symmetric())
                var_v = (d_v_d_params * vcv).dot(d_v_d_params)
                volume = format_float_with_su(volume, math.sqrt(var_v))
            a, b, c, alpha, beta, gamma = params
            self.cif_block[cell_prefix + 'length_a'] = a
            self.cif_block[cell_prefix + 'length_b'] = b
            self.cif_block[cell_prefix + 'length_c'] = c
            self.cif_block[cell_prefix + 'angle_alpha'] = alpha
            self.cif_block[cell_prefix + 'angle_beta'] = beta
            self.cif_block[cell_prefix + 'angle_gamma'] = gamma
            self.cif_block[cell_prefix + 'volume'] = volume
Ejemplo n.º 5
0
def bond_similarity_as_cif_loops(xray_structure, proxies):
  space_group_info = sgtbx.space_group_info(group=xray_structure.space_group())
  unit_cell = xray_structure.unit_cell()
  sites_cart = xray_structure.sites_cart()
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4f"
  loop = model.loop(header=(
    "_restr_equal_distance_atom_site_label_1",
    "_restr_equal_distance_atom_site_label_2",
    "_restr_equal_distance_site_symmetry_2",
    "_restr_equal_distance_class_id",
  ))
  class_loop = model.loop(header=(
    "_restr_equal_distance_class_class_id",
    "_restr_equal_distance_class_target_weight_param",
    "_restr_equal_distance_class_average",
    "_restr_equal_distance_class_esd",
    "_restr_equal_distance_class_diff_max",
  ))
  class_id = 0
  for proxy in proxies:
    restraint = geometry_restraints.bond_similarity(
      unit_cell=unit_cell,
      sites_cart=sites_cart,
      proxy=proxy)
    class_id += 1
    esd = math.sqrt(flex.sum(flex.pow2(restraint.deltas())) *
                    (1./proxy.i_seqs.size()))
    class_loop.add_row((class_id,
                        fmt % math.sqrt(1/proxy.weights[0]),# assume equal weights
                        fmt % restraint.mean_distance(),
                        fmt % esd,
                        fmt % flex.max_absolute(restraint.deltas())))
    for i in range(proxy.i_seqs.size()):
      i_seq, j_seq = proxy.i_seqs[i]
      if proxy.sym_ops is None:
        sym_op = sgtbx.rt_mx()
      else:
        sym_op = proxy.sym_ops[i]
      loop.add_row((site_labels[i_seq],
                    site_labels[j_seq],
                    space_group_info.cif_symmetry_code(sym_op),
                    class_id))
  return class_loop, loop
Ejemplo n.º 6
0
def isotropic_adp_as_cif_loop(xray_structure, proxies):
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4f"
  loop = model.loop(header=(
    "_restr_U_iso_atom_site_label",
    "_restr_U_iso_weight_param",
  ))
  for proxy in proxies:
    loop.add_row((site_labels[proxy.i_seqs[0]], fmt % math.sqrt(1/proxy.weight)))
  return loop
Ejemplo n.º 7
0
 def add_loop(self, header, columns):
   if self._current_save is not None:
     block = self._current_save
   else:
     block = self._current_block
   loop = model.loop()
   assert len(header) == len(columns)
   n_columns = len(columns)
   for i in range(n_columns):
     loop[header[i]] = columns[i]
   block.add_loop(loop)
Ejemplo n.º 8
0
 def add_loop(self, header, columns):
     if self._current_save is not None:
         block = self._current_save
     else:
         block = self._current_block
     loop = model.loop()
     assert len(header) == len(columns)
     n_columns = len(columns)
     for i in range(n_columns):
         loop[header[i]] = columns[i]
     block.add_loop(loop)
Ejemplo n.º 9
0
 def __init__(self,
              pair_asu_table,
              site_labels,
              sites_frac=None,
              sites_cart=None,
              covariance_matrix=None,
              cell_covariance_matrix=None,
              parameter_map=None,
              include_bonds_to_hydrogen=False,
              fixed_distances=None,
              eps=2e-16):
   assert [sites_frac, sites_cart].count(None) == 1
   fmt = "%.4f"
   asu_mappings = pair_asu_table.asu_mappings()
   space_group_info = sgtbx.space_group_info(group=asu_mappings.space_group())
   unit_cell = asu_mappings.unit_cell()
   if sites_cart is not None:
     sites_frac = unit_cell.fractionalize(sites_cart)
   self.loop = model.loop(header=(
     "_geom_bond_atom_site_label_1",
     "_geom_bond_atom_site_label_2",
     "_geom_bond_distance",
     "_geom_bond_site_symmetry_2"
   ))
   distances = crystal.calculate_distances(
     pair_asu_table, sites_frac,
     covariance_matrix=covariance_matrix,
     cell_covariance_matrix=cell_covariance_matrix,
     parameter_map=parameter_map)
   for d in distances:
     if (not include_bonds_to_hydrogen
         and (site_labels[d.i_seq].startswith('H') or
              site_labels[d.j_seq].startswith('H'))):
       continue
     if (d.variance is not None and d.variance > eps
         and not(fixed_distances is not None and
                 ((d.i_seq, d.j_seq) in fixed_distances or
                  (d.j_seq, d.i_seq) in fixed_distances))):
       distance = format_float_with_su(d.distance, math.sqrt(d.variance))
     else:
       distance = fmt % d.distance
     sym_code = space_group_info.cif_symmetry_code(d.rt_mx_ji)
     if sym_code == "1": sym_code = "."
     self.loop.add_row((site_labels[d.i_seq],
                        site_labels[d.j_seq],
                        distance,
                        sym_code))
   self.distances = distances.distances
   self.variances = distances.variances
   self.pair_counts = distances.pair_counts
Ejemplo n.º 10
0
def adp_volume_similarity_as_cif_loops(xray_structure, proxies):
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4e"
  loop = model.loop(header=(
    "_restr_U_volume_similar_atom_site_label_1",
    "_restr_U_volume_similar_diff",
    "_restr_U_volume_similar_class_id",
  ))
  class_loop = model.loop(header=(
    "_restr_U_volume_similar_class_class_id",
    "_restr_U_volume_similar_class_target_weight_param",
    "_restr_U_volume_similar_class_average",
    "_restr_U_volume_similar_class_esd",
    "_restr_U_volume_similar_class_diff_max",
  ))
  unit_cell = xray_structure.unit_cell()
  params = adp_restraints.adp_restraint_params(
    u_cart=xray_structure.scatterers().extract_u_cart(unit_cell),
    u_iso=xray_structure.scatterers().extract_u_iso(),
    use_u_aniso=xray_structure.use_u_aniso()
    )
  class_id = 0
  for proxy in proxies:
    restraint = adp_restraints.adp_volume_similarity(
      params=params,
      proxy=proxy)
    class_id += 1
    class_loop.add_row((class_id,
                        fmt % math.sqrt(1/proxy.weight),
                        fmt % restraint.mean_u_volume,
                        fmt % restraint.rms_deltas(),
                        fmt % flex.max_absolute(restraint.deltas())))
    for i, i_seq in enumerate(proxy.i_seqs):
      loop.add_row((site_labels[i_seq],
                    fmt % restraint.deltas()[i],
                    class_id))
  return class_loop, loop
Ejemplo n.º 11
0
def dihedrals_as_cif_loop(xray_structure, proxies):
  space_group_info = sgtbx.space_group_info(group=xray_structure.space_group())
  unit_cell = xray_structure.unit_cell()
  sites_cart = xray_structure.sites_cart()
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4f"
  loop = model.loop(header=(
    "_restr_torsion_atom_site_label_1",
    "_restr_torsion_atom_site_label_2",
    "_restr_torsion_atom_site_label_3",
    "_restr_torsion_atom_site_label_4",
    "_restr_torsion_site_symmetry_1",
    "_restr_torsion_site_symmetry_2",
    "_restr_torsion_site_symmetry_3",
    "_restr_torsion_site_symmetry_4",
    "_restr_torsion_angle_target",
    "_restr_torsion_weight_param",
    "_restr_torsion_diff",
  ))
  unit_mxs = [sgtbx.rt_mx()]*4
  for proxy in proxies:
    restraint = geometry_restraints.dihedral(
      unit_cell=unit_cell,
      sites_cart=sites_cart,
      proxy=proxy)
    sym_ops = proxy.sym_ops
    if sym_ops is None: sym_ops = unit_mxs
    i_seqs = proxy.i_seqs
    loop.add_row((site_labels[i_seqs[0]],
                  site_labels[i_seqs[1]],
                  site_labels[i_seqs[2]],
                  site_labels[i_seqs[3]],
                  space_group_info.cif_symmetry_code(sym_ops[0]),
                  space_group_info.cif_symmetry_code(sym_ops[1]),
                  space_group_info.cif_symmetry_code(sym_ops[2]),
                  space_group_info.cif_symmetry_code(sym_ops[3]),
                  fmt % restraint.angle_ideal,
                  fmt % math.sqrt(1/restraint.weight),
                  fmt % restraint.delta))
  return loop
Ejemplo n.º 12
0
def rigid_bond_as_cif_loop(xray_structure, proxies):
  unit_cell = xray_structure.unit_cell()
  sites_cart = xray_structure.sites_cart()
  u_cart = xray_structure.scatterers().extract_u_cart(unit_cell)
  site_labels = xray_structure.scatterers().extract_labels()
  fmt = "%.4f"
  loop = model.loop(header=(
    "_restr_U_rigid_atom_site_label_1",
    "_restr_U_rigid_atom_site_label_2",
    "_restr_U_rigid_target_weight_param",
    "_restr_U_rigid_U_parallel",
    "_restr_U_rigid_diff",
  ))
  for proxy in proxies:
    restraint = adp_restraints.rigid_bond(
      adp_restraint_params(sites_cart=sites_cart, u_cart=u_cart),
      proxy=proxy)
    loop.add_row((site_labels[proxy.i_seqs[0]],
                  site_labels[proxy.i_seqs[1]],
                  fmt % math.sqrt(1/proxy.weight),
                  fmt % (0.5*(restraint.z_12()+restraint.z_21())),
                  fmt % restraint.delta_z()))
  return loop
Ejemplo n.º 13
0
 def __init__(self,
              hbonds,
              pair_asu_table,
              site_labels,
              sites_frac=None,
              sites_cart=None,
              min_dha_angle=150, # degrees
              max_da_distance=2.9, # angstrom
              covariance_matrix=None,
              cell_covariance_matrix=None,
              parameter_map=None,
              eps=2e-16):
   assert [sites_frac, sites_cart].count(None) == 1
   fmt_a = "%.1f"
   pair_asu_table = pair_asu_table
   asu_mappings = pair_asu_table.asu_mappings()
   space_group_info = sgtbx.space_group_info(group=asu_mappings.space_group())
   self.unit_cell = asu_mappings.unit_cell()
   if sites_cart is not None:
     sites_frac = self.unit_cell.fractionalize(sites_cart)
   if sites_frac is not None:
     sites_cart = self.unit_cell.orthogonalize(sites_frac)
   if covariance_matrix is not None:
     assert parameter_map is not None
     self.covariance_matrix_cart = covariance.orthogonalize_covariance_matrix(
       covariance_matrix, self.unit_cell, parameter_map)
   else: self.covariance_matrix_cart = None
   self.cell_covariance_matrix = cell_covariance_matrix
   self.eps = eps
   self.parameter_map = parameter_map
   self.loop = model.loop(header=(
     "_geom_hbond_atom_site_label_D",
     "_geom_hbond_atom_site_label_H",
     "_geom_hbond_atom_site_label_A",
     "_geom_hbond_distance_DH",
     "_geom_hbond_distance_HA",
     "_geom_hbond_distance_DA",
     "_geom_hbond_angle_DHA",
     "_geom_hbond_site_symmetry_A",
   ))
   for hbond in hbonds:
     d_seq, a_seq = hbond.d_seq, hbond.a_seq
     site_cart_d = sites_cart[d_seq]
     if hbond.rt_mx is not None:
       site_frac_a = sites_frac[a_seq]
       site_frac_a = hbond.rt_mx * site_frac_a
       site_cart_a = self.unit_cell.orthogonalize(site_frac_a)
     else:
       site_cart_a = sites_cart[a_seq]
     distance_da = geometry.distance((site_cart_d, site_cart_a))
     for h_seq, h_sym_groups in pair_asu_table.table()[hbond.d_seq].items():
       if site_labels[h_seq][0] not in ('H','D'):
         # XXX better to pass scattering types instead?
         continue
       site_cart_h = sites_cart[h_seq]
       distance_dh = geometry.distance((site_cart_d, site_cart_h))
       distance_ha = geometry.distance((site_cart_h, site_cart_a))
       angle_dha = geometry.angle((site_cart_d, site_cart_h, site_cart_a))
       if (angle_dha.angle_model < min_dha_angle or
           distance_da.distance_model > max_da_distance):
         continue
       if hbond.rt_mx is not None:
         sym_code = space_group_info.cif_symmetry_code(hbond.rt_mx)
       else: sym_code = '.'
       self.loop.add_row((
         site_labels[d_seq],
         site_labels[h_seq],
         site_labels[a_seq],
         self.formatted_distance(d_seq, h_seq, distance_dh, unit_mx),
         self.formatted_distance(h_seq, a_seq, distance_ha, unit_mx),
         self.formatted_distance(d_seq, a_seq, distance_da, hbond.rt_mx),
         self.formatted_angle(d_seq, h_seq, a_seq, angle_dha, hbond.rt_mx),
         sym_code
       ))
Ejemplo n.º 14
0
def miller_indices_as_cif_loop(indices, prefix='_refln_'):
    refln_loop = model.loop(header=('%sindex_h' % prefix, '%sindex_k' % prefix,
                                    '%sindex_l' % prefix))
    for hkl in indices:
        refln_loop.add_row(hkl)
    return refln_loop
Ejemplo n.º 15
0
def atom_type_cif_loop(xray_structure, format="coreCIF"):
    format = format.lower()
    assert format in ("corecif", "mmcif")
    if format == "mmcif": separator = '.'
    else: separator = '_'

    sources = {
        "it1992": "International Tables Volume C Table 6.1.1.4 (pp. 500-502)",
        "wk1995": "Waasmaier & Kirfel (1995), Acta Cryst. A51, 416-431",
    }
    inelastic_references = {
        "henke":
        "Henke, Gullikson and Davis, At. Data and Nucl. Data Tables, 1993, 54, 2",
        "sasaki": "Sasaki, KEK Report, 1989, 88-14, 1",
    }

    scattering_type_registry = xray_structure.scattering_type_registry()
    unique_gaussians = scattering_type_registry.unique_gaussians_as_list()
    max_n_gaussians = max(
        [gaussian.n_terms() for gaussian in unique_gaussians])
    # _atom_type_* loop
    header = [
        '_atom_type%ssymbol' % separator,
        '_atom_type%sscat_dispersion_real' % separator,
        '_atom_type%sscat_dispersion_imag' % separator
    ]
    header.extend([
        '_atom_type%sscat_Cromer_Mann_a%i' % (separator, i + 1)
        for i in range(max_n_gaussians)
    ])
    header.extend([
        '_atom_type%sscat_Cromer_Mann_b%i' % (separator, i + 1)
        for i in range(max_n_gaussians)
    ])
    header.extend([
        '_atom_type%sscat_Cromer_Mann_c' % separator,
        '_atom_type%sscat_source' % separator,
        '_atom_type%sscat_dispersion_source' % separator
    ])
    atom_type_loop = model.loop(header=header)
    gaussian_dict = scattering_type_registry.as_type_gaussian_dict()
    scattering_type_registry = xray_structure.scattering_type_registry()
    params = xray_structure.scattering_type_registry_params
    fp_fdp_table = {}
    for sc in xray_structure.scatterers():
        fp_fdp_table.setdefault(sc.scattering_type, (sc.fp, sc.fdp))
    disp_source = inelastic_references.get(
        xray_structure.inelastic_form_factors_source)
    # custom?
    if disp_source is None:
        disp_source = xray_structure.inelastic_form_factors_source
    if disp_source is None:
        disp_source = "."
    for atom_type, gaussian in scattering_type_registry.as_type_gaussian_dict(
    ).iteritems():
        scat_source = sources.get(params.table)
        if params.custom_dict and atom_type in params.custom_dict:
            scat_source = "Custom %i-Gaussian" % gaussian.n_terms()
        elif scat_source is None:
            scat_source = """\
%i-Gaussian fit: Grosse-Kunstleve RW, Sauter NK, Adams PD:
Newsletter of the IUCr Commission on Crystallographic Computing 2004, 3, 22-31."""
            scat_source = scat_source % gaussian.n_terms()
        if disp_source == ".":
            fp, fdp = ".", "."
        else:
            fp, fdp = fp_fdp_table[atom_type]
            fp = "%.5f" % fp
            fdp = "%.5f" % fdp
        row = [atom_type, fp, fdp]
        #gaussian = gaussian_dict[sc.scattering_type]
        gaussian_a = ["%.5f" % a for a in gaussian.array_of_a()]
        gaussian_b = ["%.5f" % a for a in gaussian.array_of_b()]
        gaussian_a.extend(["."] * (max_n_gaussians - gaussian.n_terms()))
        gaussian_b.extend(["."] * (max_n_gaussians - gaussian.n_terms()))
        row.extend(gaussian_a + gaussian_b)
        row.extend([gaussian.c(), scat_source, disp_source])
        atom_type_loop.add_row(row)

    return atom_type_loop
Ejemplo n.º 16
0
    def __init__(self,
                 xray_structure,
                 covariance_matrix=None,
                 cell_covariance_matrix=None):
        crystal_symmetry_as_cif_block.__init__(
            self,
            xray_structure.crystal_symmetry(),
            cell_covariance_matrix=cell_covariance_matrix)
        scatterers = xray_structure.scatterers()
        uc = xray_structure.unit_cell()
        if covariance_matrix is not None:
            param_map = xray_structure.parameter_map()
            covariance_diagonal = covariance_matrix.matrix_packed_u_diagonal()
            u_star_to_u_cif_linear_map_pow2 = flex.pow2(
                flex.double(uc.u_star_to_u_cif_linear_map()))
            u_star_to_u_iso_linear_form = matrix.row(
                uc.u_star_to_u_iso_linear_form())
        fmt = "%.6f"

        # _atom_site_* loop
        atom_site_loop = model.loop(
            header=('_atom_site_label', '_atom_site_type_symbol',
                    '_atom_site_fract_x', '_atom_site_fract_y',
                    '_atom_site_fract_z', '_atom_site_U_iso_or_equiv',
                    '_atom_site_adp_type', '_atom_site_occupancy'))
        for i_seq, sc in enumerate(scatterers):
            # site
            if covariance_matrix is not None and sc.flags.grad_site():
                site = []
                for i in range(3):
                    idx = param_map[i_seq].site
                    if idx > -1:
                        var = covariance_diagonal[idx + i]
                    else:
                        var = 0
                    if var > 0:
                        site.append(
                            format_float_with_su(sc.site[i], math.sqrt(var)))
                    else:
                        site.append(fmt % sc.site[i])
            else:
                site = [fmt % sc.site[i] for i in range(3)]
            # u_eq
            if (covariance_matrix is not None
                    and (sc.flags.grad_u_iso() or sc.flags.grad_u_aniso())):
                if sc.flags.grad_u_iso():
                    u_iso_or_equiv = format_float_with_su(
                        sc.u_iso,
                        math.sqrt(
                            covariance.variance_for_u_iso(
                                i_seq, covariance_matrix, param_map)))
                else:
                    cov = covariance.extract_covariance_matrix_for_u_aniso(
                        i_seq, covariance_matrix,
                        param_map).matrix_packed_u_as_symmetric()
                    var = (u_star_to_u_iso_linear_form *
                           matrix.sqr(cov)).dot(u_star_to_u_iso_linear_form)
                    u_iso_or_equiv = format_float_with_su(
                        sc.u_iso_or_equiv(uc), math.sqrt(var))
            else:
                u_iso_or_equiv = fmt % sc.u_iso_or_equiv(uc)
            if sc.flags.use_u_aniso():
                adp_type = 'Uani'
            else:
                adp_type = 'Uiso'
            atom_site_loop.add_row(
                (sc.label, sc.scattering_type, site[0], site[1], site[2],
                 u_iso_or_equiv, adp_type, fmt % sc.occupancy))
        self.cif_block.add_loop(atom_site_loop)

        # _atom_site_aniso_* loop
        aniso_scatterers = scatterers.select(scatterers.extract_use_u_aniso())
        if aniso_scatterers.size():
            labels = list(scatterers.extract_labels())
            aniso_loop = model.loop(
                header=('_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'))
            for sc in aniso_scatterers:
                u_cif = adptbx.u_star_as_u_cif(uc, sc.u_star)
                if covariance_matrix is not None:
                    row = [sc.label]
                    idx = param_map[labels.index(sc.label)].u_aniso
                    if idx > -1:
                        var = covariance_diagonal[
                            idx:idx + 6] * u_star_to_u_cif_linear_map_pow2
                        for i in range(6):
                            if var[i] > 0:
                                row.append(
                                    format_float_with_su(
                                        u_cif[i], math.sqrt(var[i])))
                            else:
                                row.append(fmt % u_cif[i])
                    else:
                        row = [sc.label] + [fmt % u_cif[i] for i in range(6)]
                else:
                    row = [sc.label] + [fmt % u_cif[i] for i in range(6)]
                aniso_loop.add_row(row)
            self.cif_block.add_loop(aniso_loop)
            self.cif_block.add_loop(atom_type_cif_loop(xray_structure))