Esempio n. 1
0
def chirality_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_chirality_atom_site_label_1",
    "_restr_chirality_atom_site_label_2",
    "_restr_chirality_atom_site_label_3",
    "_restr_chirality_atom_site_label_4",
    "_restr_chirality_site_symmetry_1",
    "_restr_chirality_site_symmetry_2",
    "_restr_chirality_site_symmetry_3",
    "_restr_chirality_site_symmetry_4",
    "_restr_chirality_volume_target",
    "_restr_chirality_weight_param",
    "_restr_chirality_diff",
  ))
  unit_mxs = [sgtbx.rt_mx()]*4
  for proxy in proxies:
    restraint = geometry_restraints.chirality(
      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.volume_ideal,
                  fmt % math.sqrt(1/restraint.weight),
                  fmt % restraint.delta))
  return loop
Esempio n. 2
0
def exercise_chirality(verbose=0):
    # monomer library: CA N CB C
    sites = [
        col(site)
        for site in [(27.660, 9.903,
                      2.078), (28.049, 9.675,
                               3.486), (28.183, 11.269,
                                        1.625), (28.085, 8.759, 1.165)]
    ]
    chir = geometry_restraints.chirality(sites=sites,
                                         volume_ideal=-2.48,
                                         both_signs=False,
                                         weight=1)
    assert approx_equal(chir.volume_model, -2.411548478)
    assert approx_equal(chir.residual(), 0.00468561086412)
    dih = geometry_restraints.dihedral(sites=improper_permutation(sites),
                                       angle_ideal=35.26439,
                                       weight=1)
    assert approx_equal(dih.angle_model, 32.2587249641)
    assert approx_equal(dih.residual(), 9.03402230782)
    if (verbose):
        dump_pdb("sites.pdb", sites)
        print("volume_ideal:", chir.volume_ideal)
        print("volume_model:", chir.volume_model)
        print("angle_ideal:", dih.angle_ideal)
        print("angle model:", dih.angle_model)
    for i_trial in range(50):
        volume_ideal = chir.volume_ideal
        for both_signs in [False, True]:
            sites_mod = []
            for site in sites:
                shift = col([random.uniform(-.5, .5) for i in range(3)])
                sites_mod.append(site + shift)
            if (both_signs): volume_ideal = abs(volume_ideal)
            c = geometry_restraints.chirality(sites=sites_mod,
                                              volume_ideal=volume_ideal,
                                              both_signs=both_signs,
                                              weight=500 * 1 / 0.2**2)
            residual_obj = residual_functor(
                restraint_type=geometry_restraints.chirality,
                volume_ideal=c.volume_ideal,
                both_signs=c.both_signs,
                weight=c.weight)
            fg = flex.vec3_double(finite_differences(
                sites_mod, residual_obj)).as_double()
            ag = flex.vec3_double(c.gradients()).as_double()
            scale = max(1, flex.mean(flex.abs(fg)))
            assert approx_equal(ag / scale, fg / scale)
            d = geometry_restraints.dihedral(
                sites=improper_permutation(sites_mod),
                angle_ideal=dih.angle_ideal,
                weight=750)
            ag_dih = dih.gradients()
            if (verbose and i_trial == 0 and not both_signs):
                dump_pdb("sites_mod.pdb", sites_mod)
                max_g_len = 0
                for g in ag_dih:
                    max_g_len = max(max_g_len, abs(col(g)))
                for g in flex.vec3_double(fg):
                    max_g_len = max(max_g_len, abs(col(g)))
                sticks = []
                for site, g in zip(improper_permutation(sites_mod), ag_dih):
                    sticks.append(
                        pml_stick(begin=site,
                                  end=site + col(g) / max_g_len,
                                  colors=[[1, 0, 0]] * 2,
                                  width=0.01))
                pml_write(f=open("dih.pml", "w"), label="dih", sticks=sticks)
                sticks = []
                for site, g in zip(sites_mod, flex.vec3_double(fg)):
                    sticks.append(
                        pml_stick(begin=site,
                                  end=site + col(g) / max_g_len,
                                  colors=[[0, 1, 0]] * 2,
                                  width=0.01))
                pml_write(f=open("chir.pml", "w"), label="chir", sticks=sticks)
Esempio n. 3
0
  def ensemble_mean_geometry_stats(self,
                                   restraints_manager,
                                   xray_structure,
                                   ensemble_xray_structures,
                                   ignore_hd = True,
                                   verbose = False,
                                   out = None,
                                   return_pdb_string = False):
    if (out is None): out = sys.stdout
    if verbose:
      utils.print_header("Ensemble mean geometry statistics", out = out)
    ensemble_size = len(ensemble_xray_structures)
    print("Ensemble size : ", ensemble_size, file=out)

    # Dictionaries to store deltas
    ensemble_bond_deltas = {}
    ensemble_angle_deltas = {}
    ensemble_chirality_deltas = {}
    ensemble_planarity_deltas = {}
    ensemble_dihedral_deltas = {}

    # List to store rmsd of each model
    structures_bond_rmsd = flex.double()
    structures_angle_rmsd = flex.double()
    structures_chirality_rmsd = flex.double()
    structures_planarity_rmsd = flex.double()
    structures_dihedral_rmsd = flex.double()

    # Remove water and hd atoms from global restraints manager
    selection = flex.bool()
    for sc in xray_structure.scatterers():
      if sc.label.find('HOH') > -1:
        selection.append(True)
      else:
        selection.append(False)
    if ignore_hd:
      hd_selection = xray_structure.hd_selection()
      assert hd_selection.size() == selection.size()
      for n in range(hd_selection.size()):
        if hd_selection[n] or selection[n]:
          selection[n] = True
    restraints_manager = restraints_manager.select(selection = ~selection)

    # Get all deltas
    for n, structure in enumerate(ensemble_xray_structures):
      if verbose:
        print("\nModel : ", n+1, file=out)
      sites_cart = structure.sites_cart()
      # Remove water and hd atoms from individual structures sites cart
      selection = flex.bool()
      for sc in structure.scatterers():
        if sc.label.find('HOH') > -1:
          selection.append(True)
        else:
          selection.append(False)
      if ignore_hd:
        hd_selection = structure.hd_selection()
        assert hd_selection.size() == selection.size()
        for n in range(hd_selection.size()):
          if hd_selection[n] or selection[n]:
            selection[n] = True
      sites_cart = sites_cart.select(~selection)
      assert sites_cart is not None
      site_labels = None
      energies_sites = restraints_manager.energies_sites(
          sites_cart        = sites_cart,
          compute_gradients = False)

      # Rmsd of individual model
      bond_rmsd = energies_sites.geometry.bond_deviations()[2]
      angle_rmsd = energies_sites.geometry.angle_deviations()[2]
      chirality_rmsd = energies_sites.geometry.chirality_deviations()[2]
      planarity_rmsd = energies_sites.geometry.planarity_deviations()[2]
      dihedral_rmsd = energies_sites.geometry.dihedral_deviations()[2]

      structures_bond_rmsd.append(bond_rmsd)
      structures_angle_rmsd.append(angle_rmsd)
      structures_chirality_rmsd.append(chirality_rmsd)
      structures_planarity_rmsd.append(planarity_rmsd)
      structures_dihedral_rmsd.append(dihedral_rmsd)

      if verbose:
        print("  Model RMSD", file=out)
        print("    bond      : %.6g" % bond_rmsd, file=out)
        print("    angle     : %.6g" % angle_rmsd, file=out)
        print("    chirality : %.6g" % chirality_rmsd, file=out)
        print("    planarity : %.6g" % planarity_rmsd, file=out)
        print("    dihedral  : %.6g" % dihedral_rmsd, file=out)

      # Bond
      pair_proxies = restraints_manager.geometry.pair_proxies(flags=None, sites_cart=sites_cart)
      assert pair_proxies is not None
      if verbose:
        pair_proxies.bond_proxies.show_histogram_of_deltas(
          sites_cart  = sites_cart,
          n_slots     = 10,
          f           = out)
      for proxy in pair_proxies.bond_proxies.simple:
        bond_simple_proxy = geometry_restraints.bond(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_bond_deltas:
          ensemble_bond_deltas[proxy.i_seqs][0]+=bond_simple_proxy.delta
          ensemble_bond_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_bond_deltas[proxy.i_seqs] = [bond_simple_proxy.delta, 1]
        if verbose:
          print("bond simple :", proxy.i_seqs, file=out)
          print("  distance_ideal : %.6g" % proxy.distance_ideal, file=out)
          print("  distance_model : %.6g" % bond_simple_proxy.distance_model, file=out)
          print("  detla          : %.6g" % bond_simple_proxy.delta, file=out)
      if (pair_proxies.bond_proxies.asu.size() > 0):
        asu_mappings = pair_proxies.bond_proxies.asu_mappings()
        for proxy in pair_proxies.bond_proxies.asu:
          rt_mx = asu_mappings.get_rt_mx_ji(pair=proxy)
          bond_asu_proxy = geometry_restraints.bond(
              sites_cart   = sites_cart,
              asu_mappings = asu_mappings,
              proxy        = proxy)
          proxy_i_seqs = (proxy.i_seq, proxy.j_seq)
          if proxy_i_seqs in ensemble_bond_deltas:
            ensemble_bond_deltas[proxy_i_seqs][0]+=bond_asu_proxy.delta
            ensemble_bond_deltas[proxy_i_seqs][1]+=1
          else:
            ensemble_bond_deltas[proxy_i_seqs] = [bond_asu_proxy.delta, 1]
          if verbose:
            print("bond asu :", (proxy.i_seq, proxy.j_seq), rt_mx, file=out)
            print("  distance_ideal : %.6g" % proxy.distance_ideal, file=out)
            print("  distance_model : %.6g" % bond_asu_proxy.distance_model, file=out)
            print("  delta          : %.6g" % bond_asu_proxy.delta, file=out)

      # Angle
      if verbose:
        restraints_manager.geometry.angle_proxies.show_histogram_of_deltas(
            sites_cart  = sites_cart,
            n_slots     = 10,
            f           = out)
      for proxy in restraints_manager.geometry.angle_proxies:
        angle_proxy = geometry_restraints.angle(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_angle_deltas:
          ensemble_angle_deltas[proxy.i_seqs][0]+=angle_proxy.delta
          ensemble_angle_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_angle_deltas[proxy.i_seqs] = [angle_proxy.delta, 1]
        if verbose:
          print("angle : ", proxy.i_seqs, file=out)
          print("  angle_ideal   : %.6g" % proxy.angle_ideal, file=out)
          print("  angle_model   : %.6g" % angle_proxy.angle_model, file=out)
          print("  delta         : %.6g" % angle_proxy.delta, file=out)

      # Chirality
      if verbose:
        restraints_manager.geometry.chirality_proxies.show_histogram_of_deltas(
            sites_cart  = sites_cart,
            n_slots     = 10,
            f           = out)
      for proxy in restraints_manager.geometry.chirality_proxies:
        chirality_proxy = geometry_restraints.chirality(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_chirality_deltas:
          ensemble_chirality_deltas[proxy.i_seqs][0]+=chirality_proxy.delta
          ensemble_chirality_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_chirality_deltas[proxy.i_seqs] = [chirality_proxy.delta, 1]
        if verbose:
          print("chirality : ", proxy.i_seqs, file=out)
          print("  chirality_ideal : %.6g" % proxy.volume_ideal, file=out)
          print("  chirality_model : %.6g" % chirality_proxy.volume_model, file=out)
          print("  chirality       : %.6g" % chirality_proxy.delta, file=out)

      # Planarity
      for proxy in restraints_manager.geometry.planarity_proxies:
        planarity_proxy = geometry_restraints.planarity(
            sites_cart = sites_cart,
            proxy      = proxy)
        proxy_i_seqs = []
        for i_seq in proxy.i_seqs:
          proxy_i_seqs.append(i_seq)
        proxy_i_seqs = tuple(proxy_i_seqs)
        if proxy_i_seqs in ensemble_planarity_deltas:
          ensemble_planarity_deltas[proxy_i_seqs][0]+=planarity_proxy.rms_deltas()
          ensemble_planarity_deltas[proxy_i_seqs][1]+=1
        else:
          ensemble_planarity_deltas[proxy_i_seqs] = [planarity_proxy.rms_deltas(), 1]
        if verbose:
          print("planarity : ", proxy_i_seqs, file=out)
          print("  planarity rms_deltas : %.6g" % planarity_proxy.rms_deltas(), file=out)

      # Dihedral
      if verbose:
        restraints_manager.geometry.dihedral_proxies.show_histogram_of_deltas(
            sites_cart  = sites_cart,
            n_slots     = 10,
            f           = out)
      for proxy in restraints_manager.geometry.dihedral_proxies:
        dihedral_proxy = geometry_restraints.dihedral(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_dihedral_deltas:
          ensemble_dihedral_deltas[proxy.i_seqs][0]+=dihedral_proxy.delta
          ensemble_dihedral_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_dihedral_deltas[proxy.i_seqs] = [dihedral_proxy.delta, 1]
        if verbose:
          print("dihedral : ", proxy.i_seqs, file=out)
          print("  dihedral_ideal  : %.6g" % proxy.angle_ideal, file=out)
          print("  periodicity     : %.6g" % proxy.periodicity, file=out)
          print("  dihedral_model  : %.6g" % dihedral_proxy.angle_model, file=out)
          print("  delta           : %.6g" % dihedral_proxy.delta, file=out)

    # Calculate RMSDs for ensemble model
    # Bond
    mean_bond_delta = flex.double()
    for proxy, info in six.iteritems(ensemble_bond_deltas):
      # assert info[1] == ensemble_size
      if info[1]!=ensemble_size:
        print('skipping bond RMSD calns of ensemble %s' % info, file=out)
        continue
      mean_delta = info[0] / info[1]
      mean_bond_delta.append(mean_delta)
    bond_delta_sq = mean_bond_delta * mean_bond_delta
    ensemble_bond_rmsd = math.sqrt(flex.mean_default(bond_delta_sq, 0))

    # Angle
    mean_angle_delta = flex.double()
    for proxy, info in six.iteritems(ensemble_angle_deltas):
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_angle_delta.append(mean_delta)
    angle_delta_sq = mean_angle_delta * mean_angle_delta
    ensemble_angle_rmsd = math.sqrt(flex.mean_default(angle_delta_sq, 0))

    # Chirality
    mean_chirality_delta = flex.double()
    for proxy, info in six.iteritems(ensemble_chirality_deltas):
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_chirality_delta.append(mean_delta)
    chirality_delta_sq = mean_chirality_delta * mean_chirality_delta
    ensemble_chirality_rmsd = math.sqrt(flex.mean_default(chirality_delta_sq, 0))

    # Planarity
    mean_planarity_delta = flex.double()
    for proxy, info in six.iteritems(ensemble_planarity_deltas):
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_planarity_delta.append(mean_delta)
    planarity_delta_sq = mean_planarity_delta * mean_planarity_delta
    ensemble_planarity_rmsd = math.sqrt(flex.mean_default(planarity_delta_sq, 0))

    # Dihedral
    mean_dihedral_delta = flex.double()
    for proxy, info in six.iteritems(ensemble_dihedral_deltas):
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_dihedral_delta.append(mean_delta)
    dihedral_delta_sq = mean_dihedral_delta * mean_dihedral_delta
    ensemble_dihedral_rmsd = math.sqrt(flex.mean_default(dihedral_delta_sq, 0))

    # Calculate <structure rmsd>
    assert ensemble_size == structures_bond_rmsd
    assert ensemble_size == structures_angle_rmsd
    assert ensemble_size == structures_chirality_rmsd
    assert ensemble_size == structures_planarity_rmsd
    assert ensemble_size == structures_dihedral_rmsd
    structure_bond_rmsd_mean = structures_bond_rmsd.min_max_mean().mean
    structure_angle_rmsd_mean = structures_angle_rmsd.min_max_mean().mean
    structure_chirality_rmsd_mean = structures_chirality_rmsd.min_max_mean().mean
    structure_planarity_rmsd_mean = structures_planarity_rmsd.min_max_mean().mean
    structure_dihedral_rmsd_mean = structures_dihedral_rmsd.min_max_mean().mean

    # Show summary
    utils.print_header("Ensemble RMSD summary", out = out)
    print("  RMSD (mean delta per restraint)", file=out)
    print("    bond      : %.6g" % ensemble_bond_rmsd, file=out)
    print("    angle     : %.6g" % ensemble_angle_rmsd, file=out)
    print("    chirality : %.6g" % ensemble_chirality_rmsd, file=out)
    print("    planarity : %.6g" % ensemble_planarity_rmsd, file=out)
    print("    dihedral  : %.6g" % ensemble_dihedral_rmsd, file=out)
    print("  RMSD (mean RMSD per structure)", file=out)
    print("    bond      : %.6g" % structure_bond_rmsd_mean, file=out)
    print("    angle     : %.6g" % structure_angle_rmsd_mean, file=out)
    print("    chirality : %.6g" % structure_chirality_rmsd_mean, file=out)
    print("    planarity : %.6g" % structure_planarity_rmsd_mean, file=out)
    print("    dihedral  : %.6g" % structure_dihedral_rmsd_mean, file=out)
    if ignore_hd:
      print("\n  Calculated excluding H/D", file=out)
    else:
      print("\n  Calculated including H/D", file=out)

    if return_pdb_string:
      ens_geo_pdb_string  = "REMARK   3"
      ens_geo_pdb_string += "\nREMARK   3  NUMBER STRUCTURES IN ENSEMBLE : {0:5d}".format(ensemble_size)
      if ignore_hd:
        ens_geo_pdb_string += "\nREMARK   3  RMS DEVIATIONS FROM IDEAL VALUES (EXCLUDING H/D)"
      else:
        ens_geo_pdb_string += "\nREMARK   3  RMS DEVIATIONS FROM IDEAL VALUES (INCLUDING H/D)"
      ens_geo_pdb_string += "\nREMARK   3  RMSD (MEAN DELTA PER RESTRAINT)"
      ens_geo_pdb_string += "\nREMARK   3    BOND      : {0:5.3f}".format(ensemble_bond_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    ANGLE     : {0:5.3f}".format(ensemble_angle_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    CHIRALITY : {0:5.3f}".format(ensemble_chirality_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    PLANARITY : {0:5.3f}".format(ensemble_planarity_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    DIHEDRAL  : {0:5.2f}".format(ensemble_dihedral_rmsd)
      ens_geo_pdb_string += "\nREMARK   3  RMSD (MEAN RMSD PER STRUCTURE)"
      ens_geo_pdb_string += "\nREMARK   3    BOND      : {0:5.3f}".format(structure_bond_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    ANGLE     : {0:5.3f}".format(structure_angle_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    CHIRALITY : {0:5.3f}".format(structure_chirality_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    PLANARITY : {0:5.3f}".format(structure_planarity_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    DIHEDRAL  : {0:5.2f}".format(structure_dihedral_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3"
      return ens_geo_pdb_string
Esempio n. 4
0
  def ensemble_mean_geometry_stats(self,
                                   restraints_manager,
                                   xray_structure,
                                   ensemble_xray_structures,
                                   ignore_hd = True,
                                   verbose = False,
                                   out = None,
                                   return_pdb_string = False):
    if (out is None): out = sys.stdout
    if verbose:
      utils.print_header("Ensemble mean geometry statistics", out = out)
    ensemble_size = len(ensemble_xray_structures)
    print >> out, "Ensemble size : ", ensemble_size

    # Dictionaries to store deltas
    ensemble_bond_deltas = {}
    ensemble_angle_deltas = {}
    ensemble_chirality_deltas = {}
    ensemble_planarity_deltas = {}
    ensemble_dihedral_deltas = {}

    # List to store rmsd of each model
    structures_bond_rmsd = flex.double()
    structures_angle_rmsd = flex.double()
    structures_chirality_rmsd = flex.double()
    structures_planarity_rmsd = flex.double()
    structures_dihedral_rmsd = flex.double()

    # Remove water and hd atoms from global restraints manager
    selection = flex.bool()
    for sc in xray_structure.scatterers():
      if sc.label.find('HOH') > -1:
        selection.append(True)
      else:
        selection.append(False)
    if ignore_hd:
      hd_selection = xray_structure.hd_selection()
      assert hd_selection.size() == selection.size()
      for n in xrange(hd_selection.size()):
        if hd_selection[n] or selection[n]:
          selection[n] = True
    restraints_manager = restraints_manager.select(selection = ~selection)

    # Get all deltas
    for n, structure in enumerate(ensemble_xray_structures):
      if verbose:
        print >> out, "\nModel : ", n+1
      sites_cart = structure.sites_cart()
      # Remove water and hd atoms from individual structures sites cart
      selection = flex.bool()
      for sc in structure.scatterers():
        if sc.label.find('HOH') > -1:
          selection.append(True)
        else:
          selection.append(False)
      if ignore_hd:
        hd_selection = structure.hd_selection()
        assert hd_selection.size() == selection.size()
        for n in xrange(hd_selection.size()):
          if hd_selection[n] or selection[n]:
            selection[n] = True
      sites_cart = sites_cart.select(~selection)
      assert sites_cart is not None
      site_labels = None
      energies_sites = restraints_manager.energies_sites(
          sites_cart        = sites_cart,
          compute_gradients = False)

      # Rmsd of individual model
      bond_rmsd = energies_sites.geometry.bond_deviations()[2]
      angle_rmsd = energies_sites.geometry.angle_deviations()[2]
      chirality_rmsd = energies_sites.geometry.chirality_deviations()[2]
      planarity_rmsd = energies_sites.geometry.planarity_deviations()[2]
      dihedral_rmsd = energies_sites.geometry.dihedral_deviations()[2]

      structures_bond_rmsd.append(bond_rmsd)
      structures_angle_rmsd.append(angle_rmsd)
      structures_chirality_rmsd.append(chirality_rmsd)
      structures_planarity_rmsd.append(planarity_rmsd)
      structures_dihedral_rmsd.append(dihedral_rmsd)

      if verbose:
        print >> out, "  Model RMSD"
        print >> out, "    bond      : %.6g" % bond_rmsd
        print >> out, "    angle     : %.6g" % angle_rmsd
        print >> out, "    chirality : %.6g" % chirality_rmsd
        print >> out, "    planarity : %.6g" % planarity_rmsd
        print >> out, "    dihedral  : %.6g" % dihedral_rmsd

      # Bond
      pair_proxies = restraints_manager.geometry.pair_proxies(flags=None, sites_cart=sites_cart)
      assert pair_proxies is not None
      if verbose:
        pair_proxies.bond_proxies.show_histogram_of_deltas(
          sites_cart  = sites_cart,
          n_slots     = 10,
          f           = out)
      for proxy in pair_proxies.bond_proxies.simple:
        bond_simple_proxy = geometry_restraints.bond(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_bond_deltas:
          ensemble_bond_deltas[proxy.i_seqs][0]+=bond_simple_proxy.delta
          ensemble_bond_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_bond_deltas[proxy.i_seqs] = [bond_simple_proxy.delta, 1]
        if verbose:
          print >> out, "bond simple :", proxy.i_seqs
          print >> out, "  distance_ideal : %.6g" % proxy.distance_ideal
          print >> out, "  distance_model : %.6g" % bond_simple_proxy.distance_model
          print >> out, "  detla          : %.6g" % bond_simple_proxy.delta
      if (pair_proxies.bond_proxies.asu.size() > 0):
        asu_mappings = pair_proxies.bond_proxies.asu_mappings()
        for proxy in pair_proxies.bond_proxies.asu:
          rt_mx = asu_mappings.get_rt_mx_ji(pair=proxy)
          bond_asu_proxy = geometry_restraints.bond(
              sites_cart   = sites_cart,
              asu_mappings = asu_mappings,
              proxy        = proxy)
          proxy_i_seqs = (proxy.i_seq, proxy.j_seq)
          if proxy_i_seqs in ensemble_bond_deltas:
            ensemble_bond_deltas[proxy_i_seqs][0]+=bond_asu_proxy.delta
            ensemble_bond_deltas[proxy_i_seqs][1]+=1
          else:
            ensemble_bond_deltas[proxy_i_seqs] = [bond_asu_proxy.delta, 1]
          if verbose:
            print >> out, "bond asu :", (proxy.i_seq, proxy.j_seq), rt_mx
            print >> out, "  distance_ideal : %.6g" % proxy.distance_ideal
            print >> out, "  distance_model : %.6g" % bond_asu_proxy.distance_model
            print >> out, "  delta          : %.6g" % bond_asu_proxy.delta

      # Angle
      if verbose:
        restraints_manager.geometry.angle_proxies.show_histogram_of_deltas(
            sites_cart  = sites_cart,
            n_slots     = 10,
            f           = out)
      for proxy in restraints_manager.geometry.angle_proxies:
        angle_proxy = geometry_restraints.angle(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_angle_deltas:
          ensemble_angle_deltas[proxy.i_seqs][0]+=angle_proxy.delta
          ensemble_angle_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_angle_deltas[proxy.i_seqs] = [angle_proxy.delta, 1]
        if verbose:
          print >> out, "angle : ", proxy.i_seqs
          print >> out, "  angle_ideal   : %.6g" % proxy.angle_ideal
          print >> out, "  angle_model   : %.6g" % angle_proxy.angle_model
          print >> out, "  delta         : %.6g" % angle_proxy.delta

      # Chirality
      if verbose:
        restraints_manager.geometry.chirality_proxies.show_histogram_of_deltas(
            sites_cart  = sites_cart,
            n_slots     = 10,
            f           = out)
      for proxy in restraints_manager.geometry.chirality_proxies:
        chirality_proxy = geometry_restraints.chirality(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_chirality_deltas:
          ensemble_chirality_deltas[proxy.i_seqs][0]+=chirality_proxy.delta
          ensemble_chirality_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_chirality_deltas[proxy.i_seqs] = [chirality_proxy.delta, 1]
        if verbose:
          print >> out, "chirality : ", proxy.i_seqs
          print >> out, "  chirality_ideal : %.6g" % proxy.volume_ideal
          print >> out, "  chirality_model : %.6g" % chirality_proxy.volume_model
          print >> out, "  chirality       : %.6g" % chirality_proxy.delta

      # Planarity
      for proxy in restraints_manager.geometry.planarity_proxies:
        planarity_proxy = geometry_restraints.planarity(
            sites_cart = sites_cart,
            proxy      = proxy)
        proxy_i_seqs = []
        for i_seq in proxy.i_seqs:
          proxy_i_seqs.append(i_seq)
        proxy_i_seqs = tuple(proxy_i_seqs)
        if proxy_i_seqs in ensemble_planarity_deltas:
          ensemble_planarity_deltas[proxy_i_seqs][0]+=planarity_proxy.rms_deltas()
          ensemble_planarity_deltas[proxy_i_seqs][1]+=1
        else:
          ensemble_planarity_deltas[proxy_i_seqs] = [planarity_proxy.rms_deltas(), 1]
        if verbose:
          print >> out, "planarity : ", proxy_i_seqs
          print >> out, "  planarity rms_deltas : %.6g" % planarity_proxy.rms_deltas()

      # Dihedral
      if verbose:
        restraints_manager.geometry.dihedral_proxies.show_histogram_of_deltas(
            sites_cart  = sites_cart,
            n_slots     = 10,
            f           = out)
      for proxy in restraints_manager.geometry.dihedral_proxies:
        dihedral_proxy = geometry_restraints.dihedral(
            sites_cart = sites_cart,
            proxy      = proxy)
        if proxy.i_seqs in ensemble_dihedral_deltas:
          ensemble_dihedral_deltas[proxy.i_seqs][0]+=dihedral_proxy.delta
          ensemble_dihedral_deltas[proxy.i_seqs][1]+=1
        else:
          ensemble_dihedral_deltas[proxy.i_seqs] = [dihedral_proxy.delta, 1]
        if verbose:
          print >> out, "dihedral : ", proxy.i_seqs
          print >> out, "  dihedral_ideal  : %.6g" % proxy.angle_ideal
          print >> out, "  periodicity     : %.6g" % proxy.periodicity
          print >> out, "  dihedral_model  : %.6g" % dihedral_proxy.angle_model
          print >> out, "  delta           : %.6g" % dihedral_proxy.delta

    # Calculate RMSDs for ensemble model
    # Bond
    mean_bond_delta = flex.double()
    for proxy, info in ensemble_bond_deltas.iteritems():
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_bond_delta.append(mean_delta)
    bond_delta_sq = mean_bond_delta * mean_bond_delta
    ensemble_bond_rmsd = math.sqrt(flex.mean_default(bond_delta_sq, 0))

    # Angle
    mean_angle_delta = flex.double()
    for proxy, info in ensemble_angle_deltas.iteritems():
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_angle_delta.append(mean_delta)
    angle_delta_sq = mean_angle_delta * mean_angle_delta
    ensemble_angle_rmsd = math.sqrt(flex.mean_default(angle_delta_sq, 0))

    # Chirality
    mean_chirality_delta = flex.double()
    for proxy, info in ensemble_chirality_deltas.iteritems():
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_chirality_delta.append(mean_delta)
    chirality_delta_sq = mean_chirality_delta * mean_chirality_delta
    ensemble_chirality_rmsd = math.sqrt(flex.mean_default(chirality_delta_sq, 0))

    # Planarity
    mean_planarity_delta = flex.double()
    for proxy, info in ensemble_planarity_deltas.iteritems():
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_planarity_delta.append(mean_delta)
    planarity_delta_sq = mean_planarity_delta * mean_planarity_delta
    ensemble_planarity_rmsd = math.sqrt(flex.mean_default(planarity_delta_sq, 0))

    # Dihedral
    mean_dihedral_delta = flex.double()
    for proxy, info in ensemble_dihedral_deltas.iteritems():
      assert info[1] == ensemble_size
      mean_delta = info[0] / info[1]
      mean_dihedral_delta.append(mean_delta)
    dihedral_delta_sq = mean_dihedral_delta * mean_dihedral_delta
    ensemble_dihedral_rmsd = math.sqrt(flex.mean_default(dihedral_delta_sq, 0))

    # Calculate <structure rmsd>
    assert ensemble_size == structures_bond_rmsd
    assert ensemble_size == structures_angle_rmsd
    assert ensemble_size == structures_chirality_rmsd
    assert ensemble_size == structures_planarity_rmsd
    assert ensemble_size == structures_dihedral_rmsd
    structure_bond_rmsd_mean = structures_bond_rmsd.min_max_mean().mean
    structure_angle_rmsd_mean = structures_angle_rmsd.min_max_mean().mean
    structure_chirality_rmsd_mean = structures_chirality_rmsd.min_max_mean().mean
    structure_planarity_rmsd_mean = structures_planarity_rmsd.min_max_mean().mean
    structure_dihedral_rmsd_mean = structures_dihedral_rmsd.min_max_mean().mean

    # Show summary
    utils.print_header("Ensemble RMSD summary", out = out)
    print >> out, "  RMSD (mean delta per restraint)"
    print >> out, "    bond      : %.6g" % ensemble_bond_rmsd
    print >> out, "    angle     : %.6g" % ensemble_angle_rmsd
    print >> out, "    chirality : %.6g" % ensemble_chirality_rmsd
    print >> out, "    planarity : %.6g" % ensemble_planarity_rmsd
    print >> out, "    dihedral  : %.6g" % ensemble_dihedral_rmsd
    print >> out, "  RMSD (mean RMSD per structure)"
    print >> out, "    bond      : %.6g" % structure_bond_rmsd_mean
    print >> out, "    angle     : %.6g" % structure_angle_rmsd_mean
    print >> out, "    chirality : %.6g" % structure_chirality_rmsd_mean
    print >> out, "    planarity : %.6g" % structure_planarity_rmsd_mean
    print >> out, "    dihedral  : %.6g" % structure_dihedral_rmsd_mean
    if ignore_hd:
      print >> out, "\n  Calculated excluding H/D"
    else:
      print >> out, "\n  Calculated including H/D"

    if return_pdb_string:
      ens_geo_pdb_string  = "REMARK   3"
      ens_geo_pdb_string += "\nREMARK   3  NUMBER STRUCTURES IN ENSEMBLE : {0:5d}".format(ensemble_size)
      if ignore_hd:
        ens_geo_pdb_string += "\nREMARK   3  RMS DEVIATIONS FROM IDEAL VALUES (EXCLUDING H/D)"
      else:
        ens_geo_pdb_string += "\nREMARK   3  RMS DEVIATIONS FROM IDEAL VALUES (INCLUDING H/D)"
      ens_geo_pdb_string += "\nREMARK   3  RMSD (MEAN DELTA PER RESTRAINT)"
      ens_geo_pdb_string += "\nREMARK   3    BOND      : {0:5.3f}".format(ensemble_bond_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    ANGLE     : {0:5.3f}".format(ensemble_angle_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    CHIRALITY : {0:5.3f}".format(ensemble_chirality_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    PLANARITY : {0:5.3f}".format(ensemble_planarity_rmsd)
      ens_geo_pdb_string += "\nREMARK   3    DIHEDRAL  : {0:5.2f}".format(ensemble_dihedral_rmsd)
      ens_geo_pdb_string += "\nREMARK   3  RMSD (MEAN RMSD PER STRUCTURE)"
      ens_geo_pdb_string += "\nREMARK   3    BOND      : {0:5.3f}".format(structure_bond_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    ANGLE     : {0:5.3f}".format(structure_angle_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    CHIRALITY : {0:5.3f}".format(structure_chirality_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    PLANARITY : {0:5.3f}".format(structure_planarity_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3    DIHEDRAL  : {0:5.2f}".format(structure_dihedral_rmsd_mean)
      ens_geo_pdb_string += "\nREMARK   3"
      return ens_geo_pdb_string
def exercise_chirality(verbose=0):
  # monomer library: CA N CB C
  sites = [col(site) for site in [
    (27.660, 9.903, 2.078),
    (28.049, 9.675, 3.486),
    (28.183, 11.269, 1.625),
    (28.085, 8.759, 1.165)]]
  chir = geometry_restraints.chirality(
    sites=sites,
    volume_ideal=-2.48,
    both_signs=False,
    weight=1)
  assert approx_equal(chir.volume_model, -2.411548478)
  assert approx_equal(chir.residual(), 0.00468561086412)
  dih = geometry_restraints.dihedral(
    sites=improper_permutation(sites),
    angle_ideal=35.26439,
    weight=1)
  assert approx_equal(dih.angle_model, 32.2587249641)
  assert approx_equal(dih.residual(), 9.03402230782)
  if (verbose):
    dump_pdb("sites.pdb", sites)
    print "volume_ideal:", chir.volume_ideal
    print "volume_model:", chir.volume_model
    print "angle_ideal:", dih.angle_ideal
    print "angle model:", dih.angle_model
  for i_trial in xrange(50):
    volume_ideal = chir.volume_ideal
    for both_signs in [False, True]:
      sites_mod = []
      for site in sites:
        shift = col([random.uniform(-.5,.5) for i in xrange(3)])
        sites_mod.append(site+shift)
      if (both_signs): volume_ideal = abs(volume_ideal)
      c = geometry_restraints.chirality(
        sites=sites_mod,
        volume_ideal=volume_ideal,
        both_signs=both_signs,
        weight=500*1/0.2**2)
      residual_obj = residual_functor(
        restraint_type=geometry_restraints.chirality,
        volume_ideal=c.volume_ideal,
        both_signs=c.both_signs,
        weight=c.weight)
      fg = flex.vec3_double(
        finite_differences(sites_mod, residual_obj)).as_double()
      ag = flex.vec3_double(
        c.gradients()).as_double()
      scale = max(1, flex.mean(flex.abs(fg)))
      assert approx_equal(ag/scale, fg/scale)
      d = geometry_restraints.dihedral(
        sites=improper_permutation(sites_mod),
        angle_ideal=dih.angle_ideal,
        weight=750)
      ag_dih = dih.gradients()
      if (verbose and i_trial == 0 and not both_signs):
        dump_pdb("sites_mod.pdb", sites_mod)
        max_g_len = 0
        for g in ag_dih:
          max_g_len = max(max_g_len, abs(col(g)))
        for g in flex.vec3_double(fg):
          max_g_len = max(max_g_len, abs(col(g)))
        sticks = []
        for site,g in zip(improper_permutation(sites_mod),ag_dih):
          sticks.append(
            pml_stick(
              begin=site,
              end=site+col(g)/max_g_len,
              colors=[[1,0,0]]*2,
              width=0.01))
        pml_write(f=open("dih.pml", "w"), label="dih", sticks=sticks)
        sticks = []
        for site,g in zip(sites_mod,flex.vec3_double(fg)):
          sticks.append(
            pml_stick(
              begin=site,
              end=site+col(g)/max_g_len,
              colors=[[0,1,0]]*2,
              width=0.01))
        pml_write(f=open("chir.pml", "w"), label="chir", sticks=sticks)